ページ 1 / 1
calloc + strcpyについて
Posted: 2017年4月13日(木) 14:27
by わん
以下のコードを実行したときの実行結果についてわかりません。
連続して領域を確保すると、どのように考えればよろしいでしょうか?
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *a,*b;
int i;
a = (char*)calloc(20,sizeof(char));
b = (char*)calloc(20,sizeof(char));
strcpy(a,"abcdefgh ijklmn op qrstuvwxyz! abcdefg hij lmnopqrst");
for(i = 0; i<20; i++)
printf("a[%d] = %c\n",i,a[i]);
for(i = 0; i<20; i++)
printf("b[%d] = %c\n",i,b[i]);
return 0;
}
実行結果
a[0] = a
a[1] = b
a[2] = c
a[3] = d
a[4] = e
a[5] = f
a[6] = g
a[7] = h
a[8] =
a[9] = i
a[10] = j
a[11] = k
a[12] = l
a[13] = m
a[14] = n
a[15] =
a[16] = o
a[17] = p
a[18] =
a[19] = q
b[0] = b
b[1] = c
b[2] = d
b[3] = e
b[4] = f
b[5] = g
b[6] =
b[7] = h
b[8] = i
b[9] = j
b[10] =
b[11] = k
b[12] = l
b[13] = m
b[14] = n
b[15] = o
b[16] = p
b[17] = q
b[18] = r
b[19] = s
calloc + strcpyについて
Posted: 2017年4月13日(木) 14:29
by わん
言語はC++となってますが、C言語です。
Re: calloc + strcpyについて
Posted: 2017年4月13日(木) 15:54
by usao
何が言いたいのか(何の話をしたいのか,意図)がわかりません.
Re: calloc + strcpyについて
Posted: 2017年4月13日(木) 15:56
by YuO
わん さんが書きました:連続して領域を確保すると、どのように考えればよろしいでしょうか?
単なるバッファーオーバーランによる未定義動作の結果なので,「たまたまこうなった」としか考えようがないです。
Re: calloc + strcpyについて
Posted: 2017年4月13日(木) 23:38
by 梅衣堂ひよ
わん さんが書きました:コード:
a = (char*)calloc(20,sizeof(char));
b = (char*)calloc(20,sizeof(char));
メモリがaとbで連続した領域を確保できたため、事実上のa[40]になったことが原因だと思います。
プログラム実行直後だから起きた出来事ですね。
何度もメモリの確保と解放を繰り返した影響でメモリが断片化した状態で行えば、a[20]とb[20]で別々の場所にメモリが確保されるはずのなので、再現できる可能性は限りなく低いと思いますよ。
C++、メモリ断片化しますよね?(そこが自信ない
Re: calloc + strcpyについて
Posted: 2017年4月13日(木) 23:49
by みけCAT
まず、C言語では確保された領域の外にアクセスすると未定義動作となり、何があってもおかしくありません。
梅衣堂ひよ さんが書きました:メモリがaとbで連続した領域を確保できたため、事実上のa[40]になったことが原因だと思います。
これは違うでしょう。
提示された実行結果を見ると、「rstuvwxyz! a」の12文字が抜けており、領域は連続していません。
これは、メモリの管理に使う情報が入るためか、32バイトのアラインメントに合わせるためであると考えられます。
Re: calloc + strcpyについて
Posted: 2017年4月14日(金) 15:16
by わん
皆様 ご回答ありがとうございます。
このような結果となってしまった理由について、お願いしたいと思います。
aとbは不連続な領域をとり、aとbの間の領域に消えた12文字が存在する。
そのような結果となってしまった理由として、12文字はメモリの管理に使う情報またはアラインメントに合わせるためという理解でよろしいでしょうか?
Re: calloc + strcpyについて
Posted: 2017年4月14日(金) 15:34
by YuO
わん さんが書きました:このような結果となってしまった理由について、お願いしたいと思います。
たまたま。
Re: calloc + strcpyについて
Posted: 2017年4月14日(金) 22:02
by みけCAT
わん さんが書きました:どのように考えればよろしいでしょうか?
こんな未定義動作の危険なコードを書くのはやめよう、未定義動作を起こさないように気をつけよう、と考えるのがいいでしょう。
Re: calloc + strcpyについて
Posted: 2017年4月15日(土) 02:06
by みえ
calloc や malloc といった API の仕様は、言語である C/C++ の範疇ではなく、ライブラリ (VC ランタイムや GLIBC) に依存する部分だと思います。"malloc しくみ" などのキーワードで検索すれば、どのようにメモリ領域が割り当てられるかを説明しているページが数多くヒットするので、幾つか探してみてはいかがでしょうか。また、Youtube には伝説の malloc 動画と呼ばれる有名な動画もあります。
わん さんが書きました:このような結果となってしまった理由について、お願いしたいと思います。
aとbは不連続な領域をとり、aとbの間の領域に消えた12文字が存在する。
そのような結果となってしまった理由として、12文字はメモリの管理に使う情報またはアラインメントに合わせるためという理解でよろしいでしょうか?
わんさんの見た 12 文字 (すなわち "b - a == 0x20" ) は、梅衣堂ひよさんが仰るように、プロセス開始直後でヒープ領域ががら空きであり、a と b に隣り合った領域 (= チャンク) が順当に割り当てられた結果だと思います。
VC++ の場合は分かりませんが、GLIBC であれば calloc を呼び出すと以下のコードで実装されている __libc_calloc という内部関数が呼ばれます。
sourceware.org Git - glibc.git/blob - malloc/malloc.c
https://sourceware.org/git/?p=glibc.git ... 3db04#l496
上記ソースコード中のコメントに、各チャンクの構造が略図で示されています。
コード:
/*
malloc_chunk details:
(..snip..)
An allocated chunk looks like this:
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of previous chunk, if unallocated (P clear) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of chunk, in bytes |A|M|P|
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| User data starts here... .
. .
. (malloc_usable_size() bytes) .
. |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| (size of chunk, but used for application data) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of next chunk, in bytes |A|0|1|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(..snip..)
*/
もし隣り合ったチャンクがともに解放されていないのであれば、みけCAT さんの仰る「管理データ」は[Size of next chunk, in bytes] で示された 8 バイトということになります。ただし、各チャンクが管理データを持っているため、管理データの長さがチャンク間の長さに寄与することはなさそうです。
そこで出てくるのが「アラインメント」の方ですが、これは単純に 64bit 境界に合わせるのではなく、GLIBC の中でアラインメント境界 (= MALLOC_ALIGNMENT) がワード サイズの 2 倍とされているようなので、64bit だと 16 バイトでしょうか。さらに、チャンクの最小サイズ (= MIN_CHUNK_SIZE = &((struct malloc_chunk*)0)->fd_nextsize == 32?) も決まっています。
20 バイトを確保すると、まず最小サイズの 32 バイトに切り上げられ、これは 16 バイト境界に合うためチャンクは 32 バイトとなります。これが 12 バイトの真相ではないでしょうか。
上記はコードをざっと眺めただけの判断なので厳密には間違っているかもしれませんが、回答になっていれば幸いです。
Re: calloc + strcpyについて
Posted: 2017年4月15日(土) 16:02
by sleep
みえ さんが書きました:
20 バイトを確保すると、まず最小サイズの 32 バイトに切り上げられ、これは 16 バイト境界に合うためチャンクは 32 バイトとなります。これが 12 バイトの真相ではないでしょうか。
上記はコードをざっと眺めただけの判断なので厳密には間違っているかもしれませんが、回答になっていれば幸いです。
間違ってませんよ。
chunk のサイズ用の領域が8byte、それを含む最小サイズが32byte
以降、1 byteでも超えると16byteずつchunkの割り当てサイズが更新されていきます。
例えば25byte割り当てれば25+8=33byteになるので32+16=48byte、41byte割り当てれば41+8=49byteになるので32+16+16=64byte、57byte割り当てれば57+8=65byteになるので32+16+16+16=80byteになっていきます。
ただし、これはslabから連続したオブジェクトの領域を獲得できた場合の限定された話です。
サイズの大きな動的割り当てを実施した場合など、動的割り当て毎に別のslabから未割り当てオブジェクトが獲得されると今回のようなケースの結果にはなりません。
わん さんが書きました:
このような結果となってしまった理由について、お願いしたいと思います。
aとbは不連続な領域をとり、aとbの間の領域に消えた12文字が存在する。
そのような結果となってしまった理由として、12文字はメモリの管理に使う情報またはアラインメントに合わせるためという理解でよろしいでしょうか?
calloc、strcpyについての質問のようですが、これLinux環境のglibcに限定された環境依存の実装の話なので、calloc、strcpyというC言語のライブラリ関数の仕様ではありません。