c++ - 如果消毒剂没有显示任何内容,我该如何调试内存崩溃?
问题描述
我有一个复杂的应用程序在退出时崩溃。我无法通过最小的示例重现错误。当在应用程序退出时调用类的析构函数并且共享指针成员被破坏时,就会发生崩溃。我基本上在做的是这样的:
// plugin (.so loaded at runtime)
// called during application run
void SomePluginClass::foo()
{
auto ptr = std::make_shared<int>();
libraryObj.bar(ptr);
}
// library (.so linked to the executable and the plugin)
// SomeLibraryClass.hpp
class SomeLibraryClass
{
public
// ... some other code
~SomeLibraryClass();
void bar(std::shared_ptr<int> ptr);
private:
std::shared_ptr<int> m_ptr{};
}
// SomeLibraryClass.cpp
// called during application run
void SomeLibraryClass::bar(std::shared_ptr<int> ptr) { m_ptr = ptr; }
// called on application exit and cleanup
SomeLibraryClass::~SomeLibraryClass()
{
// crash happens here
// use_count shows 1
// reset() used here for debugging purposes as it causes the same crash as implicit destructor call
m_ptr.reset();
}
我尝试使用Valgrind
gcc address sanitizer 运行应用程序——它们在运行时都没有显示任何问题,但在崩溃后显示了问题。例如,这里有一些 sanitizer 的输出:
==11744==ERROR: AddressSanitizer: SEGV on unknown address 0x7f56b3ba0c20 (pc 0x555ac6680ead bp 0x7ffc9d3ce920 sp 0x7ffc9d3ce910 T0)
==11744==The signal is caused by a READ memory access.
#0 0x555ac6680eac in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/7/bits/shared_ptr_base.h:154
#1 0x555ac6680b33 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/7/bits/shared_ptr_base.h:684
#2 0x7f56e5e562cd in std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/7/bits/shared_ptr_base.h:1123
#3 0x7f56e5e56574 in std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2>::reset() /usr/include/c++/7/bits/shared_ptr_base.h:1235
数字是什么(pc 0x555ac6680ead bp 0x7ffc9d3ce920 sp 0x7ffc9d3ce910 T0)
意思?
我还能做些什么来找到崩溃源?
解决方案
数字(pc 0x555ac6680ead bp 0x7ffc9d3ce920 sp 0x7ffc9d3ce910 T0)是什么意思?
在崩溃时(由试图访问地址引起0x7f56b3ba0c20
),程序计数器 (PC)、帧指针 (BP) 和堆栈指针 (SP) 寄存器的值分别为0x555ac6680ead
,0x7ffc9d3ce920
和0x7ffc9d3ce910
。
程序计数器值对应于std::_Sp_counted_base<...>::_M_release()
功能。
我们不知道崩溃地址0x7f56b3ba0c20
来自哪里。它不在当前堆栈指针附近,看起来不像堆地址(尽管它可能是),也不像随机垃圾。ASan 也不知道这个地址是从哪里来的。
一种可能的解释:地址在堆上,然后被删除并移动到隔离区(ASan 用它来告诉您有关悬空访问的信息),但随后隔离区容量被其他delete
s 超出,导致 ASan “忘记”它所知道的关于那个地址(ASan 不能永远保存关于每个已删除内存块的信息——这会导致你的内存用完)。
您可以尝试使用以下方法增加 ASan 隔离缓冲区的大小:
ASAN_OPTIONS=quarantine_size_mb=4096
(默认为 256,增加直到内存不足或 ASan 告诉您实际上正在访问悬空内存)。
推荐阅读
- python - 比较python ValueError中的数据对象
- python - 在 tkinter 中单击按钮时删除/清除功能
- c - Linux/ubuntu/stat() 中没有这样的文件或目录,但该文件存在
- javascript - 在反应测试库中测试失败
- arrays - 数组公式索引匹配?
- matlab - 如何将此 .csv 文件中的日期正确导入 Matlab?
- r - 具有多个条件的左连接
- python - 不使用引号时 pip install 无法安装附加功能
- excel - VBA Excel。运行时错误“1004”。应用程序定义或操作定义的错误
- python - 在 Python 中转换单列抓取的数据 csv