I discovered this when playing with the standard malloc function and calling HeapWalk to see the size of the allocated block. Found out that malloc does not create blocks in the default process heap but rather in a second heap that I did not create.
Why are there two heaps? Even without calling malloc the process still has two heaps and the second one is not empty. This is the result of HeapWalk on the second heap without any call to malloc or HeapAlloc.
Also because of this behaviour of malloc another question crossed my mind. Is it correct to allocate memory on the default process heap? I never created a new heap for casual programs and did HeapAlloc(GetProcessHeap(), ...) but is this practice harmful or bad in any way?
This is the code i used for testing:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define MAX_HEAP_COUNT 10
INT APIENTRY WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
HANDLE hHeaps[MAX_HEAP_COUNT];
DWORD dwHeaps;
dwHeaps = GetProcessHeaps(MAX_HEAP_COUNT, hHeaps);
LPVOID lpDummyBlocks[20];
for(DWORD i = 0; i < 20; i++)
lpDummyBlocks[i] = malloc(rand()%1000+1);
for(DWORD i = 0; i < dwHeaps; i++)
{
SIZE_T cbSize = HeapCompact(hHeaps[i], IGNORE);
printf("Largest free block in heap %lu is %lu bytes.\n", i, cbSize);
PROCESS_HEAP_ENTRY phe;
phe.lpData = NULL;
DWORD dwTotalBlocks = 0;
while(HeapWalk(hHeaps[i], &phe))
{
printf("Found a block at address [%p]", phe.lpData);
printf(" Block size: %lu", phe.cbData);
for(DWORD i = 0; i < 20; i++)
if (phe.lpData == lpDummyBlocks[i])
{
printf(" This is DummyBlock%lu", i);
break;
}
dwTotalBlocks++;
printf("\n");
}
printf("Total blocks: %lu. \n\n", dwTotalBlocks);
}
for(DWORD i = 0; i < 20; i++)
free(lpDummyBlocks[i]);
return 0;
}
UPDATE
I played with the second heap a little bit more and noticed a strange behaviour. I am not sure if my GetHeapInfo function is correct but i think thats what MSDN said about the .cbData field of the PROCESS_HEAP_ENTRY structure.
struct tagHEAP_INFO
{
DWORD dwBlockCount;
DWORD dwTotalOverhead;
DWORD dwTotalBlockSize;
};
typedef struct tagHEAP_INFO HEAP_INFO, *LPHEAP_INFO;
WINBOOL APIENTRY GetHeapInfo(HANDLE hHeap, LPHEAP_INFO lpHeapInfo)
{
// error checking ...
// ...
// return FALSE;
PROCESS_HEAP_ENTRY phe;
phe.lpData = NULL;
lpHeapInfo->dwBlockCount = 0;
lpHeapInfo->dwTotalBlockSize = 0;
lpHeapInfo->dwTotalOverhead = 0;
while(HeapWalk(hHeap, &phe))
{
lpHeapInfo->dwBlockCount++;
lpHeapInfo->dwTotalBlockSize += phe.cbData;
lpHeapInfo->dwTotalOverhead += phe.cbOverhead;
}
DWORD dwLastError = GetLastError();
if (dwLastError == ERROR_NO_MORE_ITEMS)
return TRUE;
Beep(1000, 1000); // well, its easier this way :)
return FALSE;
}
With this function i counted the total bytes allocated at the beginning of the process, after allocating some blocks and after freeing them. This is the strange result (and i checked it and its not an overflow):
Adding to this, i made the same test with the default process heap. I got strange results here too, this time also the block count did not match (and i checked that all the blocks were allocated).
Am i misinterpreting this? I am using HeapWalk the way this example (enumerating a heap) is showing. This time i only used HeapAlloc for allocation.


