ええと、この時点で発生する segfault は、以前に割り当てていないメモリを解放しようとしたためではなく、オペレーティング システムが許可していないメモリ アドレスを参照しようとしたために発生します (これがセグメンテーション違反の定義です)。
サンプル コードを valgrind で実行すると、いくつかの実験が行われ、次のような出力が得られます。
==6945== 無効な free() / delete / delete[]
==6945== 0x402265C: フリー (vg_replace_malloc.c:323)
==6945== by 0x80483D5: メイン (bla.c:6)
==6945== アドレス 0x7 は、スタック、malloc、または (最近) 解放されていません
==6945==
==6945== エラーの概要: 1 つのコンテキストから 1 つのエラー (抑制: 1 から 11)
==6945== malloc/free: 出口で使用中: 1 ブロックで 4 バイト。
==6945== malloc/free: 1 つの割り当て、1 つの解放、4 バイトの割り当て。
したがって、これはメモリ リーク 'pur sang' です。ここで、コードを変更して、解放しようとするポインターが割り当てたポインターの「近く」にあるとします (したがって、オペレーティング システムはユーザーがポインターにアクセスできることを認識し、オペレーティング システムはバイト境界でのメモリ アクセスを許可しません)。次のようにコードを変更するとします。
int main(){
int* c;
c = (int*)malloc(sizeof(int));
c++;
free(c);
return 0;
}
このアプリケーションを実行すると、セグメンテーション違反 (カーネルによって発行される) が表示されなくなりますが、glibc ( malloc() および free() の所有者) からの警告が表示されます。
edb@Flying-Spaghetti-Monster:/tmp$ ./a.out
*** glibc が検出されました *** ./a.out: free(): 無効なポインタ: 0x0804a00c ***
... トレースが続きます
したがって、カーネルがそれがあなたに属していることを知っているが、glibcがあなたにそれを渡したのを覚えていないメモリを解放しようとしています。これを valgrind (libc の free()、malloc()、realloc()、... 関数を置き換えて独自にアカウンティングを実行することによって動作する) で実行すると、次の出力が得られます。
==6955== 無効な free() / delete / delete[]
==6955== 0x402265C: フリー (vg_replace_malloc.c:323)
==6955== by 0x80483D2: メイン (bla.c:5)
==6955== サイズ 4 のブロックが割り当てられた後、アドレス 0x418a02c は 0 バイトです
==6955== 0x4022AB8: malloc (vg_replace_malloc.c:207)
==6955== by 0x80483C0: メイン (bla.c:3)
==6955==
==6955== エラーの概要: 1 つのコンテキストから 1 つのエラー (抑制: 1 から 11)
==6955== malloc/free: 出口で使用中: 1 ブロックで 4 バイト。
==6955== malloc/free: 1 つの割り当て、1 つの解放、4 バイトの割り当て。