📄 heap.c
字号:
}
// release CS
LeaveCriticalSection(&php->cs);
// zero memory if requested
if (pRet && (dwFlags & HEAP_ZERO_MEMORY)) {
#if HEAP_SENTINELS
memset ((char*)pRet + cbOrigSize, 0, dwBytes - cbOrigSize);
#else
memset ((char*)pit + cbOrigSize, 0, cbSeek - cbOrigSize);
#endif
}
}
} else {
if (cbItem > (int) (cbSeek + sizeof(item) + HEAP_SENTINELS)) {
pitem pitNew = (pitem)((char*)pit + cbSeek);
cbItem -= cbSeek;
pitNew->size = -cbItem;
pitNew->prgn = prgn;
DEBUGMSG(DBGFIXHP, (L" 11:HeapReAlloc pitNew = %8.8lx (%8.8lx)\n", pitNew, pitNew->size));
EnterCriticalSection (&php->cs);
pit->size = cbSeek; // Shrink the orginal block
// we seems to do better without merging it here
//MergeFreeItems (prgn, pitNew);
if (prgn->cbMaxFree < cbItem) {
// the state of estimate does not change because of this
prgn->cbMaxFree = cbItem | (prgn->cbMaxFree & REGION_MAX_IS_ESTIMATE);
}
#if HEAP_SENTINELS
SetFreeSentinels (pitNew);
SetSentinels(pit, dwBytes);
#endif
LeaveCriticalSection (&php->cs);
DEBUGMSG(DBGFIXHP, (L" 12:HeapReAlloc pit = %8.8lx (%8.8lx)\n", pit, pit->size));
}
#if HEAP_SENTINELS
else {
// If the size is changing, we must update the sentinels and
// possibly zero out a few bytes.
if ((dwSize = pit->cbTrueSize) != dwBytes) {
SetSentinels(pit, dwBytes);
if (dwSize < dwBytes && (dwFlags & HEAP_ZERO_MEMORY))
memset((char*)(pit+1)+dwSize, 0, dwBytes-dwSize);
}
}
#endif
pRet = pit+1;
}
}
if (pit && !pRet && !(dwFlags & HEAP_REALLOC_IN_PLACE_ONLY)) {
if ((pRet = Int_HeapAlloc(hHeap, dwFlags & HEAP_GENERATE_EXCEPTIONS, dwBytes)) != 0) {
#if HEAP_SENTINELS
cbItem = pit->cbTrueSize;
memcpy(pRet, pit+1, cbItem);
if (dwFlags & HEAP_ZERO_MEMORY)
memset((char*)pRet+cbItem, 0, dwBytes - cbItem);
#else
cbItem = (pit->size & ~1) - sizeof(item);
memcpy(pRet, pit+1, cbItem);
if (dwFlags & HEAP_ZERO_MEMORY) {
// Zero out tail of data that wasn't copied.
int cbNew = (((pitem)pRet)[-1].size & ~1) - sizeof(item);
if (cbNew > cbItem)
memset((char*)pRet+cbItem, 0, cbNew - cbItem);
}
#endif
// The new block has been allocated and the contents of the old block have been
// copied to it. Now free the old block.
Int_HeapFree(hHeap, dwFlags & HEAP_GENERATE_EXCEPTIONS, lpMem);
}
} else if (!pRet)
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
DEBUGMSG(DBGFIXHP, (L" 9:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx ==> %8.8lx\r\n", hHeap,dwFlags,lpMem,dwBytes,pRet));
DEBUGCHK(!pRet || ((Int_HeapSize(hHeap,0,pRet) >= dwBytes) && (Int_HeapSize(hHeap,0,pRet) != (DWORD)-1)));
if (IsCeLogStatus(CELOGSTATUS_ENABLED_GENERAL)) {
CELOG_HeapRealloc(hHeap, dwFlags, dwBytes, (DWORD)lpMem, (DWORD)pRet);
}
return bZeroPtr ? (LPVOID)ZeroPtr(pRet) : pRet;
}
/*
@doc BOTH EXTERNAL
@func LPVOID | HeapAlloc | Allocates a block of memory from specified heap
@parm HANDLE | hHeap | Handle returned from CreateHeap()
@parm DWORD | dwFlags | HEAP_NO_SERIALIZE and HEAP_ZERO_MEM supported
@parm DWORD | dwBytes | Desired size of block
*/
LPVOID WINAPI HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes)
{
return ptrHeapAlloc(hHeap, dwFlags, dwBytes);
}
LPVOID WINAPI HeapAllocTrace(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes, DWORD dwLineNum, PCHAR szFilename)
{
// If it's redirected then call it, otherwise ignore the trace params and call HeapAlloc
if (ptrHeapAllocTrace) {
return ptrHeapAllocTrace(hHeap, dwFlags, dwBytes, dwLineNum, szFilename);
} else {
return ptrHeapAlloc(hHeap, dwFlags, dwBytes);
}
}
LPVOID WINAPI Int_HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes)
{
pheap php = (pheap) hHeap;
pregion prgn;
LPVOID lpSlot;
pitem pitRet;
//
// check parameters
//
lpSlot = (char*)php - (DWORD)ZeroPtr(php);
if ((dwFlags & ~(HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY)) || !hHeap || php->dwSig != HEAPSIG) {
DEBUGMSG(DBGFIXHP, (L" HeapAlloc %8.8lx %8.8lx %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap,dwFlags,dwBytes,0));
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (dwBytes > HEAP_MAX_ALLOC) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
if (!php->cbMaximum && (dwBytes+sizeof(vaitem) >= CE_VALLOC_MINSIZE)) {
// size requested is greated that VA threshold, use VirtualAlloc
pitRet = DoLargeHeapAlloc (lpSlot, php, dwBytes);
#ifdef HEAP_STATISTICS
InterlockedIncrement (&lNumAllocs[BUCKET_VIRTUAL]);
#endif
} else {
// ordinary HeapAlloc
int cbSeek = ALIGNSIZE(dwBytes + sizeof(item) + HEAP_SENTINELS);
#ifdef HEAP_STATISTICS
int idx = (cbSeek >> 4) - 1; // slot number
if (idx > BUCKET_LARGE) // idx BUCKET_LARGE is for items >= 1K in size
idx = BUCKET_LARGE;
InterlockedIncrement (&lNumAllocs[idx]);
#endif
// grab CS if serialized.
EnterCriticalSection (&php->cs);
// try allocating in existing regions
if (!(pitRet = FindFreeItem (lpSlot, php, cbSeek, &prgn)) // try existing region first
&& !php->cbMaximum // can we grow?
&& (prgn = CreateNewRegion (lpSlot, php, cbSeek))) { // enough memory to create a new region?
// if we can't find it in existing regions, try to create new regions
pitRet = FIRSTITEM (prgn);
}
if (pitRet) {
// carve the size requested from the free item found
pitRet = CarveItem (prgn, pitRet, cbSeek, dwBytes, NULL);
#ifdef MEMTRACKING
AddTrackedItem(php->wMemType, pitRet+1, TCB, GetCurrentProcessId(), pitRet->size, 0, 0);
#endif
}
LeaveCriticalSection (&php->cs);
// Zero the memory block if requested.
if ((dwFlags & HEAP_ZERO_MEMORY) && pitRet) {
#if HEAP_SENTINELS
memset(pitRet+1, 0, pitRet->cbTrueSize);
#else
memset(pitRet+1, 0, pitRet->size - sizeof(item));
#endif
}
}
if (pitRet)
++pitRet; // return the pointer AFTER the item header.
if (IsCeLogStatus(CELOGSTATUS_ENABLED_GENERAL)) {
CELOG_HeapAlloc(hHeap, dwFlags, dwBytes, (DWORD)pitRet);
}
DEBUGMSG(DBGFIXHP, (L" HeapAlloc %8.8lx %8.8lx %8.8lx ==> %8.8lx\r\n", hHeap, dwFlags, dwBytes, pitRet));
return lpSlot!=PSlot ? pitRet : (pitem)ZeroPtr(pitRet);
}
/*
@doc BOTH EXTERNAL
@func BOOL | HeapFree | Frees a HeapAlloc'ed block of memory
@parm HANDLE | hHeap | Handle returned from CreateHeap()
@parm DWORD | dwFlags | HEAP_NO_SERIALIZE only
@parm LPVOID | lpMem | Pointer to memory block
*/
BOOL WINAPI HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
{
return ptrHeapFree(hHeap, dwFlags, lpMem);
}
BOOL WINAPI Int_HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
{
pheap php;
pitem pit;
pregion prgn;
int size;
BOOL bRet = FALSE;
php = (pheap)hHeap;
if ((dwFlags & ~HEAP_NO_SERIALIZE) || !hHeap || php->dwSig != HEAPSIG || (DWORD)lpMem < 0x10000) {
DEBUGMSG(DBGFIXHP, (L" HeapFree %8.8lx %8.8lx %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap,dwFlags,lpMem,0));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (IsCeLogStatus(CELOGSTATUS_ENABLED_GENERAL)) {
CELOG_HeapFree(hHeap, dwFlags, (DWORD)lpMem);
}
pit = (pitem)((char*)lpMem - sizeof(item));
if (!((DWORD) pit >> VA_SECTION)) {
// pit belongs to this heap, make sure it's slotized
pit = (pitem) ((char *) pit + (DWORD)php - (DWORD)ZeroPtr(php));
}
size = pit->size;
if (size > 0) {
#if HEAP_SENTINELS
CheckSentinels(pit, TRUE);
#endif
if (size & 1) {
if (php == pit->php) {
// VirtualAlloc'ed item. Locate the vaitem structure for the block.
// Remove the item from the heap's list, release the critical section (if serialized)
// and then free the vitual memory block.
pvaitem pva = (pvaitem)((char*)lpMem - sizeof(vaitem));
DWORD dwData = pva->dwData;
EnterCriticalSection(&php->cs);
if (pva->pvaBak == NULL) {
// This item is the head of the list.
DEBUGCHK(php->pvaList == pva || (pvaitem)ZeroPtr(php->pvaList) == pva);
if ((php->pvaList = pva->pvaFwd) != NULL)
php->pvaList->pvaBak = NULL;
} else {
// Item in the middle or end of the list.
DEBUGCHK(php->pvaList != pva);
if ((pva->pvaBak->pvaFwd = pva->pvaFwd) != NULL)
pva->pvaFwd->pvaBak = pva->pvaBak;
}
LeaveCriticalSection(&php->cs);
lpMem = (LPVOID)((DWORD)lpMem & -PAGE_SIZE);
php->pfnFree (lpMem, size, MEM_DECOMMIT, dwData);
php->pfnFree (lpMem, 0, MEM_RELEASE, dwData);
bRet = TRUE;
}
} else if ((prgn = pit->prgn)->phpOwner == php) {
EnterCriticalSection (&php->cs);
pit->size = -size;
#if HEAP_SENTINELS
// fill the item with 0xcc
memset (pit+1, 0xcc, size - sizeof(item));
#endif
MergeFreeItems (prgn, pit);
if (prgn->cbMaxFree < -pit->size)
prgn->cbMaxFree = -pit->size;
prgn->cbMaxFree |= REGION_MAX_IS_ESTIMATE;
LeaveCriticalSection (&php->cs);
bRet = TRUE;
}
}
#ifdef MEMTRACKING
if (bRet)
DeleteTrackedItem(((pheap)hHeap)->dwMemType, lpMem);
#endif
DEBUGMSG(DBGFIXHP, (L" HeapFree %8.8lx %8.8lx %8.8lx ==> %8.8lx\r\n",hHeap,dwFlags,lpMem,bRet));
return bRet;
}
/*
@doc BOTH EXTERNAL
@func DWORD | HeapSize | Returns the size of a HeapAlloc'ed block of memory
@parm HANDLE | hHeap | Heap from which memory was alloc'ed
@parm DWORD | dwFlags | can be HEAP_NO_SERIALIZE
@parm LPVOID | lpMem | handle of local memory object to get size of
@comm Follows the Win32 reference description without restrictions
or modifications.
*/
DWORD WINAPI HeapSize(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
{
return ptrHeapSize(hHeap, dwFlags, lpMem);
}
DWORD WINAPI Int_HeapSize(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
{
UINT cbRet;
pitem pit;
pheap php;
if ((dwFlags & ~HEAP_NO_SERIALIZE) || !hHeap || ((pheap)hHeap)->dwSig != HEAPSIG || (DWORD)lpMem < 0x10000) {
DEBUGMSG(DBGFIXHP, (L" HeapSize %8.8lx: Invalid parameter\r\n"));
SetLastError(ERROR_INVALID_PARAMETER);
return (DWORD)-1;
}
pit = (pitem)((char*)lpMem - sizeof(item));
php = (pit->size&1) ? pit->php : pit->prgn->phpOwner;
if (php == (pheap)hHeap && pit->size > 0) {
#if HEAP_SENTINELS
CheckSentinels(pit, TRUE);
cbRet = pit->cbTrueSize;
#else
cbRet = (pit->size & -2) - sizeof(item);
#endif
} else
cbRet = (DWORD)-1;
DEBUGMSG(DBGFIXHP, (L" HeapSize %8.8lx ==> %8.8lx\r\n", lpMem, cbRet));
return cbRet;
}
/*
@doc BOTH EXTERNAL
@func BOOL | HeapDestroy | Destroys a heap and releases its memory
@parm HANDLE | hHeap | Handle returned from CreateHeap()
*/
BOOL WINAPI HeapDestroy(HANDLE hHeap)
{
return ptrHeapDestroy(hHeap);
}
BOOL WINAPI Int_HeapDestroy(HANDLE hHeap)
{
pheap php = (pheap)hHeap;
pheap *pphp;
pregion prgn;
pvaitem pva;
PFN_FreeHeapMem pfnFree;
DWORD dwRgnData;
if (!hHeap || php->dwSig != HEAPSIG || (php->flOptions & HEAP_IS_PROC_HEAP)) {
SetLastError(ERROR_INVALID_PARAMETER);
DEBUGMSG(DBGFIXHP, (L" HeapDestroy %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap, 0));
return FALSE;
}
if (IsCeLogStatus(CELOGSTATUS_ENABLED_GENERAL)) {
CELOG_HeapDestroy(hHeap);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -