📄 heap.c
字号:
// Remove the heap from the list of heaps for the current process.
EnterCriticalSection(&csHeapList);
for (pphp = &phpListAll ; *pphp != 0 ; pphp = &(*pphp)->phpNext) {
if (*pphp == php) {
*pphp = php->phpNext;
break;
}
}
LeaveCriticalSection(&csHeapList);
// Free all VirtualAlloc'ed heap items.
while ((pva = php->pvaList) != 0)
HeapFree(hHeap, 0, pva+1);
#ifdef MEMTRACKING
// If memory tracking is enabled, scan the heap and delete the tracking info.
prgn = &php->rgn;
do {
pitem pit = FIRSTITEM(prgn);
do {
if (pit->size > 0) {
if (pit->prgn == prgn)
DeleteTrackedItem(php->dwMemType, pit+1);
else
DEBUGCHK(pit->prgn == 0);
pit = (pitem)((char*)pit + pit->size);
} else
pit = (pitem)((char*)pit - pit->size);
} while (pit->size);
} while ((prgn = prgn->prgnNext) != 0);
#endif
// Free all additional regions added to the heap.
while ((prgn = php->rgn.prgnNext) != 0)
DeleteRegion(prgn);
DeleteCriticalSection(&php->cs);
#ifdef MEMTRACKING
DeleteTrackedItem(dwHeapMemType, hHeap);
#endif
pfnFree = php->pfnFree;
dwRgnData = php->rgn.dwRgnData;
pfnFree (php, (php->cbMaximum ? php->cbMaximum : CE_FIXED_HEAP_MAXSIZE), MEM_DECOMMIT, dwRgnData);
pfnFree (php, 0, MEM_RELEASE, dwRgnData);
DEBUGMSG(DBGFIXHP, (L" HeapDestroy %8.8lx ==> %8.8lx\r\n", hHeap, 1));
return TRUE;
}
UINT CompactRegion(pregion prgn)
{
pitem pit, pitNext;
pitem pitPrev;
int cbMaxFree = 0;
int cbItem;
DEBUGMSG(DBGHEAP2, (L" CompactRegion: 0x%08X\r\n", prgn));
pit = pitPrev = FIRSTITEM(prgn);
do {
// Skip over allocated blocks (and holes)
while ((cbItem = pit->size) > 0) {
pitPrev = pit;
pit = (pitem)((char*)pit + cbItem);
}
// Scan a possible run of free blocks and merge them.
pitNext = MergeFreeItems (prgn, pit);
cbItem = -pit->size;
// if we're on the last block, free the extra pages
if ((cbItem >= PAGE_SIZE) && !pitNext->size) {
// move back the end marker and free the extra pages
int cbHead = PAGE_SIZE - ((DWORD)pit & PageMask) - sizeof (item);
int cbEx = ((cbItem - cbHead) & ~PageMask);
pitem pitEnd = (pitem)((char*)pit + cbHead); // (pit) = ptr to tail
DEBUGCHK (cbEx > 0);
prgn->pitLast = pit;
pit->size = -cbHead;
pitEnd->size = 0; // NOTE: this assignment must come after chaning pit->size because they might overlap
pitEnd->cbTail = pitNext->cbTail + cbEx;
#if HEAP_SENTINELS
pitEnd->dwSig = TAILSIG;
#endif
DEBUGCHK (((DWORD)(pitEnd+1) & PageMask) == 0);
DEBUGMSG(DBGHEAP2, (L" CompactRegion: Combining tail item to make free pages 0x%08X [%06x]\r\n", pit, cbHead));
prgn->phpOwner->pfnFree (pitEnd+1, cbEx, MEM_DECOMMIT, prgn->dwRgnData);
cbItem = cbHead;
pitNext = pitEnd;
}
if (cbItem > cbMaxFree)
cbMaxFree = cbItem;
pit = pitNext;
} while (pit->size);
prgn->cbMaxFree = cbMaxFree;
DEBUGMSG(DBGHEAP2, (L" CompactRegion: 0x%08X MaxFree=0x%07X pitFree=0x%08X\r\n", prgn, cbMaxFree, prgn->pitFree));
return cbMaxFree;
}
UINT WINAPI HeapCompact(HANDLE hHeap, DWORD dwFlags)
{
pheap php;
pregion prgn;
INT cbMaxFree;
if (dwFlags & ~HEAP_NO_SERIALIZE) {
DEBUGMSG(DBGFIXHP, (L" HeapCompact %8.8lx %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap, dwFlags, 0));
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (!hHeap) {
SetLastError(ERROR_INVALID_PARAMETER);
DEBUGMSG(DBGFIXHP, (L" HeapCompact %8.8lx %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap, dwFlags, 0));
return 0;
}
php = (pheap)hHeap;
EnterCriticalSection(&php->cs);
cbMaxFree = 0;
for (prgn = &php->rgn ; prgn ; prgn = prgn->prgnNext) {
int cbFree = CompactRegion(prgn);
if (cbFree > cbMaxFree)
cbMaxFree = cbFree;
}
LeaveCriticalSection(&php->cs);
DEBUGMSG(DBGFIXHP, (L" HeapCompact %8.8lx %8.8lx ==> %8.8lx\r\n", hHeap, dwFlags, cbMaxFree));
return cbMaxFree;
}
void CompactAllHeaps(void)
{
pheap php;
DEBUGMSG(1, (L"CompactAllHeaps: starting\r\n"));
if (!fFullyCompacted) {
fFullyCompacted = TRUE;
EnterCriticalSection(&csHeapList);
for (php = phpListAll ; php ; php = php->phpNext)
HeapCompact((HANDLE)php, 0);
LeaveCriticalSection(&csHeapList);
}
DEBUGMSG(1, (L"CompactAllHeaps: done\r\n"));
}
/*
@doc BOTH EXTERNAL
@func HANDLE | GetProcessHeap | Obtains a handle to the heap of the
calling process
*/
HANDLE WINAPI GetProcessHeap(VOID)
{
return hProcessHeap;
}
BOOL WINAPI HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
{
pitem pitSeek, pit;
pheap php = (pheap)hHeap;
pregion prgn;
BOOL bRet = FALSE;
int cbFree;
if ((dwFlags & ~HEAP_NO_SERIALIZE) || !hHeap || php->dwSig != HEAPSIG
|| (lpMem && lpMem < (LPCVOID)0x10000)) {
DEBUGMSG(DBGFIXHP, (L" HeapValidate %8.8lx: Invalid parameter\r\n", hHeap));
return FALSE;
}
try {
if (lpMem) {
if (((DWORD)hHeap>>SECTION_SHIFT) != ((DWORD)lpMem>>SECTION_SHIFT)) {
// The ptr has been unmapped by someone or it doesn't belong to this heap.
if ((DWORD)lpMem>>SECTION_SHIFT) {
DEBUGMSG(DBGFIXHP, (L" HeapValidate %8.8lx %8.8lx %8.8lx ==> %8.8lx\r\n", hHeap,dwFlags,lpMem,0));
return FALSE;
}
// Restore the "slot mapping" bits to the pointer.
lpMem = (LPVOID)((DWORD)lpMem | ((DWORD)hHeap & -(1<<SECTION_SHIFT)));
}
pitSeek = (pitem)((char*)lpMem - sizeof(item));
if (pitSeek->size > 0) {
#if HEAP_SENTINELS
CheckSentinels(pitSeek, TRUE);
#endif
if (pitSeek->size & 1) {
// VirtualAlloc'ed item. Validate that the item pointer falls correctly within a
// 64K aligned virtual memory block and that the heap owner information in the
// item is correct.
pvaitem pva;
pva = (pvaitem)(((DWORD)lpMem&0xFFFF0000) + (ALIGNSIZE(sizeof(vaitem)) - sizeof(vaitem)));
if (pitSeek != &pva->it || pitSeek->php != php)
goto done;
// Make sure that the true size of the block is a multiple of a page.
if (((pitSeek->size-1 + ALIGNSIZE(sizeof(vaitem)) - sizeof(item)) & PageMask) != 0)
goto done;
bRet = TRUE;
goto done;
} else {
// Ordinary item. Validate that the region pointer points at a region
// that is part of the given heap and that the size of the block is a
// multiple of the heap alignment value.
prgn = pitSeek->prgn;
if (prgn->phpOwner != php || (pitSeek->size & ALIGNBYTES-1) != 0)
goto done;
}
}
} else {
pitSeek = NULL;
prgn = &php->rgn;
}
// Walk the regions of the heap validating the linkages. If the validation is for
// a specific block then only the region containing that block will be scanned.
EnterCriticalSection(&php->cs);
do {
pit = FIRSTITEM(prgn);
cbFree = 0;
do {
if (pit->size > 0) {
// Allocated block or hole. Check if this is the item we're looking for and
// quit if so. Otherwise, validate the block and continue scanning.
if (pit == pitSeek) {
bRet = TRUE;
goto done;
}
if (pit->size & ALIGNBYTES-1) {
// Bogus block size. Quit scanning now.
DEBUGMSG(1, (L" HeapValidate: %08x busy item=%08x invalid block size: %08x\r\n",
php, pit, pit->size));
goto done;
}
if (pit->prgn && pit->prgn != prgn) {
// Invalid region pointer. Quit scanning now.
DEBUGMSG(1, (L" HeapValidate: %08x busy item=%08x invalid region: %08x SHDB %08x\r\n",
php, pit, pit->prgn, prgn));
goto done;
}
#if HEAP_SENTINELS
if (!CheckSentinels(pit, FALSE))
goto done;
#endif
// Advance to the next item.
pit = (pitem)((char*)pit + pit->size);
} else if (pit->size < 0) {
// Free item. Validate the item size.
if (pit->size & ALIGNBYTES-1) {
// Bogus block size. Quit scanning now.
DEBUGMSG(1, (L" HeapValidate: %08x free item=%08x invalid block size: %08x\r\n",
php, pit, -pit->size));
goto done;
}
if (pit->prgn != prgn) {
// Invalid region pointer. Quit scanning now.
DEBUGMSG(1, (L" HeapValidate: %08x free item=%08x invalid region: %08x SHDB %08x\r\n",
php, pit, pit->prgn, prgn));
goto done;
}
#if HEAP_SENTINELS
if (!CheckFreeSentinels(pit, FALSE))
goto done;
#endif
// Advance to the next item.
cbFree -= pit->size;
pit = (pitem)((char*)pit - pit->size);
}
} while (pit->size != 0);
if (pitSeek) {
// The item wasn't found in a scan of the heap region.
DEBUGMSG(1, (L" HeapValidate: %08x item=%08x not found!\r\n", php, pitSeek));
goto done;
}
}while ((prgn = prgn->prgnNext) != 0);
bRet = TRUE;
done: ;
} except (EXCEPTION_EXECUTE_HANDLER) {
bRet = FALSE;
}
LeaveCriticalSection(&php->cs);
#ifdef DEBUG
if (!bRet) {
_HeapDump(hHeap);
DEBUGCHK(0);
}
#endif
DEBUGMSG(DBGFIXHP, (L" HeapValidate %8.8lx %8.8lx %8.8lx ==> %8.8lx\r\n", hHeap,dwFlags,lpMem,1));
return bRet;
}
#ifdef DEBUG
UINT WINAPI _HeapDump(HLOCAL hHeap) {
UINT retval = 1;
pheap php = (pheap) hHeap;
pregion prgn;
pitem pit;
pvaitem pva;
try {
if (php->dwSig != HEAPSIG) {
DEBUGMSG(1, (TEXT("_HeapDump: %8.8lx is not a valid heap! Signature=%8.8lx\r\n"), php, php->dwSig));
goto done;
}
EnterCriticalSection(&php->cs);
DEBUGMSG(1, (TEXT("_HeapDump: %8.8lx\r\n"), php));
DEBUGMSG(1, (TEXT(" flOptions: 0x%08X cbMaximum: 0x%08X\r\n"), php->flOptions, php->cbMaximum));
// Walk the region list dumping all of the items in the regions.
prgn = &php->rgn;
do {
if (prgn->phpOwner != php) {
DEBUGMSG(1, (TEXT("_HeapDump: region %8.8lx has incorrect owner (%.8.8lx)\r\n"), prgn, prgn->phpOwner));
goto done;
}
DEBUGMSG(1, (TEXT(" Region: 0x%08X cbMaxFree: 0x%08X\r\n"), prgn, prgn->cbMaxFree));
DEBUGMSG(1, (TEXT(" pitFree: 0x%08X pitLast: 0x%08X\r\n"), prgn->pitFree, prgn->pitLast));
pit = FIRSTITEM(prgn);
do {
if (pit->size > 0) {
if (pit->prgn == NULL) {
// This is a hole.
DEBUGMSG(1, (TEXT(" Hole: 0x%08X size: 0x%08X\r\n"), pit, pit->size));
#if HEAP_SENTINELS
if (pit->dwSig != HOLESIG) {
DEBUGMSG(1, (TEXT("Invalid hole signature: 0x%08X SHDB 0x%08X\r\n"), pit->dwSig, HOLESIG));
goto done;
}
#endif
} else {
// This is an allocated item.
DEBUGMSG(1, (TEXT(" Item: 0x%08X size: 0x%08X\r\n"), pit, pit->size));
#if HEAP_SENTINELS
if (!CheckSentinels(pit, FALSE))
goto done;
#endif
}
pit = (pitem)((char*)pit + pit->size);
} else {
// This is a free item.
DEBUGMSG(1, (TEXT(" Free: 0x%08X size: 0x%08X\r\n"), pit, -pit->size));
#if HEAP_SENTINELS
if (!CheckFreeSentinels(pit, FALSE))
goto done;
#endif
pit = (pitem)((char*)pit - pit->size);
}
} while (pit->size != 0);
DEBUGM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -