如何追踪"双重免费或损坏"错误

neu*_*cer 71 c c++ debugging free

当我运行我的(C++)程序时,它会因此错误而崩溃.

*glibc检测到* ./load:双重免费或损坏(!prev):0x0000000000c6ed50***

如何追踪错误?

我尝试使用print(std::cout)语句,没有成功.可以gdb让这更容易吗?

Has*_*kun 54

如果您正在使用glibc,则可以将MALLOC_CHECK_环境变量设置为2,这将导致glibc使用容错版本malloc,这将导致程序在双重释放的位置中止.

您可以set environment MALLOC_CHECK_ 2在运行程序之前使用命令从gdb设置此项; 该程序应该中止,free()在回溯中可以看到该调用.

有关更多信息,请参见手册页malloc()

  • @puk 我有同样的问题,将 MALLOC_CHECK_ 设置为 2 确实避免了我的双重免费问题。还有什么其他选项可以注入尽可能少的代码来重现问题并提供回溯? (4认同)
  • 设置`MALLOC_CHECK_2`实际上修复了我的双重释放问题(尽管它仅在调试模式下无法修复) (3认同)

Kor*_*icz 25

至少有两种可能的情况:

  1. 你要删除两次相同的实体
  2. 你正在删除未分配的东西

对于第一个,我强烈建议对所有删除的指针进行NULL处理.

你有三个选择:

  1. 重载new并删除并跟踪分配
  2. 是的,使用gdb - 那么你将从崩溃中得到一个回溯,这可能会非常有帮助
  3. 正如建议的那样 - 使用Valgrind - 它并不容易进入,但它将在未来为您节省数千倍的时间......


Mat*_*hen 20

你可以使用gdb,但我会首先尝试Valgrind.请参阅快速入门指南.

简而言之,Valgrind会对您的程序进行检测,以便在使用动态分配的内存时检测到多种错误,例如双重释放和写入已分配的内存块(可能会损坏堆)的结尾.它会在错误发生时立即检测并报告错误 ,从而直接指出问题的原因.


Jac*_*ack 17

三个基本规则:

  1. 将指针设置为NULL空闲后
  2. NULL在解放前检查.
  3. NULL在开始时初始化指针.

这三个作品的结合相当不错.

  • @ Component10我认为C标准要求释放NULL什么都不做. (9认同)
  • 严格来说,我认为#2是不必要的,因为大多数编译器都会允许您尝试删除空指针而不会导致问题.如果我错了,我相信有人会纠正我.:) (8认同)
  • @Demetri:是的,你是对的*"如果delete的操作数的值是空指针,则操作无效." (ISO/IEC 14882:2003(E)5.3.5.2)* (2认同)

小智 14

您可以使用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]$
Run Code Online (Sandbox Code Playgroud)

一个可能的解决方

#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]$
Run Code Online (Sandbox Code Playgroud)

查看使用Valgrind Link的博客


Sit*_*esh 6

使用现代C++编译器,您可以使用清洁剂进行跟踪.

示例示例:

我的节目:

$cat d_free.cxx 
#include<iostream>

using namespace std;

int main()

{
   int * i = new int();
   delete i;
   //i = NULL;
   delete i;
}
Run Code Online (Sandbox Code Playgroud)

使用地址清理程序编译:

# g++-7.1 d_free.cxx -Wall -Werror -fsanitize=address -g
Run Code Online (Sandbox Code Playgroud)

执行 :

# ./a.out 
=================================================================
==4836==ERROR: AddressSanitizer: attempting double-free on 0x602000000010 in thread T0:
    #0 0x7f35b2d7b3c8 in operator delete(void*, unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140
    #1 0x400b2c in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:11
    #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)
    #3 0x400a08  (/media/sf_shared/jkr/cpp/d_free/a.out+0x400a08)

0x602000000010 is located 0 bytes inside of 4-byte region [0x602000000010,0x602000000014)
freed by thread T0 here:
    #0 0x7f35b2d7b3c8 in operator delete(void*, unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140
    #1 0x400b1b in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:9
    #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)

previously allocated by thread T0 here:
    #0 0x7f35b2d7a040 in operator new(unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:80
    #1 0x400ac9 in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:8
    #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)

SUMMARY: AddressSanitizer: double-free /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140 in operator delete(void*, unsigned long)
==4836==ABORTING
Run Code Online (Sandbox Code Playgroud)

要了解有关消毒剂的更多信息,您可以查看或任何现代c ++编译器(例如gcc,clang等)文档.


Com*_* 10 5

您是否使用智能指针,例如 Boost shared_ptr?如果是这样,请检查您是否通过调用在任何地方直接使用原始指针get()。我发现这是一个很常见的问题。

例如,想象一个原始指针被传递给你的代码的场景(比如作为回调处理程序)。您可能决定将其分配给智能指针以应对引用计数等。大错误:除非您进行深层复制,否则您的代码不拥有此指针。当您的代码使用智能指针完成时,它将销毁它并尝试销毁它指向的内存,因为它认为没有其他人需要它,但是调用代码将尝试删除它,您将得到一个双倍免费问题。

当然,这可能不是你的问题。这是最简单的例子,它展示了它是如何发生的。第一次删除没问题,但编译器感觉到它已经删除了该内存并导致了问题。这就是为什么在删除后立即将 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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:更改deletedelete[],因为 ptr 是一个字符数组。