如何用gdb跟踪C ++中的double free或者corrupt错误
当我运行我的C ++程序时,它崩溃了这个错误。
*检测到glibc * ./load:double free或者腐败(!prev):0x0000000000c6ed50 ***
我试图使用cout声明来追踪它,但是我发现它很困难。 gdb可以使这更容易吗? 它是如何完成的?
如果你使用的是glibc,你可以将MALLOC_CHECK_
环境variables设置为2
,这将导致glibc使用malloc
容错版本,这会导致你的程序在double free被完成的地方中止。
你可以在运行你的程序之前使用set environment MALLOC_CHECK_ 2
命令从gdb set environment MALLOC_CHECK_ 2
; 程序应该放弃,在回溯中可以看到free()
调用。
有关更多信息,请参阅malloc()
的手册页
至less有两种可能的情况:
- 您正在删除相同的实体两次
- 你正在删除没有分配的东西
对于第一个我强烈build议NULL删除所有删除的指针。
你有三个select:
- 重载新的和删除并跟踪分配
- 是的,使用gdb – 那么你会从你的崩溃中得到一个回溯,这可能会非常有帮助
- 正如所build议的那样 – 使用Valgrind – 进入并不容易,但将来会为您节省千倍的时间。
你可以使用gdb,但我会先尝试Valgrind 。 请参阅快速入门指南 。
三条基本规则:
- 空闲后将指针设置为NULL
- 释放前检查NULL。
- 在开始时初始化指向NULL的指针。
这三部作品相结合的不错。
你可以使用valgrind
来debugging它。
#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]$
一个可能的修复:
#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 链接的博客
你是否使用智能指针,如Boost shared_ptr
? 如果是这样,请通过调用get()
来检查是否直接使用原始指针。 我发现这是一个相当普遍的问题。
例如,想象一个原始指针传递给你的代码的场景(可能是callback处理程序)。 你可能会决定把它分配给一个智能指针,以便处理引用计数等。大错误:除非你进行深度复制,否则你的代码不拥有这个指针。 当你的代码用智能指针完成时,它会销毁它,并试图销毁它指向的内存,因为它认为没有人需要它, 但调用代码然后将尝试删除它,你会得到一个双免费问题。
当然,这可能不是你的问题。 这是最简单的一个例子,它显示了如何发生。 第一次删除是好的,但编译器意识到它已经删除了内存,并导致一个问题。 这就是为什么在删除后立即将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; }
编辑:改变delete
delete[]
,因为ptr是一个字符数组。
我知道这是一个非常古老的线程,但它是谷歌search这个错误的最高层,没有一个响应提到错误的常见原因。
哪一个正在closures你已经closures的文件。
如果你不注意并且有两个不同的函数closures同一个文件,那么第二个会产生这个错误。