删除[]失败,如何查找原因

delete [] failed, how to find out the reason?

本文关键字:查找 何查找 失败 删除      更新时间:2023-10-16

我有一大堆代码整天都在运行。每周一次,当试图释放某个指针时,它会崩溃:

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

我想找出是什么原因导致删除失败:重复删除或其他东西。我怎么能做到呢?

首先,注意反向跟踪包含一个调用malloc_printerr。该函数将把原因写入标准错误,因此请记住捕获它!

不管是不匹配的new/delete类型,双删除还是无效指针,实际的错误早在实际检测到它的delete之前就发生了。所以gdb不会有太大用处。你必须记录发生在相关指针上的任何事情,并找出它何时出错。

  • 如果它是一个无效的指针,它可能是未初始化的内存或缓冲区溢出覆盖它。检查所有对象是否具有正确的构造函数,这些构造函数将可能涉及的任何指针归零。这两种问题都可以用valgrind捕获,缓冲区溢出也可以用较少的开销(但精度较低)使用DUMA库或mudflap (gcc附带)捕获。
  • 如果是double-delete,检查在删除指针后是否将涉及的指针归零,除非是在析构函数中(如果在析构函数中删除指针,请确保在构造函数中初始化它)。为相关指针上的所有操作添加日志消息,当指针崩溃时,在日志中跟踪指针似乎已经复活的位置。您也可以尝试对无效指针执行此操作。
  • 如果[]不匹配,请确保在分配[]时始终使用[]删除,而不是以其他方式删除,并确保始终删除完整类型(c++接受删除不完整类型和未定义行为)。
  • 上述任何一种都可能是没有正确调用持有相关指针的任何对象的析构函数的次要影响。未能调用析构函数可能是删除类型不正确的指针、删除类型不完整的指针或new和delete的[]不匹配的原因。除了检查,添加日志到任何可能相关的构造函数和析构函数,并检查它们是否正确匹配的日志。

不要忘记总是记录指针的值,这样你就可以实际匹配条目。您可能还需要编写一些脚本来分析日志(查找不匹配的条目)。要有足够的空间;通过这种方式很容易生成许多 gb 字节的日志。

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

编写好的单元测试,使用valgrind执行它们,并希望您能捕获错误。

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