Leaked source code of windows server 2003
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.
 
 
 
 
 
 

511 lines
19 KiB

// Ruler
// 1 2 3 4 5 6 7 8
//345678901234567890123456789012345678901234567890123456789012345678901234567890
/********************************************************************/
/* */
/* The standard layout. */
/* */
/* The standard layout for 'cpp' files in this code is as */
/* follows: */
/* */
/* 1. Include files. */
/* 2. Constants local to the class. */
/* 3. Data structures local to the class. */
/* 4. Data initializations. */
/* 5. Static functions. */
/* 6. Class functions. */
/* */
/* The constructor is typically the first function, class */
/* member functions appear in alphabetical order with the */
/* destructor appearing at the end of the file. Any section */
/* or function this is not required is simply omitted. */
/* */
/********************************************************************/
#include "InterfacePCH.hpp"
#include "Heap.hpp"
#include "RockallDebugBackEnd.hpp"
#include "RockallDebugFrontEnd.hpp"
/********************************************************************/
/* */
/* Constants local to the class. */
/* */
/* The constants supplied here try to make the layout of the */
/* the caches easier to understand and update. */
/* */
/********************************************************************/
CONST SBIT32 FindCacheSize = 2048;
CONST SBIT32 FindCacheThreshold = 0;
CONST SBIT32 FindSize = 1024;
/********************************************************************/
/* */
/* The description bit vectors. */
/* */
/* All heaps keep track of allocations using bit vectors. An */
/* allocation requires 2 bits to keep track of its state. The */
/* following array supplies the size of the available bit */
/* vectors measured in 32 bit words. */
/* */
/********************************************************************/
STATIC int NewPageSizes[] = { 1,4,0 };
/********************************************************************/
/* */
/* Class constructor. */
/* */
/* The overall structure and layout of the heap is controlled */
/* by the various constants and calls made in this function. */
/* There is a significant amount of flexibility available to */
/* a heap which can lead to them having dramatically different */
/* properties. */
/* */
/********************************************************************/
ROCKALL_DEBUG_FRONT_END::ROCKALL_DEBUG_FRONT_END
(
CACHE_DETAILS *Caches1,
CACHE_DETAILS *Caches2,
int MaxFreeSpace,
ROCKALL_BACK_END *RockallBackEnd,
bool Recycle,
bool SingleImage,
int Stride1,
int Stride2,
bool ThreadSafe
) :
//
// Call the constructors for the contained classes.
//
ROCKALL_FRONT_END
(
Caches1,
Caches2,
FindCacheSize,
FindCacheThreshold,
FindSize,
((MaxFreeSpace == 0) ? MaxFreeSpace : 0),
NewPageSizes,
RockallBackEnd,
Recycle,
SingleImage,
Stride1,
Stride2,
ThreadSafe
)
{
//
// We make much use of the guard value in the
// debug heap so here we try to claim the
// address but not commit it so we will ensure
// an access violation if the program ever
// tries to access it.
//
VirtualAlloc
(
((void*) GuardValue),
GuardSize,
MEM_RESERVE,
PAGE_NOACCESS
);
}
/********************************************************************/
/* */
/* Memory deallocation. */
/* */
/* We make sure the memory is allocated and that the guard */
/* words have not been damanged. If so we reset the contents */
/* of the allocation and delete the allocation. */
/* */
/********************************************************************/
bool ROCKALL_DEBUG_FRONT_END::Delete( void *Address,int Size )
{
//
// A well known practice is to try to delete
// a null pointer. This is really a very poor
// style but we support it in any case.
//
if ( Address != ((void*) AllocationFailure) )
{
//
// Delete the user information by writing
// guard words over the allocation. This
// should cause the application to crash
// if the area is read and also allows us
// to check to see if it is written later.
//
DeleteGuard( Address );
return true;
}
else
{ return false; }
}
/********************************************************************/
/* */
/* Delete all allocations. */
/* */
/* We check to make sure the heap is not corrupt and force */
/* the return of all heap space back to the operating system. */
/* */
/********************************************************************/
void ROCKALL_DEBUG_FRONT_END::DeleteAll( bool Recycle )
{
AUTO bool Active;
AUTO void *Address = NULL;
AUTO int Space;
//
// Walk the heap to verify all the allocations
// so that we know that the heap is undamaged.
//
while ( WalkGuard( & Active,& Address,& Space ) );
//
// Delete the heap and force all the allocated
// memory to be returned to the operating system
// regardless of what the user requested. Any
// attempt to access the deallocated memory will
// be trapped by the operating system.
//
ROCKALL_FRONT_END::DeleteAll( (Recycle && false) );
}
/********************************************************************/
/* */
/* Memory allocation details. */
/* */
/* Extract information about a memory allocation and just for */
/* good measure check the guard words at the same time. */
/* */
/********************************************************************/
bool ROCKALL_DEBUG_FRONT_END::Details( void *Address,int *Space )
{ return Verify( Address,Space ); }
/********************************************************************/
/* */
/* Exception processing. */
/* */
/* Although it is very hard to make Rockall crash it is */
/* technically possible. When (or should I say if) this */
/* we call the following function (which may be overloadded). */
/* */
/********************************************************************/
void ROCKALL_DEBUG_FRONT_END::Exception( char *Message )
{
DebugPrint
(
"EXCEPTION CAUGHT: %s\n"
"ROCKALL TOTAL HEAP FAILURE: You have toasted the heap - Wow !!!!\n",
Message
);
}
/********************************************************************/
/* */
/* Multiple memory deallocations. */
/* */
/* We make sure all the memory is allocated and that the guard */
/* words have not been damaged. If so we reset the contents */
/* of the allocations and then delete the allocations. */
/* */
/********************************************************************/
bool ROCKALL_DEBUG_FRONT_END::MultipleDelete
(
int Actual,
void *Array[],
int Size
)
{
REGISTER bool Result = true;
REGISTER SBIT32 Count;
//
// We would realy like to use the multiple
// delete functionality of Rockall here but
// it is too much effort. So we simply call
// the standard debug delete on each entry
// in the array. Although this is not as
// fast it does give more transparent results.
//
for ( Count=0;Count < Actual;Count ++ )
{
//
// Delete each memory allocation after
// carefully checking it.
//
if ( ! Delete( Array[ Count ],Size ) )
{ Result = false; }
}
return Result;
}
/********************************************************************/
/* */
/* Multiple memory allocations. */
/* */
/* Allocate a collection of memory elements and setup the */
/* guard information so we can check they have not been */
/* damaged later. */
/* */
/********************************************************************/
bool ROCKALL_DEBUG_FRONT_END::MultipleNew
(
int *Actual,
void *Array[],
int Requested,
int Size,
int *Space,
bool Zero
)
{
//
// We would realy like to use the multiple
// new functionality of Rockall here but
// it is too much effort. So we simply call
// the standard debug new on each entry
// in the array. Although this is not as
// fast it does give more transparent results.
//
for ( (*Actual)=0;(*Actual) < Requested;(*Actual) ++ )
{
REGISTER void *Current = New( Size,Space,Zero );
//
// We add each sucessful memory allocation to
// into the array.
//
if ( Current != ((void*) AllocationFailure) )
{ Array[ (*Actual) ] = Current; }
else
{ break; }
}
return ((*Actual) == Requested);
}
/********************************************************************/
/* */
/* Memory allocation. */
/* */
/* We add some space on to the original allocation size for */
/* various information and then call the allocator. We then */
/* set the guard words so we can check for overruns. */
/* */
/********************************************************************/
void *ROCKALL_DEBUG_FRONT_END::New( int Size,int *Space,bool Zero )
{
AUTO void *Address = ((void*) AllocationFailure);
//
// The size must be greater than or equal to zero.
// We do not know how to allocate a negative amount
// of memory.
//
if ( Size >= 0 )
{
//
// We need to allocate some space plus an extra
// bit for the guard words so we can detect any
// corruption later.
//
if ( NewGuard( & Address,Size,Space ) )
{
//
// Zero the allocation if requested. We do
// this based on whether we are returning the
// space information. If not we only zero
// size requested. Otherwise we have to zero
// the entire area.
//
if ( Zero )
{
ZeroMemory
(
Address,
((Space == NULL) ? Size : (*Space))
);
}
}
}
else
{ UserError( Address,NULL,"Allocation size can not be negative" ); }
return Address;
}
/********************************************************************/
/* */
/* Memory reallocation. */
/* */
/* We need to resize an allocation. We ensure the original */
/* allocation was undamaged and then expand it. We also */
/* update the guard words to reflect the changes. */
/* */
/********************************************************************/
void *ROCKALL_DEBUG_FRONT_END::Resize
(
void *Address,
int NewSize,
int Move,
int *Space,
bool NoDelete,
bool Zero
)
{
REGISTER void *NewAddress = ((void*) AllocationFailure);
//
// A well known practice is to try to resize a null
// pointer. This is really a very poor style but we
// support it in any case.
//
if ( Address != ((void*) AllocationFailure) )
{
//
// The new size must be greater than or equal to
// zero. We do not know how to allocate a negative
// amount of memory.
//
if ( NewSize >= 0 )
{
AUTO int ActualSize;
//
// Ask for the details of the allocation. This
// will fail if the memory is not allocated.
//
if ( VerifyGuard( Address,& ActualSize,Space ) )
{
//
// We always move an allocation if we are
// allowed to as this has the best chance
// of shaking out various types of bugs.
//
if ( Move != 0 )
{
//
// We need to make sure we were able
// to allocate the new memory otherwise
// the copy will fail.
//
if ( NewGuard( & NewAddress,NewSize,Space ) )
{
REGISTER SBIT32 Smallest =
((ActualSize < NewSize) ? ActualSize : NewSize);
REGISTER SBIT32 Largest =
(((Space == NULL)) ? NewSize : (*Space));
//
// Copy the contents of the old allocation
// to the new allocation.
//
memcpy
(
((void*) NewAddress),
((void*) Address),
((int) Smallest)
);
//
// Zero the allocation if requested. We do
// this based on whether we are returning the
// space information. If not we only zero
// size requested. Otherwise we have to zero
// the entire area.
//
if ( Zero )
{
ZeroMemory
(
(((char*) NewAddress) + Smallest),
(Largest - Smallest)
);
}
//
// Delete the existing memory allocation
// and clean up.
//
DeleteGuard( Address );
}
}
}
else
{ UserError( Address,NULL,"Resize on unallocated address" ); }
}
else
{ UserError( Address,NULL,"Allocation size must be positive" ); }
}
else
{ NewAddress = New( NewSize,Space,Zero ); }
return NewAddress;
}
/********************************************************************/
/* */
/* Verify memory allocation details. */
/* */
/* Extract information about a memory allocation and just for */
/* good measure check the guard words at the same time. */
/* */
/********************************************************************/
bool ROCKALL_DEBUG_FRONT_END::Verify( void *Address,int *Space )
{
AUTO int Size;
//
// Verify that the supplied address is an area
// of allocated memory. If not just exit as this
// is only a request for information.
//
return VerifyGuard( Address,& Size,Space );
}
/********************************************************************/
/* */
/* Walk the heap. */
/* */
/* We have been asked to walk the heap. It is hard to know */
/* why anybody might want to do this given the rest of the */
/* functionality available. Nonetheless, we just do what is */
/* required to keep everyone happy. */
/* */
/********************************************************************/
bool ROCKALL_DEBUG_FRONT_END::Walk( bool *Active,void **Address,int *Space )
{
//
// Walk the heap.
//
return WalkGuard( Active,Address,Space );
}
/********************************************************************/
/* */
/* Class destructor. */
/* */
/* Destory the current instance of the class. */
/* */
/********************************************************************/
ROCKALL_DEBUG_FRONT_END::~ROCKALL_DEBUG_FRONT_END( void )
{ /* void */ }