1200 lines
27 KiB
C++
1200 lines
27 KiB
C++
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
memalloc.cxx
|
||
|
||
Abstract:
|
||
|
||
Debug-only memory allocation routines
|
||
|
||
Contents:
|
||
InetInitializeDebugMemoryPackage
|
||
InetTerminateDebugMemoryPackage
|
||
InetAllocateMemory
|
||
InetReallocateMemory
|
||
(InetIsBlockMoveable)
|
||
InetFreeMemory
|
||
(InetCheckBlockConsistency)
|
||
InetLockMemory
|
||
InetUnlockMemory
|
||
InetMemorySize
|
||
InetCheckDebugMemoryFreed
|
||
(x86SleazeCallersAddress)
|
||
|
||
Author:
|
||
|
||
Richard L Firth (rfirth) 02-Feb-1995
|
||
|
||
Environment:
|
||
|
||
Win32 user mode
|
||
|
||
Revision History:
|
||
|
||
02-Feb-1995
|
||
Created
|
||
|
||
--*/
|
||
|
||
#include <wininetp.h>
|
||
#include "rprintf.h"
|
||
|
||
#if INET_DEBUG
|
||
|
||
//
|
||
// manifests
|
||
//
|
||
|
||
#define HEADER_SIGNATURE 0x414d454d // 'MEMA'
|
||
#define FOOTER_SIGNATURE 0x434f4c4c // 'LLOC'
|
||
#define DWORD_FILL 0xa9a9a9a9
|
||
#define BYTE_FILL 0xa9
|
||
#define BYTE_FILL_EXTRA 0xcb
|
||
#define GUARD_DWORD_FILL 0xcccd21f4
|
||
#define DWORD_FREE_FILL 0xb7b7b7b7
|
||
#define BYTE_FREE_FILL 0xb7
|
||
|
||
//
|
||
// private types
|
||
//
|
||
|
||
typedef struct {
|
||
|
||
//
|
||
// hMoveable - local handle of moveable memory that this tag links
|
||
//
|
||
|
||
HLOCAL hMoveable;
|
||
|
||
} DEBUG_MOVEABLE_TAG, *LPDEBUG_MOVEABLE_TAG;
|
||
|
||
typedef struct {
|
||
|
||
//
|
||
// List - maintains a list of allocated blocks
|
||
//
|
||
|
||
LIST_ENTRY List;
|
||
|
||
//
|
||
// BlockLength - the size of this block, *including* all headers, footers
|
||
// and padding
|
||
//
|
||
|
||
UINT BlockLength;
|
||
|
||
//
|
||
// RealLength - the original caller request
|
||
//
|
||
|
||
UINT RealLength;
|
||
|
||
//
|
||
// Signature - just used as a sanity check to ensure that what we are
|
||
// dealing with is actually a block we allocated
|
||
//
|
||
|
||
DWORD Signature;
|
||
|
||
//
|
||
// LockCount - if this is moveable memory, keeps the number of times this
|
||
// block has been locked
|
||
//
|
||
|
||
LONG LockCount;
|
||
|
||
//
|
||
// Flags - what type of memory this is, etc.
|
||
//
|
||
|
||
DWORD Flags;
|
||
|
||
//
|
||
// LastAccessOperation - the operation caller at LastAccessReturnAddress
|
||
// performed
|
||
//
|
||
|
||
MEMALLOC_ACTION LastAccessOperation;
|
||
|
||
//
|
||
// LastAccessReturnAddress - caller of last function to perform memory
|
||
// function operation (alloc, lock, realloc, unlock, etc) on this block
|
||
//
|
||
|
||
LPVOID LastAccessReturnAddress[2];
|
||
|
||
//
|
||
// CreatorReturnAddress - return EIP (x86-only) of caller of allocator
|
||
// and caller of caller
|
||
//
|
||
|
||
LPVOID CreatorReturnAddress[2];
|
||
|
||
//
|
||
// Tag - if this is moveable memory, we can't add this block to the allocated
|
||
// block list, we have to allocate a DEBUG_MOVEABLE_TAG, link that and point
|
||
// to it from here
|
||
//
|
||
|
||
LPDEBUG_MOVEABLE_TAG Tag;
|
||
|
||
//
|
||
// Guard - just a sentinel to find out if the caller is writing before the
|
||
// start of this block
|
||
//
|
||
|
||
DWORD Guard[4];
|
||
|
||
//
|
||
// sizeof(MEMORY_SIGNATURE) currently 17 DWORDs
|
||
//
|
||
|
||
} DEBUG_MEMORY_HEADER, *LPDEBUG_MEMORY_HEADER;
|
||
|
||
typedef struct {
|
||
|
||
//
|
||
// Guard - allows us to determine if the end of allocated memory was
|
||
// overwritten
|
||
//
|
||
|
||
DWORD Guard[4];
|
||
|
||
//
|
||
// Signature - should be the footer signature
|
||
//
|
||
|
||
DWORD Signature;
|
||
|
||
//
|
||
// BlockLength - should be the same as the header
|
||
//
|
||
|
||
DWORD BlockLength;
|
||
|
||
//
|
||
// Guard2 - to make sure the end of the block is coherent
|
||
//
|
||
|
||
DWORD Guard2[2];
|
||
|
||
//
|
||
// sizeof(DEBUG_MEMORY_FOOTER) currently 8 DWORDs
|
||
//
|
||
|
||
} DEBUG_MEMORY_FOOTER, *LPDEBUG_MEMORY_FOOTER;
|
||
|
||
//
|
||
// data
|
||
//
|
||
|
||
LONG ActualMemoryAllocated = 0;
|
||
LONG BlockLengthAllocated = 0;
|
||
LONG RealLengthAllocated = 0;
|
||
DWORD MemoryAllocations = 0;
|
||
DWORD MemoryFrees = 0;
|
||
SERIALIZED_LIST AllocatedBlockList;
|
||
|
||
//
|
||
// macros
|
||
//
|
||
|
||
#if defined(i386)
|
||
|
||
#define GET_CALLERS_ADDRESS(p, pp) x86SleazeCallersAddress(p, pp)
|
||
|
||
#else
|
||
|
||
#define GET_CALLERS_ADDRESS(p, pp)
|
||
|
||
#endif // defined(i386)
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
PRIVATE
|
||
BOOL
|
||
InetIsBlockMoveable(
|
||
IN HLOCAL hLocal
|
||
);
|
||
|
||
PRIVATE
|
||
VOID
|
||
InetCheckBlockConsistency(
|
||
IN LPVOID lpMemory
|
||
);
|
||
|
||
PRIVATE
|
||
VOID
|
||
x86SleazeCallersAddress(
|
||
LPVOID* pCaller,
|
||
LPVOID* pCallersCaller
|
||
);
|
||
|
||
//
|
||
// functions
|
||
//
|
||
|
||
|
||
VOID
|
||
InetInitializeDebugMemoryPackage(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Just initializes data items in this module
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
static BOOL MemoryPackageInitialized = FALSE;
|
||
|
||
if (!MemoryPackageInitialized) {
|
||
InitializeSerializedList(&AllocatedBlockList);
|
||
MemoryPackageInitialized = TRUE;
|
||
} else {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("Memory package already initialized\n"
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
InetTerminateDebugMemoryPackage(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Undoes any resource allocation in InetInitializeDebugMemoryPackage, after
|
||
checking that all memory is freed
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
InetCheckDebugMemoryFreed();
|
||
TerminateSerializedList(&AllocatedBlockList);
|
||
}
|
||
|
||
|
||
HLOCAL
|
||
InetAllocateMemory(
|
||
IN UINT LocalAllocFlags,
|
||
IN UINT NumberOfBytes
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Debug memory allocator: allocates memory with head & tail. Fills memory
|
||
with signature unless otherwise requested. If this is moveable memory
|
||
then the caller must lock the memory with InetLockMemory(), else a pointer
|
||
will be returned to the head of the heap's real start-of-block, and the
|
||
caller will probably nuke the signature contents (but we should discover
|
||
this when the block is freed)
|
||
|
||
Arguments:
|
||
|
||
LocalAllocFlags - flags to be passed on to LocalAlloc
|
||
NumberOfBytes - to allocate for caller
|
||
|
||
Return Value:
|
||
|
||
LPVOID
|
||
Success - pointer to memory after DEBUG_MEMORY_HEADER
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
HLOCAL hLocal;
|
||
UINT blockLength;
|
||
BOOL isMoveable;
|
||
|
||
isMoveable = (LocalAllocFlags & LMEM_MOVEABLE) ? TRUE : FALSE;
|
||
blockLength = ROUND_UP_DWORD(NumberOfBytes)
|
||
+ sizeof(DEBUG_MEMORY_HEADER)
|
||
+ sizeof(DEBUG_MEMORY_FOOTER)
|
||
;
|
||
|
||
//
|
||
// possible problem: if NumberOfBytes + signatures would overflow UINT.
|
||
// Only really problematic on 16-bit platforms
|
||
//
|
||
|
||
if (blockLength < NumberOfBytes) {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("can't allocate %lu bytes: would overflow\n",
|
||
(DWORD)NumberOfBytes
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
return (HLOCAL)NULL;
|
||
}
|
||
|
||
hLocal = LocalAlloc(LocalAllocFlags, blockLength);
|
||
if (hLocal != NULL) {
|
||
|
||
LPVOID lpMem;
|
||
LPDEBUG_MEMORY_HEADER lpHeader;
|
||
DWORD dwFiller;
|
||
BYTE bFiller;
|
||
UINT dwFillLength;
|
||
UINT bFillLength1;
|
||
UINT bFillLength2;
|
||
UINT i;
|
||
LPVOID userPointer;
|
||
|
||
ActualMemoryAllocated += LocalSize(hLocal);
|
||
BlockLengthAllocated += blockLength;
|
||
RealLengthAllocated += NumberOfBytes;
|
||
++MemoryAllocations;
|
||
|
||
if (isMoveable) {
|
||
lpMem = (LPVOID)LocalLock(hLocal);
|
||
if (lpMem == NULL) {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("LocalLock(%x) failed: %d\n",
|
||
hLocal,
|
||
GetLastError()
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
}
|
||
} else {
|
||
lpMem = (LPVOID)hLocal;
|
||
}
|
||
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)lpMem;
|
||
InitializeListHead(&lpHeader->List);
|
||
lpHeader->BlockLength = blockLength;
|
||
lpHeader->RealLength = NumberOfBytes;
|
||
lpHeader->Signature = HEADER_SIGNATURE;
|
||
lpHeader->LockCount = 0;
|
||
lpHeader->Flags = LocalAllocFlags;
|
||
|
||
GET_CALLERS_ADDRESS(&lpHeader->CreatorReturnAddress[0],
|
||
&lpHeader->CreatorReturnAddress[1]
|
||
);
|
||
|
||
lpHeader->LastAccessOperation = MemAllocate;
|
||
|
||
for (i = 0; i < ARRAY_ELEMENTS(lpHeader->Guard); ++i) {
|
||
lpHeader->Guard[i] = GUARD_DWORD_FILL;
|
||
}
|
||
|
||
if (LocalAllocFlags & LMEM_ZEROINIT) {
|
||
dwFiller = 0;
|
||
bFiller = 0;
|
||
} else {
|
||
dwFiller = DWORD_FILL;
|
||
bFiller = BYTE_FILL;
|
||
}
|
||
dwFillLength = NumberOfBytes / sizeof(DWORD);
|
||
bFillLength1 = NumberOfBytes % sizeof(DWORD);
|
||
bFillLength2 = bFillLength1 ? (sizeof(DWORD) - bFillLength1) : 0;
|
||
userPointer = (LPVOID)(lpHeader + 1);
|
||
|
||
LPDWORD lpdwUserPointer = (LPDWORD)userPointer;
|
||
|
||
for (i = 0; i < dwFillLength; ++i) {
|
||
*lpdwUserPointer++ = dwFiller;
|
||
}
|
||
|
||
LPBYTE lpbUserPointer = (LPBYTE)lpdwUserPointer;
|
||
|
||
for (i = 0; i < bFillLength1; ++i) {
|
||
*lpbUserPointer++ = bFiller;
|
||
}
|
||
for (i = 0; i < bFillLength2; ++i) {
|
||
*lpbUserPointer++ = BYTE_FILL_EXTRA;
|
||
}
|
||
|
||
userPointer = (LPVOID)lpbUserPointer;
|
||
|
||
for (i = 0; i < ARRAY_ELEMENTS(((LPDEBUG_MEMORY_FOOTER)userPointer)->Guard); ++i) {
|
||
((LPDEBUG_MEMORY_FOOTER)userPointer)->Guard[i] = GUARD_DWORD_FILL;
|
||
}
|
||
((LPDEBUG_MEMORY_FOOTER)userPointer)->BlockLength = blockLength;
|
||
((LPDEBUG_MEMORY_FOOTER)userPointer)->Signature = FOOTER_SIGNATURE;
|
||
for (i = 0; i < ARRAY_ELEMENTS(((LPDEBUG_MEMORY_FOOTER)userPointer)->Guard2); ++i) {
|
||
((LPDEBUG_MEMORY_FOOTER)userPointer)->Guard2[i] = GUARD_DWORD_FILL;
|
||
}
|
||
|
||
//
|
||
// if this is moveable memory, then we can't link it into the allocated
|
||
// block list because if it moves, the list gets nuked. So we have to
|
||
// allocate a DEBUG_MOVEABLE_TAG, link that and point to it from here
|
||
//
|
||
|
||
if (isMoveable) {
|
||
|
||
LPDEBUG_MOVEABLE_TAG lpTag;
|
||
|
||
lpTag = (LPDEBUG_MOVEABLE_TAG)InetAllocateMemory(LMEM_FIXED, sizeof(DEBUG_MOVEABLE_TAG));
|
||
|
||
INET_ASSERT(lpTag != NULL);
|
||
|
||
lpTag->hMoveable = hLocal;
|
||
lpHeader->Tag = lpTag;
|
||
} else {
|
||
InsertAtHeadOfSerializedList(&AllocatedBlockList, &lpHeader->List);
|
||
}
|
||
|
||
if (isMoveable) {
|
||
if (LocalUnlock(hLocal)) {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("LocalUnlock(%x): memory still locked\n",
|
||
hLocal
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
} else {
|
||
|
||
DWORD err;
|
||
|
||
err = GetLastError();
|
||
if (err != NO_ERROR) {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("LocalUnlock(%x) returns %d\n",
|
||
hLocal,
|
||
err
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
}
|
||
}
|
||
} else {
|
||
hLocal = (HLOCAL)(lpHeader + 1);
|
||
}
|
||
} else {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("failed to allocate %u bytes memory\n",
|
||
blockLength
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
}
|
||
return hLocal;
|
||
}
|
||
|
||
|
||
HLOCAL
|
||
InetReallocateMemory(
|
||
IN HLOCAL hLocal,
|
||
IN UINT Size,
|
||
IN UINT Flags,
|
||
IN BOOL IsMoveable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reallocates previously allocated block
|
||
|
||
BUGBUG - this doesn't handle the more exotic LocalReAlloc stuff, like
|
||
DISCARDABLE memory, allocating/freeing through realloc etc
|
||
|
||
Arguments:
|
||
|
||
hLocal - block to reallocate
|
||
Size - new size
|
||
Flags - new flags
|
||
IsMoveable - TRUE if this is moveable memory. We need this help because
|
||
there is no good way to find out from hLocal whether this
|
||
memory is moveable or fixed
|
||
|
||
Return Value:
|
||
|
||
HLOCAL
|
||
|
||
--*/
|
||
|
||
{
|
||
LPDEBUG_MEMORY_HEADER lpHeader;
|
||
UINT realLength;
|
||
UINT heapLength;
|
||
|
||
//
|
||
// can't handle reallocating down to zero
|
||
//
|
||
|
||
INET_ASSERT(Size != 0);
|
||
|
||
if (IsMoveable) {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)LocalLock(hLocal);
|
||
heapLength = LocalSize(hLocal);
|
||
} else {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)hLocal - 1;
|
||
heapLength = LocalSize((HLOCAL)lpHeader);
|
||
}
|
||
|
||
InetCheckBlockConsistency((LPVOID)lpHeader);
|
||
|
||
if (IsMoveable) {
|
||
LocalUnlock(hLocal);
|
||
}
|
||
|
||
realLength = Size;
|
||
|
||
Size = ROUND_UP_DWORD(Size)
|
||
+ sizeof(DEBUG_MEMORY_HEADER)
|
||
+ sizeof(DEBUG_MEMORY_FOOTER)
|
||
;
|
||
|
||
ActualMemoryAllocated -= heapLength;
|
||
BlockLengthAllocated -= lpHeader->BlockLength;
|
||
RealLengthAllocated -= lpHeader->RealLength;
|
||
|
||
hLocal = LocalReAlloc(hLocal, Size, Flags);
|
||
if (hLocal != NULL) {
|
||
|
||
LPBYTE extraPointer;
|
||
UINT extraLength;
|
||
UINT i;
|
||
LPDEBUG_MEMORY_FOOTER lpFooter;
|
||
|
||
if (IsMoveable) {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)LocalLock(hLocal);
|
||
} else {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)hLocal;
|
||
}
|
||
|
||
lpHeader->BlockLength = Size;
|
||
lpHeader->RealLength = realLength;
|
||
lpHeader->Flags = Flags;
|
||
|
||
GET_CALLERS_ADDRESS(&lpHeader->LastAccessReturnAddress[0],
|
||
&lpHeader->LastAccessReturnAddress[1]
|
||
);
|
||
|
||
lpHeader->LastAccessOperation = MemReallocate;
|
||
|
||
extraPointer = (LPBYTE)(lpHeader + 1) + realLength;
|
||
extraLength = (sizeof(DWORD) - (realLength % sizeof(DWORD)))
|
||
& (sizeof(DWORD) - 1)
|
||
;
|
||
for (i = 0; i < extraLength; ++i) {
|
||
*extraPointer++ = BYTE_FILL_EXTRA;
|
||
}
|
||
lpFooter = (LPDEBUG_MEMORY_FOOTER)((LPBYTE)(lpHeader + 1)
|
||
+ ROUND_UP_DWORD(realLength)
|
||
);
|
||
for (i = 0; i < ARRAY_ELEMENTS(lpFooter->Guard); ++i) {
|
||
lpFooter->Guard[i] = GUARD_DWORD_FILL;
|
||
}
|
||
lpFooter->Signature = FOOTER_SIGNATURE;
|
||
lpFooter->BlockLength = Size;
|
||
for (i = 0; i < ARRAY_ELEMENTS(lpFooter->Guard2); ++i) {
|
||
lpFooter->Guard2[i] = GUARD_DWORD_FILL;
|
||
}
|
||
ActualMemoryAllocated += LocalSize(hLocal);
|
||
BlockLengthAllocated += Size;
|
||
RealLengthAllocated += lpHeader->RealLength;
|
||
if (IsMoveable) {
|
||
LocalUnlock(hLocal);
|
||
} else {
|
||
hLocal = (HLOCAL)(lpHeader + 1);
|
||
}
|
||
} else {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("failed to reallocate %u bytes memory. Last error = %d\n",
|
||
Size,
|
||
GetLastError()
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
}
|
||
return hLocal;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
BOOL
|
||
InetIsBlockMoveable(
|
||
IN HLOCAL hLocal
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines if hLocal is moveable or fixed memory
|
||
|
||
Arguments:
|
||
|
||
hLocal -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
LPDEBUG_MEMORY_HEADER lpHeader;
|
||
BOOL isMoveable;
|
||
|
||
//
|
||
// BUGBUG - this method won't work for Win32s unless it supports SEH. But
|
||
// there is another method...
|
||
//
|
||
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)hLocal - 1;
|
||
__try {
|
||
if (lpHeader->Signature == HEADER_SIGNATURE) {
|
||
isMoveable = FALSE;
|
||
} else {
|
||
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)LocalLock(hLocal);
|
||
|
||
INET_ASSERT(lpHeader != NULL);
|
||
|
||
isMoveable = (BOOL)(lpHeader->Signature == HEADER_SIGNATURE);
|
||
LocalUnlock(hLocal);
|
||
}
|
||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
//
|
||
// yeowww! hLocal must be a handle to moveable memory. Either that, or
|
||
// it is completely bogus
|
||
//
|
||
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)LocalLock(hLocal);
|
||
|
||
INET_ASSERT(lpHeader != NULL);
|
||
|
||
isMoveable = (BOOL)(lpHeader->Signature == HEADER_SIGNATURE);
|
||
LocalUnlock(hLocal);
|
||
}
|
||
return isMoveable;
|
||
}
|
||
|
||
|
||
HLOCAL
|
||
InetFreeMemory(
|
||
IN HLOCAL hLocal,
|
||
IN BOOL IsMoveable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Debug memory deallocator: checks memory is already allocated and that the
|
||
head and tail structures are still ok. Fills freed memory with signature
|
||
|
||
Arguments:
|
||
|
||
hLocal - address/handle of memory to free
|
||
IsMoveable - TRUE if this is moveable memory. We need this help because
|
||
there is no good way to determine if the memory is moveable
|
||
or fixed
|
||
|
||
Return Value:
|
||
|
||
HLOCAL
|
||
Success - NULL
|
||
Failure - hLocal
|
||
|
||
--*/
|
||
|
||
{
|
||
UINT memFlags;
|
||
LPDEBUG_MEMORY_HEADER lpHeader;
|
||
BOOL isMoveable;
|
||
UINT memSize;
|
||
UINT blockLength;
|
||
UINT realLength;
|
||
|
||
if (!IsMoveable) {
|
||
hLocal = (HLOCAL)((LPDEBUG_MEMORY_HEADER)hLocal - 1);
|
||
}
|
||
|
||
memFlags = LocalFlags(hLocal);
|
||
|
||
INET_ASSERT(memFlags != LMEM_INVALID_HANDLE);
|
||
INET_ASSERT((memFlags & LMEM_LOCKCOUNT) == 0);
|
||
|
||
if (IsMoveable) {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)LocalLock(hLocal);
|
||
|
||
INET_ASSERT(lpHeader != NULL);
|
||
|
||
} else {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)hLocal;
|
||
}
|
||
|
||
memSize = LocalSize(hLocal);
|
||
|
||
INET_ASSERT((lpHeader->BlockLength <= memSize)
|
||
&& !(lpHeader->BlockLength & (sizeof(DWORD) - 1))
|
||
&& (lpHeader->RealLength < lpHeader->BlockLength)
|
||
);
|
||
|
||
InetCheckBlockConsistency((LPVOID)lpHeader);
|
||
|
||
//
|
||
// if this is moveable memory then we didn't link it to the allocated
|
||
// block list, but allocated a DEBUG_MOVEABLE_TAG to do the job. We
|
||
// must remove it
|
||
//
|
||
|
||
if (IsMoveable) {
|
||
|
||
LPDEBUG_MOVEABLE_TAG lpTag;
|
||
|
||
lpTag = lpHeader->Tag;
|
||
|
||
INET_ASSERT(lpTag->hMoveable == hLocal);
|
||
|
||
InetFreeMemory(lpTag, FALSE);
|
||
} else {
|
||
RemoveFromSerializedList(&AllocatedBlockList, &lpHeader->List);
|
||
}
|
||
|
||
if (IsMoveable) {
|
||
|
||
BOOL stillLocked;
|
||
|
||
stillLocked = LocalUnlock(hLocal);
|
||
|
||
INET_ASSERT(!stillLocked);
|
||
INET_ASSERT(GetLastError() == NO_ERROR);
|
||
|
||
}
|
||
|
||
blockLength = lpHeader->BlockLength;
|
||
realLength = lpHeader->RealLength;
|
||
hLocal = LocalFree(hLocal);
|
||
|
||
INET_ASSERT(hLocal == NULL);
|
||
|
||
ActualMemoryAllocated -= memSize;
|
||
BlockLengthAllocated -= blockLength;
|
||
RealLengthAllocated -= realLength;
|
||
++MemoryFrees;
|
||
|
||
return hLocal;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
VOID
|
||
InetCheckBlockConsistency(
|
||
IN LPVOID lpMemory
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks that what we think is a valid allocated block (allocated by
|
||
InetAllocateMemory), really is
|
||
|
||
Arguments:
|
||
|
||
lpMemory - pointer to what we think is DEBUG_MEMORY_HEADER
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPDEBUG_MEMORY_HEADER lpHeader;
|
||
LPDEBUG_MEMORY_FOOTER lpFooter;
|
||
UINT i;
|
||
BOOL headerGuardOverrun;
|
||
BOOL footerGuardOverrun;
|
||
BOOL footerGuard2Overrun;
|
||
BOOL extraMemoryOverrun;
|
||
LPBYTE lpExtraMemory;
|
||
UINT byteLength;
|
||
|
||
__try {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)lpMemory;
|
||
lpFooter = (LPDEBUG_MEMORY_FOOTER)((LPBYTE)lpMemory
|
||
+ (lpHeader->BlockLength - sizeof(DEBUG_MEMORY_FOOTER)))
|
||
;
|
||
|
||
headerGuardOverrun = FALSE;
|
||
for (i = 0; i < ARRAY_ELEMENTS(lpHeader->Guard); ++i) {
|
||
if (lpHeader->Guard[i] != GUARD_DWORD_FILL) {
|
||
headerGuardOverrun = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
footerGuardOverrun = FALSE;
|
||
for (i = 0; i < ARRAY_ELEMENTS(lpFooter->Guard); ++i) {
|
||
if (lpFooter->Guard[i] != GUARD_DWORD_FILL) {
|
||
footerGuardOverrun = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
footerGuard2Overrun = FALSE;
|
||
for (i = 0; i < ARRAY_ELEMENTS(lpFooter->Guard2); ++i) {
|
||
if (lpFooter->Guard2[i] != GUARD_DWORD_FILL) {
|
||
footerGuard2Overrun = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
lpExtraMemory = (LPBYTE)(lpHeader + 1) + lpHeader->RealLength;
|
||
extraMemoryOverrun = FALSE;
|
||
byteLength = ROUND_UP_DWORD(lpHeader->RealLength) - lpHeader->RealLength;
|
||
for (i = 0; i < byteLength; ++i) {
|
||
if (lpExtraMemory[i] != BYTE_FILL_EXTRA) {
|
||
extraMemoryOverrun = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (headerGuardOverrun
|
||
|| footerGuardOverrun
|
||
|| footerGuard2Overrun
|
||
|| extraMemoryOverrun
|
||
|| (lpHeader->Signature != HEADER_SIGNATURE)
|
||
|| (lpFooter->Signature != FOOTER_SIGNATURE)
|
||
|| (lpFooter->BlockLength != lpHeader->BlockLength)) {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("Bad block: %x\n",
|
||
lpMemory
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
}
|
||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
FATAL,
|
||
("Invalid block %x - exception occurred\n",
|
||
lpMemory
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
}
|
||
}
|
||
|
||
|
||
LPVOID
|
||
InetLockMemory(
|
||
IN HLOCAL hLocal
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Locks a moveable memory block and increments the lock count. Checks block
|
||
consistency
|
||
|
||
Arguments:
|
||
|
||
hLocal - handle of moveable memory to lock
|
||
|
||
Return Value:
|
||
|
||
LPVOID
|
||
pointer to locked memory
|
||
|
||
--*/
|
||
|
||
{
|
||
LPDEBUG_MEMORY_HEADER lpHeader = NULL;
|
||
UINT memFlags;
|
||
|
||
memFlags = LocalFlags(hLocal);
|
||
|
||
INET_ASSERT(memFlags != LMEM_INVALID_HANDLE);
|
||
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)LocalLock(hLocal);
|
||
|
||
INET_ASSERT(lpHeader != NULL);
|
||
|
||
InetCheckBlockConsistency((LPVOID)lpHeader);
|
||
++lpHeader->LockCount;
|
||
|
||
GET_CALLERS_ADDRESS(&lpHeader->LastAccessReturnAddress[0],
|
||
&lpHeader->LastAccessReturnAddress[1]
|
||
);
|
||
|
||
lpHeader->LastAccessOperation = MemLock;
|
||
|
||
memFlags = LocalFlags(hLocal);
|
||
|
||
INET_ASSERT((memFlags != LMEM_INVALID_HANDLE)
|
||
&& (lpHeader->LockCount == (LONG)(memFlags & LMEM_LOCKCOUNT))
|
||
);
|
||
|
||
return ++lpHeader;
|
||
}
|
||
|
||
|
||
BOOL
|
||
InetUnlockMemory(
|
||
IN HLOCAL hLocal
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Unlocks a (locked!) moveable memory block
|
||
|
||
Arguments:
|
||
|
||
hLocal - handle (pointer) of block to unlock
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
UINT memFlags;
|
||
BOOL stillLocked;
|
||
LPDEBUG_MEMORY_HEADER lpHeader;
|
||
DWORD lockCount;
|
||
|
||
memFlags = LocalFlags(hLocal);
|
||
|
||
INET_ASSERT(memFlags != LMEM_INVALID_HANDLE);
|
||
INET_ASSERT((memFlags & LMEM_LOCKCOUNT) >= 1);
|
||
|
||
//
|
||
// memory must be locked or LocalFlags would have returned error.
|
||
// Lock memory again to get pointer to block, then unlock it.
|
||
// There should still be at least one lock on the block
|
||
//
|
||
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)LocalLock(hLocal);
|
||
LocalUnlock(hLocal);
|
||
|
||
InetCheckBlockConsistency((LPVOID)lpHeader);
|
||
|
||
GET_CALLERS_ADDRESS(&lpHeader->LastAccessReturnAddress[0],
|
||
&lpHeader->LastAccessReturnAddress[1]
|
||
);
|
||
|
||
lpHeader->LastAccessOperation = MemUnlock;
|
||
|
||
lockCount = --lpHeader->LockCount;
|
||
stillLocked = LocalUnlock(hLocal);
|
||
|
||
INET_ASSERT(stillLocked ? (lockCount > 0) : GetLastError() == NO_ERROR);
|
||
|
||
return stillLocked;
|
||
}
|
||
|
||
|
||
UINT
|
||
InetMemorySize(
|
||
IN HLOCAL hLocal,
|
||
IN BOOL IsMoveable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns allocated block size
|
||
|
||
Arguments:
|
||
|
||
hLocal - memory handle
|
||
IsMoveable - TRUE if hLocal is a handle to moveable memory >>> THAT IS NOT
|
||
LOCKED <<<
|
||
|
||
Return Value:
|
||
|
||
UINT
|
||
|
||
--*/
|
||
|
||
{
|
||
UINT size;
|
||
UINT sizeInHeader;
|
||
LPDEBUG_MEMORY_HEADER lpHeader;
|
||
|
||
if (IsMoveable) {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)LocalLock(hLocal);
|
||
|
||
INET_ASSERT(lpHeader != NULL);
|
||
|
||
sizeInHeader = lpHeader->RealLength;
|
||
size = LocalSize(hLocal);
|
||
LocalUnlock(hLocal);
|
||
} else {
|
||
lpHeader = (LPDEBUG_MEMORY_HEADER)hLocal - 1;
|
||
|
||
INET_ASSERT(lpHeader->Signature == HEADER_SIGNATURE);
|
||
|
||
sizeInHeader = lpHeader->RealLength;
|
||
size = LocalSize((HLOCAL)lpHeader);
|
||
}
|
||
|
||
INET_ASSERT((sizeInHeader <= size)
|
||
&& (size >= sizeof(DEBUG_MEMORY_HEADER) + sizeof(DEBUG_MEMORY_FOOTER))
|
||
);
|
||
|
||
return sizeInHeader;
|
||
}
|
||
|
||
|
||
BOOL
|
||
InetCheckDebugMemoryFreed(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check that we don't have any memory allocated
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
if (ActualMemoryAllocated || (MemoryFrees != MemoryAllocations)) {
|
||
|
||
DEBUG_PRINT(MEMALLOC,
|
||
ERROR,
|
||
("MemoryAllocated = %ld, MemoryAllocations = %lu, MemoryFrees = %lu\n",
|
||
ActualMemoryAllocated,
|
||
MemoryAllocations,
|
||
MemoryFrees
|
||
));
|
||
|
||
DEBUG_BREAK(MEMALLOC);
|
||
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
#if defined(i386)
|
||
|
||
|
||
VOID
|
||
x86SleazeCallersAddress(
|
||
LPVOID* pCaller,
|
||
LPVOID* pCallersCaller
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is a sleazy function that reads return addresses out of the stack/
|
||
frame pointer (ebp). We pluck out the return address of the function
|
||
that called THE FUNCTION THAT CALLED THIS FUNCTION, and the caller of
|
||
that function. Returning the return address of the function that called
|
||
this function is not interesting to that caller (almost worthy of Sir
|
||
Humphrey Appleby isn't it?)
|
||
|
||
Assumes:
|
||
|
||
my ebp => | caller's ebp |
|
||
| caller's eip |
|
||
| arg #1 | (pCaller)
|
||
| arg #2 | (pCallersCaller
|
||
|
||
Arguments:
|
||
|
||
pCaller - place where we return addres of function that called
|
||
the function that called this function
|
||
pCallersCaller - place where we return caller of above
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// this only works on x86 and only if not fpo functions!
|
||
//
|
||
|
||
LPVOID* ebp;
|
||
|
||
ebp = (PVOID*)&pCaller - 2; // told you it was sleazy
|
||
ebp = (PVOID*)*(PVOID*)ebp;
|
||
*pCaller = *(ebp + 1);
|
||
ebp = (PVOID*)*(PVOID*)ebp;
|
||
*pCallersCaller = *(ebp + 1);
|
||
}
|
||
|
||
#endif // defined(i386)
|
||
|
||
#endif // INET_DEBUG
|