In a Windows system, the heap dynamically allocates and manages memory at runtime. Application Verifier specifically checks for access issues and corruption. If you want to detect other kinds of issues, we recommend using the Debug C Run Time (DCRT) library or the Microsoft Foundation Classes (MFC) Debug library. You can learn more on the MSDN website: http://www.msdn.microsoft.com/library/en-us/vccore98/html/_core_memory_management_and_the_debug_heap.asp.
Another great resource for debugging unmanaged applications is John Robbins's excellent book Debugging Applications for Microsoft .NET and Microsoft Windows (Microsoft Press, 2003).
One of the strengths of Application Verifier is that it effectively detects corruption and memory access issues, and does so instantly! The effects of heap corruption are nefarious — a coding mistake can corrupt the heap, which in turn will cause other components to malfunction later because there is a delayed domino effect that is usually difficult to track down. Detecting heap problems without a tool such as Application Verifier can be notoriously difficult.
Depending on the memory conservation settings you picked, you can work with a full or light page heap. The distinction is important because it affects the effectiveness of the heap tests:
Full page heap: This will occur when you select No in the Heap Layer Advanced Options, Conserve Memory option. As explained before, guard pages will be inserted in memory to detect memory corruption. This option enables you to easily find overrun and underrun bugs using the stack trace.
Light page heap: This will occur if you choose Yes to Conserve Memory option. As a result, guard pages are disabled and there will be less consumption of memory. On the downside, although all tests will be enabled, Application Verifier will only be able to detect corruption when a memory block is freed up, which makes it hard to troubleshoot. However, in some circumstances a light page heap is preferable; especially if your application is already using nearly 3GB of memory (see the "Excessive size for the current operation" stop code for more information about Windows built-in memory limitations).
Application Verifier will return specific information about an error, including the heap handle, the block address, the size, and the trace description (in some cases, you will also receive a stack trace to help you track down the error). The following list describes some common heap-related stop codes and the techniques you can use to troubleshoot them:
Memory Access Operation in the context of a freed block reuse-after-delete or double-delete: This error will occur when you try to access a block of memory in the heap after it has been freed or you are trying to repeatedly free a memory block. Once memory has been freed, it is read/write protected and any attempted accesses will result in a break.
To fix this problem, audit any instances where you are freeing memory in your code (for example, via the free operation) and look for duplicates. To rectify this problem, look at the call stack at the point where the target memory has been freed. The call stack will then display where you are trying to access that block of memory in error.
Memory Access Operation in the context of an allocated block: heap overrun or heap under- run: Application Verifier can effectively detect buffer overruns and underruns by inserting guard pages at the beginning or end of memory (see the Conserve Memory Heap Layer options). When these pages are accessed, Application Verifier will break into the "Memory access operation in the context of an allocated block: heap overrun or heap underrun" error.
A heap overrun can easily be caused by trying to write to a buffer beyond the designated memory allocation. Heap overruns and underruns commonly occur with arithmetic and string operations. To fix this problem, look at the call stack for heap memory allocation information and details about where the memory overrun or underrun is happening.
Multithreaded access in a HEAP_NO_SERIALIZE heap: Heap serialization is a useful feature for managing heaps in a multi-threaded application. If a thread frees a heap block and another thread tries to do the same, you will experience a double-free error. A heap created with HEAP_NO_SERIALIZE flag is not supposed to be accessed simultaneously from two threads. The typical way this situation happens in a program is by linking with a single-threaded version of the C runtime.
If you don't specify the library, the compiler will incorporate LIBC.lib by default. Be sure to add the \MT or \MD switches in your compiler commands (or within the Visual Studio IDE options) to specify multi-threaded runtime libraries. An example is shown here:
c:\>cl.exe /MT multithreadedapp.cpp
The MT switch will link your application to the static multi-threaded library (LIBCMT.lib). The MD switch compiles your application using the Dynamic Link Library (DLL) CRT library (located in MSVCRT71.DLL or MSVCRTxx.DLL).
As a best practice (unless you are writing a basic single-threaded application that requires a lot of speed), use the dynamically linked multi-threaded library. It will make your application more secure (the .DLL is regularly updated with hot fixes and service packs) and more reusable.
Please note that the single-threaded CRT libraries, libc.lib, licd.lib, msvcrt.lib, and msvcrtd.lib, are no longer supported in Visual C++ 2005.
Excessive size for the current operation: You can use the HeapAlloc() and HeapReAlloc() operations to allocate a block of memory from the heap. However, be aware that there are limits to the size of the block, depending on the platform you are using. On the 32-bit platform, the usual value is 0x80000000 (on Windows XP, your total memory allowance is 0x7FFDEFFF — Win32 applications have a realistic upper limit of about 2GB). The 64-bit platform has a much higher limit. The stop code may also be triggered if there are problems calculating the allocation size (which would result in a negative value).
To troubleshoot this problem, perform a code review, specifically looking at the HeapAlloc() and HeapReAlloc() calls. Application Verifier will provide you with a call stack to help you track down the problem.
Heap handle with incorrect signature: This error will appear when your heap has been corrupted by random factors, or if you have an incorrect value as a heap handle.
To troubleshoot this problem, do a code review and specifically look at all your handles (with the help of the call stack). Consider the following example:
HANDLE hToken = HeapCreate(0,1000,0);
Is hToken manipulated or altered anywhere in the rest of your code? That is where you'll find the root of your problem.
Heap operation performed on an invalid heap handle: This error is very similar to the "Heap handle with incorrect signature" error. It will occur when you try to access a heap block using the wrong handle. This error is usually accompanied by the following message (which is very useful for tracking down the affected handle):
<handle identifier> was expected
Looking at the handle in question in your code should help you target the problem. You can use the call stack to pinpoint the problem area. This error can also occur as a result of general heap corruption.
The heap block object of the current operation is corrupted: If Application Verifier detects a corrupted heap and can't classify the error using any of the other error codes, it will display the "The heap block object of the current operation is corrupted" stop code. This stop code will also appear when the light page heap can't validate the heap block headers.
The techniques for handling this stop code vary on a case-by-case basis. The stack trace will pinpoint the last operation that accessed the corrupted heap object. You can troubleshoot it using a code review or the CRT Debug Heap. You can learn more at http://www.msdn.microsoft.com/library/en-us/vsdebug/html/_core_solving_buffer_overwrites_and_memory_leaks.asp.
Attempt to destroy process heap: You can't destroy the default process heap — any attempts to do so will result in an access violation. You can access the default heap using the GetProcessHeap() function (without any arguments).
To troubleshoot this error, look at all relevant HeapDestroy calls in your code. The call stack will pinpoint the problem area. One possible problem is that you are passing a handle to the default heap instead of your custom heap.
Unexpected exception raised in heap code path: Unless you are validating the heap (using a function call such as HeapValidate()), this stop code indicates that there is a condition that caused an access violation. This stop code can appear, for example, when random heap corruption occurs, because of a "double-free," and when there are problems with the heap blocks. You can find and fix the source of the exception by looking at the exception record information.
Exception raised while verifying block header: Sometimes Application Verifier will find corruption from an indeterminate source — for example, when you are trying to free up memory and you pass a pointer to an inaccessible address in memory. The header contains useful information such as user-requested size, real size, owning heap, and, in some cases, a stack trace.
Much like other "indeterminate" errors, your best bet is to look at the stack trace and review your code.
Corrupted infix pattern for freed block: Whenever blocks of memory are freed, they are marked. When you are running a full-page heap, these blocks are marked protected and will cause access violation errors.
When you are running in light page heap, the memory blocks are marked with a distinctive infix pattern. Eventually, the block will be freed. If the infix pattern has been modified (the memory block has been corrupted), then you will receive this error and your application will break.
Your best bet for tackling this error is doing a thorough code review based on the information returned by the Application Verifier or enabling a full-page heap by setting Conserve Memory to No.
Corrupted suffix pattern: In theory, if your memory is properly managed, it should properly fit in the space allocated to it. A suffix pattern is a data integrity pattern added to your application memory space when it is relegated into protected memory. Before finally disposing or reusing memory, the heap manager will look at the suffix pattern. If your application uses more memory than allocated, your suffix pattern will not match up and will throw a "Corrupted suffix pattern" error in Application Verifier.
This type of error is indicative of a buffer overrun. You can use the stack trace and the block address to pinpoint the source, but bear in mind that this particular error may be hard to troubleshoot (because you will be alerted when your application memory is freed, rather than at the source of the corruption). A solid review of the affected code can help; the only information you are provided with is the allocation stack trace and a pointer to your code when the stop code is triggered.
Corrupted start stamp of block header: This error is very similar to the "Corrupted suffix pattern" error because it denotes that the integrity of the start stamp of the block header has been compromised. This error is indicative of a buffer underrun.
For this error, apply same recommendations for the previous stop code: Pinpoint the problem space using the stack trace and perform a code review.
Corrupted end stamp of block header: This stop code indicates that the end stamp of your memory block header has been corrupted and your application caused a buffer underrun. Refer to the stack trace to determine where the heap allocation occurred. You can then use the call stack to find the buffer underrun.
Corrupted prefix pattern: Like the suffix pattern, the prefix pattern can also be corrupted in the case of a buffer underrun, or if there was a buffer overrun from the previous block.
Please follow the troubleshooting guidelines outlined for the "Corrupted suffix pattern" error to solve this problem.
Process heap list count is wrong: This stop code will come up when GetProcessHeaps() is used and the page heap manager detects problems with the process address space (sometimes caused by corruption). As mentioned before, heap corruption issues are fundamentally difficult to troubleshoot. An in-depth code review might reveal problems in some cases.