2

我有一整天都在运行的大量代码。每周一次,它在尝试释放一些指针时崩溃:

delete [] p

回溯(使用 gdb):

0x00007f4f709f2885 in raise () from /lib64/libc.so.6
0x00007f4f709f4065 in abort () from /lib64/libc.so.6
0x00007f4f70a2f7a7 in __libc_message () from /lib64/libc.so.6
0x00007f4f70a350c6 in malloc_printerr () from /lib64/libc.so.6

我想找出导致删除失败的原因:重复删除或其他。我怎样才能做到这一点?

4

2 回答 2

2

首先,请注意回溯包含一个 call malloc_printerr。该函数会将原因写入标准错误,因此请记住将其捕获!

现在,无论是不匹配的新/删除类型、双重删除还是完全无效的指针,实际的错误都发生在实际检测到它的删除之前很久。所以 gdb 不会有太大用处。您必须记录相关指针发生的任何事情,并在出错时进行挖掘。

  • 如果它完全是无效指针,则可能是未初始化的内存或缓冲区溢出覆盖它。检查所有对象是否具有正确的构造函数,这些构造函数将可能涉及的任何指针归零。使用valgrind也可以捕获任一问题,也可以使用DUMA 库mudflap(随 gcc 提供)以更少的开销(但精度更低)捕获缓冲区溢出。
  • 如果它是双重删除的,请检查是否在删除后将任何涉及的指针清零,除非在析构函数中(如果在析构函数中删除它,请确保在构造函数中对其进行了初始化)。为涉及的指针上的所有操作添加日志消息,当它崩溃时,在日志中追溯指针似乎已复活的位置。您也可以尝试对无效指针执行此操作。
  • 如果它不匹配[],请确保[]在分配时始终删除 with[]而不是其他情况,并确保始终删除完整类型(C++ 接受删除不完整类型,这是未定义的行为)。
  • 以上任何情况也可能是未正确调用任何持有相关指针的对象的析构函数的次要影响。未能调用析构函数可能是因为删除了类型不正确的指针、删除了指向不完整类型的指针或[]new 和 delete 不匹配。除了审查之外,将日志添加到可能相关的任何构造函数和析构函数,并在日志中检查它们是否正确匹配。

不要忘记始终记录指针值,以便您可以实际匹配条目。您可能还需要编写一些脚本来分析日志(查找不匹配的条目)。并有足够的空间放置它;以这种方式生成许多千兆字节的日志相当容易。

一旦您缩小了一些可疑操作的范围,您可能需要将回溯写入日志。查看backtrace(3)库函数或libunwind

于 2013-01-16T09:14:16.507 回答
1

编写好的单元测试,使用 valgrind 执行它们,并希望你能发现错误。

除此之外,您可以查看您的代码并搜索错误(例如,“Good Clues, Easy Bugs”文章解释了调试技术)。

于 2013-01-16T08:47:10.447 回答