Share via

Memory Management and the Debug Heap

Two of the most common and intractable problems that programmers encounter are overwriting the end of an allocated buffer and leaking memory (failing to free allocations after they are no longer needed). The debug heap provides powerful tools to solve memory allocation problems of this kind.

The debug versions of the heap functions call the standard or base versions used in release builds. When you request a memory block, the debug heap manager allocates from the base heap a slightly larger block of memory than requested and returns a pointer to your portion of that block. For example, suppose your application contains the call: malloc( 10 ). In a release build, malloc would call the base heap allocation routine requesting an allocation of 10 bytes. In a debug build, however, malloc would call _malloc_dbg, which would then call the base heap allocation routine requesting an allocation of 10 bytes plus approximately 36 bytes of additional memory. All the resulting memory blocks in the debug heap are connected in a single linked list, ordered according to when they were allocated:

The additional memory allocated by the debug heap routines is used for bookkeeping information, for pointers that link debug memory blocks together, and for small buffers on either side of your data to catch overwrites of the allocated region.

Currently, the block header structure used to store the debug heap’s bookkeeping information is declared as follows in the DBGINT.H header file:

typedef struct _CrtMemBlockHeader
// Pointer to the block allocated just before this one:
   struct _CrtMemBlockHeader *pBlockHeaderNext;
// Pointer to the block allocated just after this one:
   struct _CrtMemBlockHeader *pBlockHeaderPrev;
   char *szFileName;   // File name
   int nLine;          // Line number
   size_t nDataSize;   // Size of user block
   int nBlockUse;      // Type of block
   long lRequest;      // Allocation number
// Buffer just before (lower than) the user's memory:
   unsigned char gap[nNoMansLandSize]; 
} _CrtMemBlockHeader;

/* In an actual memory block in the debug heap,
 * this structure is followed by:
 *    unsigned char data[nDataSize];
 *    unsigned char anotherGap[nNoMansLandSize];

The “NoMansLand” buffers on either side of the user data area of the block are currently 4 bytes in size, and are filled with a known byte value used by the debug heap routines to verify that the limits of the user’s memory block have not been overwritten. The debug heap also fills new memory blocks with a known value. If you elect to keep freed blocks in the heap’s linked list as explained below, these freed blocks are also filled with a known value. Currently, the actual byte values used are as follows:

NoMansLand (0xFD)

The “NoMansLand” buffers on either side of the memory used by an application are currently filled with 0xFD.

Freed blocks (0xDD)

  The freed blocks kept unused in the debug heap’s linked list when the _CRTDBG_DELAY_FREE_MEM_DF flag is set are currently filled with 0xDD.

New objects (0xCD)

New objects are filled with 0xCD when they are allocated.