|
Updated: 01.09.2005
We were in the middle of the debugging session, when suddenly the debugger displayed
a message similar to the following:
User breakpoint called from code at 0x77fa018c
or the following:
Unhandled exception at 0x77f767cd (ntdll.dll) in myapp.exe: User breakpoint.
What happened? We did not even set any breakpoints, so why there is a user breakpoint?
The problem starts looking even stranger when we notice that the application works fine
when we start it outside of the debugger! But under debugger it keeps showing the message
about user breakpoint, so that we cannot effectively debug our application anymore.
Searching for an answer, we look at Debug Output window. And yes, there is another message!
For example:
HEAP[myapp.exe]: Heap block at 00360F78 modified at 00360F90 past requested size of 10
Aha, it looks like the heap is corrupted. The contents of Call Stack window also point to the heap:
NTDLL! DbgBreakPoint@0 address 0x77fa018c
NTDLL! RtlpBreakPointHeap@4 + 38 bytes
NTDLL! RtlpCheckBusyBlockTail@4 + 106 bytes
NTDLL! RtlpValidateHeapEntry@12 + 146975 bytes
NTDLL! RtlDebugFreeHeap@12 + 191 bytes
NTDLL! RtlFreeHeapSlowly@12 + 70765 bytes
NTDLL! RtlFreeHeap@12 + 4078 bytes
MYAPP! free + 102 bytes
MYAPP! operator delete(void *) + 9 bytes
main(int 1, char * * 0x003610b0) line 21 + 15 bytes
MYAPP! mainCRTStartup + 180 bytes
KERNEL32! BaseProcessStart@4 + 130958 bytes
It turns out that when we start the application under debugger, the operating system uses a special
kind of heap – Debug Win32 heap – instead of the normal heap. Whenever an operation on the heap
is performed (such as allocating or freeing memory), the debug heap manager checks integrity of
the heap entries and internal structures. If it founds a corruption, it notifies us via a hard-coded
breakpoint, which is reported by the debugger.
How can we find the reason of the heap corruption? We can of course employ a specialized runtime
checker application (such as BoundsChecker,
Purify or
Memory Validator), but I prefer
to use PageHeap, because it is part of the operating system (since Windows 2000 SP2) and is easy to use.
Detailed technical information about PageHeap can be found
in KB286470.
We can enable Full PageHeap with the help of the following Registry entries:
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\yourapp.exe
GlobalFlag = REG_DWORD 0x2000000
PageHeapFlags = REG_DWORD 0x3
(replace yourapp.exe with the real name of your executable)
If you have Debugging Tools for Windows
installed, there is another way to achieve the same – run the following command:
gflags –p /enable yourapp.exe /full
(gflags.exe can be found in the installation directory of Debugging Tools)
After we have enabled Full PageHeap, we should run the application under debugger and wait
for access violations or hard-coded breakpoints. After an access violation occurred or
a breakpoint has been hit, examination of the current source line and the call stack
usually allows us to immediately see who is corrupting the heap.
Note also that it is recommended to link the application with release version of CRT library
(that is, use /ML, /MT or /MD compiler option (or the corresponding IDE equivalent) instead
of /MLd, /MTd or /MDd option). This is because debug version of CRT library uses its own heap
checking infrastructure (by the way, not as powerful as Full PageHeap), which can overlap
with PageHeap and hide some errors instead of exposing them.
Another situation that worth talking about is when we are debugging a DLL that is loaded by
a large application (often a 3rd party application). Since there is probably no point
in checking the whole application with PageHeap, we can ask it to check only the heap
entries that are allocated by our DLL:
gflags –p /enable yourapp.exe /full /dlls yourdll.dll
|