プロセスのメモリ割り当てを調べると、通常、次のように概説されます。
ここまでは順調ですね。
しかし、プログラムがデータセクションの上限を変更できるようにするsbrk()システムコールがあり、sbrk(0)でその上限がどこにあるかを簡単に確認するためにも使用できます。その機能を使用して、次のパターンを見つけました。
パターン 1 - 小さな malloc
Linux マシンで次のプログラムを実行します。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int globalVar;
int main(){
int localVar;
int *ptr;
printf("localVar address (i.e., stack) = %p\n",&localVar);
printf("globalVar address (i.e., data section) = %p\n",&globalVar);
printf("Limit of data section = %p\n",sbrk(0));
ptr = malloc(sizeof(int)*1000);
printf("ptr address (should be on stack)= %p\n",&ptr);
printf("ptr points to: %p\n",ptr);
printf("Limit of data section after malloc= %p\n",sbrk(0));
return 0;
}
出力は次のとおりです。
localVar address (i.e., stack) = 0xbfe34058
globalVar address (i.e., data section) = 0x804a024
Limit of data section = 0x91d9000
ptr address (should be on stack)= 0xbfe3405c
ptr points to: 0x91d9008
Limit of data section after malloc= 0x91fa000
ご覧のとおり、割り当てられたメモリ領域は古いデータ セクションの制限のすぐ上にあり、malloc の後でその制限が押し上げられたので、割り当てられた領域は実際には新しいデータ セクション内にあります。
質問 1 : これは、小さな malloc がデータ セクションにメモリを割り当て、ヒープをまったく使用しないということですか?
パターン 2 - ビッグ マロック
15 行目で要求されたメモリ サイズを増やすと、次のようになります。
ptr = malloc(sizeof(int)*100000);
次の出力が得られます。
localVar address (i.e., stack) = 0xbf93ba68
globalVar address (i.e., data section) = 0x804a024
Limit of data section = 0x8b16000
ptr address (should be on stack)= 0xbf93ba6c
ptr points to: 0xb750b008
Limit of data section after malloc= 0x8b16000
ここでわかるように、データ セクションの制限は変更されておらず、割り当てられたメモリ領域は、データ セクションとスタックの間のギャップ セクションの中央にあります。
質問 2 : これは実際にヒープを使用している大きな malloc ですか?
質問 3 : この動作について何か説明はありますか? 最初の例(小さなmalloc)では、割り当てられたメモリを解放した後でも、データ内にあるため、セグフォルトを発生させることなくポインタを使用してそのメモリを使用することができます。これにより、バグの検出が困難になる可能性があります。
仕様の更新: Ubuntu 12.04、32 ビット、gcc バージョン 4.6.3、Linux カーネル 3.2.0-54-generic-pae。
更新 2: 以下のロドリゴの回答がこの謎を解決しました。このウィキペディアのリンクも役に立ちました。