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
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 */ }
|