I've observed a crash to desktop. After debugging it turned out that it was somehow due to an unintended destruction of an object, but I'd like to understand why this results in heap corruption. And why this doesn't trigger our crash handler.
There is a QDialog A that is supposed to stay alive through the lifetime of the application. It's allocated with new, and managed by a std::shared_ptr
. Under some circumstances, this dialog was given another dialog B as parent. That other dialog went out of scope, and destroyed all its children, including dialog A. The stack trace is:
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()
...
Why does Windows complain already at this point in time? I would have expected the dtor to go through fine here, and instead expect an access violation later when the application closes and the std::unique_ptr
tries to destroy A (again).
Exception handling?
Also why does this not trigger our crash handling? We call SetUnhandledExceptionFilter
to register a callback that writes a crash dump. But this doesn't happen at all. It's just a crash to desktop. Without a debugger attached, the process vanishes without a trace.
-> Answered in comment: Heap corruption is special and won't trigger any exception handler.
What I've tried so far
Read documentation. The RtlFreeHeap
documentation is unhelpful. Error cases or heap corruption are not addressed at all. The other functions have no public documentation at all.
Attached WinDbg after reading https://stackoverflow.com/a/22074401/872616. !heap
says
**************************************************************
* *
* 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
It says "illegal on a free block", implying a double free. That would explain why Windows complains. But as far as I know, that block should not be free.
I've tried to set breakpoints in A's dtor, but they're not triggered in Release mode, probably all inlined. In Debug mode they're triggered, but only once, which would rule out the double free.