(C++) プログラムを実行すると、このエラーでクラッシュします。
* glibc が検出されました * ./load: 二重解放または破損 (!prev): 0x0000000000c6ed50 ***
エラーを追跡するにはどうすればよいですか?
print ( std::cout
) ステートメントを使用してみましたが、成功しませんでした。gdb
これを簡単にできますか?
MALLOC_CHECK_
glibc を使用している場合は、環境変数を に設定できます。2
これにより、glibc は のエラー トレラント バージョンを使用するようmalloc
になり、二重解放が行われた時点でプログラムが中止されます。
set environment MALLOC_CHECK_ 2
これは、プログラムを実行する前にコマンドを使用して gdb から設定できます。プログラムは中止され、free()
呼び出しがバックトレースに表示されます。
詳細については、man ページをmalloc()
参照してください
少なくとも 2 つの状況が考えられます。
最初のものについては、削除されたすべてのポインターを NULL にすることを強くお勧めします。
次の 3 つのオプションがあります。
gdb を使用できますが、最初にValgrindを試してみます。クイック スタート ガイドを参照してください。
簡単に言えば、Valgrind はプログラムをインストルメント化して、動的に割り当てられたメモリを使用する際に発生するいくつかの種類のエラーを検出できるようにします。たとえば、二重解放や、割り当てられたメモリ ブロックの末尾を超えた書き込み (ヒープが破損する可能性がある) などです。エラーが発生するとすぐに検出して報告する ため、問題の原因を直接指摘できます。
3 つの基本ルール:
NULL
解放後にポインタを設定NULL
解放する前に確認してください。NULL
。これら3つの組み合わせは非常にうまく機能します。
valgrind
デバッグに使用できます。
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *x = malloc(100);
free(x);
free(x);
return 0;
}
[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ ./t1
*** glibc detected *** ./t1: double free or corruption (top): 0x00000000058f7010 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3a3127245f]
/lib64/libc.so.6(cfree+0x4b)[0x3a312728bb]
./t1[0x400500]
/lib64/libc.so.6(__libc_start_main+0xf4)[0x3a3121d994]
./t1[0x400429]
======= Memory map: ========
00400000-00401000 r-xp 00000000 68:02 30246184 /home/sand/testbox/t1
00600000-00601000 rw-p 00000000 68:02 30246184 /home/sand/testbox/t1
058f7000-05918000 rw-p 058f7000 00:00 0 [heap]
3a30e00000-3a30e1c000 r-xp 00000000 68:03 5308733 /lib64/ld-2.5.so
3a3101b000-3a3101c000 r--p 0001b000 68:03 5308733 /lib64/ld-2.5.so
3a3101c000-3a3101d000 rw-p 0001c000 68:03 5308733 /lib64/ld-2.5.so
3a31200000-3a3134e000 r-xp 00000000 68:03 5310248 /lib64/libc-2.5.so
3a3134e000-3a3154e000 ---p 0014e000 68:03 5310248 /lib64/libc-2.5.so
3a3154e000-3a31552000 r--p 0014e000 68:03 5310248 /lib64/libc-2.5.so
3a31552000-3a31553000 rw-p 00152000 68:03 5310248 /lib64/libc-2.5.so
3a31553000-3a31558000 rw-p 3a31553000 00:00 0
3a41c00000-3a41c0d000 r-xp 00000000 68:03 5310264 /lib64/libgcc_s-4.1.2-20080825.so.1
3a41c0d000-3a41e0d000 ---p 0000d000 68:03 5310264 /lib64/libgcc_s-4.1.2-20080825.so.1
3a41e0d000-3a41e0e000 rw-p 0000d000 68:03 5310264 /lib64/libgcc_s-4.1.2-20080825.so.1
2b1912300000-2b1912302000 rw-p 2b1912300000 00:00 0
2b191231c000-2b191231d000 rw-p 2b191231c000 00:00 0
7ffffe214000-7ffffe229000 rw-p 7ffffffe9000 00:00 0 [stack]
7ffffe2b0000-7ffffe2b4000 r-xp 7ffffe2b0000 00:00 0 [vdso]
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0 [vsyscall]
Aborted
[sand@PS-CNTOS-64-S11 testbox]$
[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck ./t1
==20859== Memcheck, a memory error detector
==20859== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20859== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20859== Command: ./t1
==20859==
==20859== Invalid free() / delete / delete[]
==20859== at 0x4A05A31: free (vg_replace_malloc.c:325)
==20859== by 0x4004FF: main (t1.c:8)
==20859== Address 0x4c26040 is 0 bytes inside a block of size 100 free'd
==20859== at 0x4A05A31: free (vg_replace_malloc.c:325)
==20859== by 0x4004F6: main (t1.c:7)
==20859==
==20859==
==20859== HEAP SUMMARY:
==20859== in use at exit: 0 bytes in 0 blocks
==20859== total heap usage: 1 allocs, 2 frees, 100 bytes allocated
==20859==
==20859== All heap blocks were freed -- no leaks are possible
==20859==
==20859== For counts of detected and suppressed errors, rerun with: -v
==20859== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$
[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck --leak-check=full ./t1
==20899== Memcheck, a memory error detector
==20899== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20899== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20899== Command: ./t1
==20899==
==20899== Invalid free() / delete / delete[]
==20899== at 0x4A05A31: free (vg_replace_malloc.c:325)
==20899== by 0x4004FF: main (t1.c:8)
==20899== Address 0x4c26040 is 0 bytes inside a block of size 100 free'd
==20899== at 0x4A05A31: free (vg_replace_malloc.c:325)
==20899== by 0x4004F6: main (t1.c:7)
==20899==
==20899==
==20899== HEAP SUMMARY:
==20899== in use at exit: 0 bytes in 0 blocks
==20899== total heap usage: 1 allocs, 2 frees, 100 bytes allocated
==20899==
==20899== All heap blocks were freed -- no leaks are possible
==20899==
==20899== For counts of detected and suppressed errors, rerun with: -v
==20899== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$
考えられる修正の 1 つ:
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *x = malloc(100);
free(x);
x=NULL;
free(x);
return 0;
}
[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ ./t1
[sand@PS-CNTOS-64-S11 testbox]$
[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck --leak-check=full ./t1
==20958== Memcheck, a memory error detector
==20958== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20958== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20958== Command: ./t1
==20958==
==20958==
==20958== HEAP SUMMARY:
==20958== in use at exit: 0 bytes in 0 blocks
==20958== total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==20958==
==20958== All heap blocks were freed -- no leaks are possible
==20958==
==20958== For counts of detected and suppressed errors, rerun with: -v
==20958== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$
Valgrind Linkの使用に関するブログをチェックしてください
Boost などのスマート ポインターを使用していますshared_ptr
か? その場合は、 を呼び出して、生ポインタをどこでも直接使用しているかどうかを確認してくださいget()
。これは非常に一般的な問題であることがわかりました。
たとえば、未加工のポインターが (コールバック ハンドラーなどとして) コードに渡されるシナリオを想像してみてください。参照カウントなどに対処するために、これをスマート ポインターに割り当てることにするかもしれません。大きな間違い: ディープ コピーを取得しない限り、コードはこのポインターを所有しません。あなたのコードがスマートポインタで完了すると、それを破棄し、誰もそれを必要としないと考えているため、それが指すメモリを破棄しようとしますが、呼び出し元のコードはそれを削除しようとし、double を取得します無料の問題。
もちろん、それはここでの問題ではないかもしれません。最も簡単なのは、これがどのように発生するかを示す例です。最初の削除は問題ありませんが、コンパイラはそのメモリが既に削除されていることを認識し、問題を引き起こします。そのため、削除直後にポインターに 0 を代入することをお勧めします。
int main(int argc, char* argv[])
{
char* ptr = new char[20];
delete[] ptr;
ptr = 0; // Comment me out and watch me crash and burn.
delete[] ptr;
}
編集: ptr は char の配列であるため、 に変更delete
されました。delete[]
これが非常に古いスレッドであることは知っていますが、このエラーの Google 検索のトップであり、エラーの一般的な原因について言及している応答はありません。
すでに閉じたファイルを閉じています。
注意を払っておらず、2 つの異なる関数で同じファイルを閉じると、2 番目の関数でこのエラーが発生します。