Windows Tools

PageHeap Examples

Overview | Notes | Syntax | Examples | Related Tools

Example 1: Test an Application Using PageHeap

Your application (pheap-buggy.exe) seems to have a problem with the heap. To enable normal page heap checking for the application, thereby minimizing the memory requirements, type the following at the command line:

pageheap /enable pheap-buggy.exe

To make sure that the partial page heap is actually enabled, type the following at the command line:

pageheap

You should see output similar to the following, confirming that partial page heap is enabled for pheap-buggy.exe:

pheap-buggy.exe: page heap enabled with flags

Next you need to run the application in a debugger. Type the following at the command line:

ntsd -g -x pheap-buggy /CorruptAfterEnd

When the application fails, you will see output similar to the following:

===========================================================
VERIFIER STOP 00000008: pid 0xAA0: corrupted suffix pattern

		00C81000 : Heap handle 
		00D81EB0 : Heap block 
		00000100 : Block size 
		00000000 :
===========================================================

Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00d81eb0 ecx=77f7e257 edx=0006fa18 esi=00000008 edi=00c81000
eip=77f7e098 esp=0006fc48 ebp=0006fc5c iopl=0		 nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000			 efl=00000246
ntdll!DbgBreakPoint:
77f7e098 cc			 int	 3

The header information contains the address of the heap where the corrupted block is (00C81000 : Heap handle), the address of the corrupted block itself (00D81EB0 : Heap block) and the size of the allocation (00000100 : Block size). It is clear that PageHeap caught an error in pheap-buggy.exe. To further investigate the cause of the error by turning on line number dumping, type the following in the debuger:

.lines

The following information is displayed:

Line number information will be loaded

To specify that you want a call stack, type the following in the debugger:

kb

You will see output similar to the following call stack:

ChildEBP RetAddr  Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0006fc5c 77f9e6dd 00000008 77f9e3e8 00c81000 ntdll!DbgBreakPoint
0006fcd8 77f9f3c8 00c81000 00000004 00d81eb0 ntdll!RtlpNtEnumerateSubKey+0x2879
0006fcfc 77f9f5bb 00c81000 01001002 00000010 ntdll!RtlpNtEnumerateSubKey+0x3564
0006fd4c 77fa261e 00c80000 01001002 00d81eb0 ntdll!RtlpNtEnumerateSubKey+0x3757
0006fdc0 77fc0dc2 00c80000 01001002 00d81eb0 ntdll!RtlpNtEnumerateSubKey+0x67ba
0006fe78 77fbd87b 00c80000 01001002 00d81eb0 ntdll!RtlSizeHeap+0x16a8
0006ff24 010013a4 00c80000 01001002 00d81eb0 ntdll!RtlFreeHeap+0x69
0006ff3c 01001450 00000000 00000001 0006ffc0 pheap-buggy!TestCorruptAfterEnd+0x2b [d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 185]
0006ff4c 0100157f 00000002 00c65a68 00c631d8 pheap-buggy!main+0xa9 [d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 69]
0006ffc0 77de43fe 00000000 00000001 7ffdf000 pheap-buggy!mainCRTStartup+0xe3 [crtexe.c @ 349]
0006fff0 00000000 0100149c 00000000 78746341 kernel32!DosPathToSessionPathA+0x204

Looking at this call stack, you see that this bug was caught when the function TestCorruptAfterEnd in pheap-buggy.exe tried to free an allocation at 0x00c80000 by calling HeapFree, which is just a redirect to RtlFreeHeap. You suspect that this "corrupted suffix pattern" break means that the application has violated a data integrity pattern after the end of its heap allocation. This leads you to believe that your code has written past the end of the buffer it allocated here. To quit the debugger so that you can look at your code, type the following in the debugger:

q

You look for the bug in your code, but you cannot find the problem. You decide to change PageHeap mode from normal to full and see if it can catch the misuse of this heap buffer at the exact time of misuse. To enable full-page heap for pheap-buggy.exe, type the following at the command line:

pageheap /enable pheap-buggy.exe /full

To make sure that full-page heap is actually enabled, type the following at the command line:

pageheap

You should see output similar to the following, confirming that full-page heap is enabled for pheap-buggy.exe:

pheap-buggy.exe: page heap enabled with flags (full traces )

To run pheap-buggy.exe in the debugger, type the following at the command line:

ntsd -g -x pheap-buggy /CorruptAfterEnd

When the application fails, you will see output similar to the following:

Page heap: process 0x5BC created heap @ 00880000 (00980000, flags 0x3)
ModLoad: 77db0000 77e8c000   kernel32.dll
ModLoad: 78000000 78046000   MSVCRT.dll
Page heap: process 0x5BC created heap @ 00B60000 (00C60000, flags 0x3)
Page heap: process 0x5BC created heap @ 00C80000 (00D80000, flags 0x3)
Access violation - code c0000005 (first chance)
Access violation - code c0000005 (!!! second chance !!!)
eax=00c86f00 ebx=00000000 ecx=77fbd80f edx=00c85000 esi=00c80000 edi=00c16fd0
eip=01001398 esp=0006ff2c ebp=0006ff4c iopl=0		 nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000			 efl=00000206
pheap-buggy!TestCorruptAfterEnd+1f:
01001398 889801010000	 mov	 [eax+0x101],bl		ds:0023:00c87001=??

This time you have an access violation. To investigate the actual location of the access violation, you turn on line number dumping again by typing the following in the debuger:

.lines

The following information is displayed:

Line number information will be loaded

Once again you specify that you want a call stack by typing the following in the debugger:

kb

You will see output similar to the following call stack:

ChildEBP RetAddr  Args to Child
0006ff3c 01001450 00000000 00000001 0006ffc0 pheap-buggy!TestCorruptAfterEnd+0x1f [d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 184]
0006ff4c 0100157f 00000002 00c16fd0 00b70eb0 pheap-buggy!main+0xa9 [d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 69]
0006ffc0 77de43fe 00000000 00000001 7ffdf000 pheap-buggy!mainCRTStartup+0xe3 [crtexe.c @ 349]
WARNING: Stack unwind information not available. Following frames may be wrong.
0006fff0 00000000 0100149c 00000000 78746341 kernel32!DosPathToSessionPathA+0x204

You can see by the stack trace that the problem takes place at line 184 of pheap-buggy.exe ([d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 184]). Because you used a full-page heap, this time the call stack starts in your code, not in a system DLL. As a result the bug was caught as it happened instead of when the heap block was freed. To quit the debugger so that you can look at your code, type the following in the debugger:

q

Line 184 in pheap-buggy.cxx reads as follows:

*((PCHAR)Block + 0x100 + 1) = 0;

Looking at this code you see that the buffer is 0x100 bytes large, but you are trying to write to the 0x101th byte. You have identified the bug. It is an off-by-one error where you have written beyond the end of the memory allocation.