我观察到一个桌面崩溃。经过调试,结果发现这是由于无意中销毁了一个对象,但我想知道为什么这会导致堆损坏。以及为什么这不会触发我们的崩溃处理程序。
有一个QDialog A,它应该在应用程序的整个生命周期中保持活动。它使用new分配,并由std::shared_ptr
管理。在某些情况下,此对话框被赋予另一个对话框B作为父对话框。另一个对话框超出了范围,并销毁了它的所有子对话框,包括对话框A。堆栈跟踪为:
ntdll.dll!RtlReportCriticalFailure()
ntdll.dll!RtlpHeapHandleError()
ntdll.dll!RtlpHpHeapHandleError()
ntdll.dll!RtlpLogHeapFailure()
ntdll.dll!RtlpFreeHeapInternal()
ntdll.dll!RtlFreeHeap()
ucrtbase.dll!_free_base()
A::`scalar deleting destructor'(unsigned int)
QtCore4.dll!00000000573ba2cf()
QtGui4.dll!000000005696be43()
functionWhereBGoesOutOfScope()
...
为什么Windows在这个时间点已经抱怨了?我本来希望dtor在这里能顺利通过,但当应用程序关闭并且std::unique_ptr
试图(再次)销毁A时,我希望会发生访问冲突。
异常处理?
为什么这不会触发我们的崩溃处理?我们调用SetUnhandledExceptionFilter
来注册一个写崩溃转储的回调。但这根本不会发生。只是电脑死机了。如果没有附加调试器,进程将消失得无影无踪。
->在评论中回答:Heap corruption is special,不会触发任何异常处理程序。
我一直在努力
阅读文档。RtlFreeHeap
documentation是无用的。错误情况或堆损坏根本没有得到解决。其他功能根本没有公共文档。
在阅读https://stackoverflow.com/a/22074401/872616后附加WinDbg。!heap
说
**************************************************************
* *
* HEAP ERROR DETECTED *
* *
**************************************************************
Details:
Heap address: 00000182adfa0000
Error address: 00000182ba16f050
Error type: HEAP_FAILURE_BLOCK_NOT_BUSY
Details: The caller performed an operation (such as a free
or a size check) that is illegal on a free block.
Follow-up: Check the error's stack trace to find the culprit.
Stack trace:
Stack trace at 0x00007fff8ef39848
00007fff8eede361: ntdll!RtlpLogHeapFailure+0x45
00007fff8edf5bf0: ntdll!RtlpFreeHeapInternal+0x4e0
00007fff8edf47b1: ntdll!RtlFreeHeap+0x51
00007fff8c81f05b: ucrtbase!_free_base+0x1b
*** WARNING: Unable to verify checksum for xxx64.dll
00007ffe8aacc227: xxx64!A::`scalar deleting destructor'+0x87
*** WARNING: Unable to verify checksum for ...\Qt-4.8.7-VS15x64\bin\QtCore4.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ...\Qt-4.8.7-VS15x64\bin\QtCore4.dll -
00000000573ba2cf: QtCore4!QObjectPrivate::deleteChildren+0x9f
*** WARNING: Unable to verify checksum for ...\Qt-4.8.7-VS15x64\bin\QtGui4.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ...\Qt-4.8.7-VS15x64\bin\QtGui4.dll -
000000005696be43: QtGui4!QWidget::~QWidget+0x893
00007ffe8b1a8425: xxx64!functionWhereBGoesOutOfScope+0x345
上面写着“在空闲区块上非法”,意味着双重免费。这就解释了为什么Windows会抱怨。但据我所知,那个街区不应该是免费的。
我尝试在A的dtor中设置断点,但它们在Release模式下不会被触发,可能都是内联的。在Debug模式下,它们会被触发,但只有一次,这将排除双重释放。
1条答案
按热度按时间yyyllmsg1#
原因是
std::make_shared
,可能是因为它使用了带有指针魔法的placement new。作为一个实验,当我用
std::shared_ptr::reset
设置shared_ptr
变量并直接调用new时,它的行为符合预期:问题发生在以后。因为shared_ptr被访问,或者当应用程序退出并且shared_ptr第二次尝试删除对话框时。正确的解决方法是不使用
shared_ptr
和QObject
s。