You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
461 lines
11 KiB
461 lines
11 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1990 - 1999
|
|
|
|
Module Name:
|
|
|
|
memory.cxx
|
|
|
|
Abstract:
|
|
|
|
This file contains the new and delete routines for memory management in
|
|
the Bits runtime. Rather than using the memory management provided by the
|
|
C++ system we'll use the system allocator.
|
|
|
|
Revision History:
|
|
|
|
mikemon ??-??-?? Beginning of time (at least for this file).
|
|
mikemon 12-31-90 Upgraded the comments.
|
|
mariogo 04-24-96 Rewrite to unify platforms, behavior and performance.
|
|
|
|
--*/
|
|
|
|
#include <qmgrlib.h>
|
|
|
|
#if !defined(BITS_V12_ON_NT4)
|
|
#include <memory.tmh>
|
|
#endif
|
|
|
|
HANDLE hBitsHeap = 0;
|
|
unsigned int DebugFlags = 0;
|
|
|
|
#define NO_HEAP_SLOWDOWN
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Default allocators
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
#if !defined(DBG)
|
|
|
|
void * _cdecl operator new(size_t nSize)
|
|
{
|
|
void *pNewMemory = HeapAlloc( hBitsHeap, 0, nSize );
|
|
|
|
if ( !pNewMemory )
|
|
{
|
|
LogError( "Unable to allocate memory block of size, %X\n", nSize );
|
|
throw ComError( E_OUTOFMEMORY );
|
|
}
|
|
|
|
return pNewMemory;
|
|
}
|
|
|
|
void _cdecl operator delete(void *pMemory)
|
|
{
|
|
if (!pMemory)
|
|
return;
|
|
|
|
if (!HeapFree( hBitsHeap, 0, pMemory ))
|
|
{
|
|
LogError( "Error occured freeing memory at %p, error %!winerr!\n",
|
|
pMemory, GetLastError() );
|
|
}
|
|
}
|
|
|
|
int fHeapInitialized = 0;
|
|
|
|
int InitializeBitsAllocator(void)
|
|
{
|
|
#if 1
|
|
|
|
if (0 == fHeapInitialized)
|
|
{
|
|
if (0 == hBitsHeap)
|
|
{
|
|
hBitsHeap = RtlCreateHeap( HEAP_GROWABLE
|
|
| HEAP_FREE_CHECKING_ENABLED
|
|
| HEAP_CLASS_1,
|
|
0,
|
|
16 * 1024 - 512,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
|
|
if (hBitsHeap)
|
|
{
|
|
fHeapInitialized = 1;
|
|
}
|
|
|
|
if (0 == fHeapInitialized )
|
|
{
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
|
|
|
|
#else
|
|
|
|
hBitsHeap = RtlProcessHeap();
|
|
|
|
return(0);
|
|
|
|
#endif
|
|
}
|
|
|
|
int
|
|
BitspCheckHeap (
|
|
void
|
|
)
|
|
// Allow some checked compenents to be linked into a free memory.cxx.
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
#else // ******************** DEBUG ********************
|
|
|
|
#ifdef NO_HEAP_SLOWDOWN
|
|
int fMemoryCheck = 0;
|
|
#else
|
|
int fMemoryCheck = 1;
|
|
#endif
|
|
|
|
int fHeapInitialized = 0;
|
|
|
|
CRITICAL_SECTION BitsHeapLock;
|
|
|
|
typedef NTSYSAPI
|
|
USHORT
|
|
(NTAPI RTLCAPTURESTACKBACKTRACE)(
|
|
IN ULONG FramesToSkip,
|
|
IN ULONG FramesToCapture,
|
|
OUT PVOID *BackTrace,
|
|
OUT PULONG BackTraceHash OPTIONAL
|
|
);
|
|
|
|
typedef RTLCAPTURESTACKBACKTRACE * PRTLCAPTURESTACKBACKTRACE;
|
|
|
|
PRTLCAPTURESTACKBACKTRACE g_RtlCaptureStackBackTrace;
|
|
|
|
int InitializeBitsAllocator(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called during Bits initialization. This function must can by one
|
|
thread at a time. Sets the heap handle for debugging.
|
|
|
|
Maybe called more then once if this (or a later step) of Bits
|
|
initialization fails.
|
|
|
|
--*/
|
|
{
|
|
if (0 == fHeapInitialized)
|
|
{
|
|
if (0 == hBitsHeap)
|
|
{
|
|
hBitsHeap = RtlCreateHeap( HEAP_GROWABLE
|
|
| HEAP_TAIL_CHECKING_ENABLED
|
|
| HEAP_FREE_CHECKING_ENABLED
|
|
| HEAP_CLASS_1,
|
|
0,
|
|
16 * 1024 - 512,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
|
|
if (hBitsHeap)
|
|
{
|
|
if (0 == RtlInitializeCriticalSection(&BitsHeapLock))
|
|
{
|
|
fHeapInitialized = 1;
|
|
}
|
|
}
|
|
|
|
if (0 == fHeapInitialized )
|
|
{
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
HMODULE hModule = GetModuleHandle( L"kernel32" );
|
|
if (hModule)
|
|
{
|
|
g_RtlCaptureStackBackTrace = (PRTLCAPTURESTACKBACKTRACE) GetProcAddress( hModule, "RtlCaptureStackBacktrace" );
|
|
|
|
// ignore error, because it's just a debugging aid and is not available in Win2000
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
#define Bits_GUARD 0xA1
|
|
|
|
typedef struct _Bits_MEMORY_BLOCK
|
|
{
|
|
// First,forward and backward links to other Bits heap allocations.
|
|
// These are first allow easy debugging with the dl command
|
|
struct _Bits_MEMORY_BLOCK *next;
|
|
struct _Bits_MEMORY_BLOCK *previous;
|
|
|
|
// Specifies the size of the block of memory in bytes.
|
|
unsigned long size;
|
|
|
|
// Thread id of allocator
|
|
unsigned long tid;
|
|
|
|
void * AllocStackTrace[4];
|
|
|
|
// (Pad to make header 0 mod 8) 0 when allocated, 0xF0F0F0F0 when freed.
|
|
unsigned long free;
|
|
|
|
// Reserve an extra 4 bytes as the front guard of each block.
|
|
unsigned char frontguard[4];
|
|
|
|
// Data will appear here. Note that the header must be 0 mod 8.
|
|
|
|
// Reserve an extra 4 bytes as the rear guard of each block.
|
|
unsigned char rearguard[4];
|
|
|
|
} Bits_MEMORY_BLOCK;
|
|
|
|
//
|
|
// Compile-time test to ensure that Bits_MEMORY_BLOCK.rearguard is aligned on
|
|
// natural boundary.
|
|
//
|
|
|
|
#if defined(_WIN64)
|
|
C_ASSERT( (FIELD_OFFSET( Bits_MEMORY_BLOCK, rearguard ) % 16) == 0 );
|
|
#else
|
|
C_ASSERT( (FIELD_OFFSET( Bits_MEMORY_BLOCK, rearguard ) % 8) == 0 );
|
|
#endif
|
|
|
|
Bits_MEMORY_BLOCK * AllocatedBlocks = 0;
|
|
unsigned long BlockCount = 0;
|
|
|
|
int
|
|
CheckMemoryBlock (
|
|
Bits_MEMORY_BLOCK * block
|
|
)
|
|
{
|
|
if ( block->frontguard[0] != Bits_GUARD
|
|
|| block->frontguard[1] != Bits_GUARD
|
|
|| block->frontguard[2] != Bits_GUARD
|
|
|| block->frontguard[3] != Bits_GUARD )
|
|
{
|
|
LogError("BAD BLOCK (front) @ %p\n", block);
|
|
ASSERT(0);
|
|
return(1);
|
|
}
|
|
|
|
if ( block->rearguard[block->size] != Bits_GUARD
|
|
|| block->rearguard[block->size+1] != Bits_GUARD
|
|
|| block->rearguard[block->size+2] != Bits_GUARD
|
|
|| block->rearguard[block->size+3] != Bits_GUARD )
|
|
{
|
|
LogError("BAD BLOCK (rear) @ %p (%p)\n",block, &block->rearguard[block->size]);
|
|
ASSERT(0);
|
|
return(1);
|
|
}
|
|
|
|
ASSERT(block->free == 0);
|
|
|
|
if ( block->next != 0)
|
|
{
|
|
ASSERT(block->next->previous == block);
|
|
}
|
|
|
|
if ( block->previous != 0)
|
|
{
|
|
ASSERT(block->previous->next == block);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
BitsValidateHeapList(
|
|
void
|
|
)
|
|
// Called with BitsHeapLock held.
|
|
{
|
|
Bits_MEMORY_BLOCK * block;
|
|
unsigned Blocks = 0;
|
|
|
|
// Under stress this check causes performance to drop too much.
|
|
// Compile with -DNO_HEAP_SLOWDOWN or ed the flag in memory
|
|
// to speed things up.
|
|
|
|
if (fMemoryCheck == 0)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
block = AllocatedBlocks;
|
|
|
|
while (block != 0)
|
|
{
|
|
if (CheckMemoryBlock(block))
|
|
{
|
|
return(1);
|
|
}
|
|
block = block->next;
|
|
Blocks++;
|
|
}
|
|
|
|
ASSERT(Blocks == BlockCount);
|
|
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
BitspCheckHeap (
|
|
void
|
|
)
|
|
// Returns 0 if the heap appears to be okay.
|
|
{
|
|
if (fMemoryCheck == 0)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
EnterCriticalSection(&BitsHeapLock);
|
|
|
|
int ret = BitsValidateHeapList();
|
|
|
|
LeaveCriticalSection(&BitsHeapLock);
|
|
|
|
return(ret);
|
|
}
|
|
|
|
void * __cdecl
|
|
operator new(
|
|
size_t size
|
|
)
|
|
{
|
|
Bits_MEMORY_BLOCK * block;
|
|
|
|
EnterCriticalSection(&BitsHeapLock);
|
|
|
|
ASSERT( ("You allocated a negative amount",
|
|
size < (size + sizeof(Bits_MEMORY_BLOCK))) );
|
|
|
|
BitsValidateHeapList();
|
|
|
|
block = (Bits_MEMORY_BLOCK *) HeapAlloc( hBitsHeap, 0, size + sizeof(Bits_MEMORY_BLOCK));
|
|
if ( block == 0 )
|
|
{
|
|
LeaveCriticalSection(&BitsHeapLock);
|
|
|
|
LogError( "Unable to allocate memory block of size %X\n", size );
|
|
throw ComError( E_OUTOFMEMORY );
|
|
}
|
|
|
|
block->size = size;
|
|
block->tid = GetCurrentThreadId();
|
|
block->free = 0;
|
|
|
|
if (AllocatedBlocks != 0)
|
|
AllocatedBlocks->previous = block;
|
|
|
|
block->next = AllocatedBlocks;
|
|
block->previous = 0;
|
|
AllocatedBlocks = block;
|
|
BlockCount++;
|
|
|
|
block->frontguard[0] = Bits_GUARD;
|
|
block->frontguard[1] = Bits_GUARD;
|
|
block->frontguard[2] = Bits_GUARD;
|
|
block->frontguard[3] = Bits_GUARD;
|
|
|
|
#if i386
|
|
|
|
if (g_RtlCaptureStackBackTrace)
|
|
{
|
|
ULONG ignore;
|
|
|
|
g_RtlCaptureStackBackTrace(
|
|
2,
|
|
4,
|
|
(void **) &block->AllocStackTrace,
|
|
&ignore);
|
|
}
|
|
#endif
|
|
|
|
|
|
block->rearguard[size] = Bits_GUARD;
|
|
block->rearguard[size+1] = Bits_GUARD;
|
|
block->rearguard[size+2] = Bits_GUARD;
|
|
block->rearguard[size+3] = Bits_GUARD;
|
|
|
|
LeaveCriticalSection(&BitsHeapLock);
|
|
|
|
return(&(block->rearguard[0]));
|
|
}
|
|
|
|
void __cdecl
|
|
operator delete (
|
|
IN void * obj
|
|
)
|
|
{
|
|
Bits_MEMORY_BLOCK * block;
|
|
|
|
if (obj == 0)
|
|
return;
|
|
|
|
EnterCriticalSection(&BitsHeapLock);
|
|
|
|
block = (Bits_MEMORY_BLOCK *) (((unsigned char *) obj)
|
|
- FIELD_OFFSET(Bits_MEMORY_BLOCK, rearguard));
|
|
|
|
// Validate block being freed.
|
|
|
|
CheckMemoryBlock(block);
|
|
|
|
if (block->next != 0)
|
|
{
|
|
CheckMemoryBlock(block->next);
|
|
}
|
|
|
|
if (block->previous != 0)
|
|
{
|
|
CheckMemoryBlock(block->previous);
|
|
}
|
|
|
|
// Remove the block from the list
|
|
|
|
if (block == AllocatedBlocks)
|
|
AllocatedBlocks = block->next;
|
|
|
|
if (block->next != 0)
|
|
block->next->previous = block->previous;
|
|
|
|
if (block->previous != 0)
|
|
block->previous->next = block->next;
|
|
|
|
// Mark this block as free
|
|
block->free = 0xF0F0F0F0;
|
|
|
|
// Validate other Bits allocations.
|
|
BlockCount-- ;
|
|
BitsValidateHeapList();
|
|
|
|
LeaveCriticalSection(&BitsHeapLock);
|
|
|
|
if (!HeapFree( hBitsHeap, 0, block ))
|
|
{
|
|
LogError( "Error occured freeing memory at %p, error %!winerr!\n",
|
|
block, GetLastError() );
|
|
}
|
|
}
|
|
|
|
#endif // not debug
|