📄 pgpmemorymgr.c
字号:
/*____________________________________________________________________________
Copyright (C) 1997 Network Associates Inc. and affiliated companies.
All rights reserved.
$Id: pgpMemoryMgr.c,v 1.4 1999/05/11 17:38:11 dgal Exp $
____________________________________________________________________________*/
#include "pgpPFLErrors.h"
#include "pgpMem.h"
#include "pgpRMWOLock.h"
#include "pgpMemoryMgrPriv.h"
/* if defined as 1, causes leaks to be tracked */
#define MEMORY_MGR_TRACK_LEAKS PGP_DEBUG
#define TESTING PGP_DEBUG
#if TESTING
static void sTestMemoryMgr( PGPMemoryMgrRef mgr );
#else
#define sTestMemoryMgr( mgr ) /* nothing */
#endif
/*____________________________________________________________________________
This structure is prepended to every allocated block.
It is dynamically padded to keep it aligned to the alignment
requirement. See kRealHeaderSize.
____________________________________________________________________________*/
typedef struct DataHeader
{
#define kHeaderMagic ((PGPUInt16)0xABCD)
PGPMemoryMgrRef mgr;
PGPUInt32 secureAlloc : 1;
PGPUInt32 nonPageable : 1;
PGPUInt32 requestSize : 30;
#if MEMORY_MGR_TRACK_LEAKS
struct DataHeader * next;
struct DataHeader * prev;
#endif
PGPUInt32 magic;
#define kDataHeaderMagic 0x42554746 /*'BUGF'*/
} DataHeader;
#define kHeaderAlign 16
#define kOddHeaderBytes ( sizeof( DataHeader ) % kHeaderAlign )
#define kNeededHeaderBytes ( (kHeaderAlign - kOddHeaderBytes) % kHeaderAlign)
#define kRealHeaderSize ( sizeof( DataHeader ) + kNeededHeaderBytes )
#define HeaderToUserBlock( hdr ) \
( (void *)( ((char *)(hdr)) + kRealHeaderSize) )
#define UserBlockToHeader( user ) \
( (DataHeader *)(((char *)user) - kRealHeaderSize) )
static PGPBoolean
sDataHeaderIsValid( const DataHeader *header )
{
return( IsntNull( header ) &&
PGPMemoryMgrIsValid( header->mgr ) &&
header->magic == kDataHeaderMagic );
}
#if PGP_DEBUG
#define AssertBlockValid( block) \
pgpAssert( IsntNull( block ) && \
sDataHeaderIsValid( (const DataHeader *)\
UserBlockToHeader( block ) ) )
#else
#define AssertBlockValid( block ) /* nothing */
#endif
struct PGPMemoryMgr
{
#define kPGPMemoryMgrMagic 0x4D4D6772 /* 'MMgr' */
PGPUInt32 magic; /* Always kPGPMemoryMgrMagic */
PGPUserValue customValue; /* for custom memory mgrs */
PGPBoolean isDefault;
PGPMemoryMgrAllocationProc allocProc;
PGPMemoryMgrReallocationProc reallocProc;
PGPMemoryMgrDeallocationProc deallocProc;
PGPMemoryMgrSecureAllocationProc secureAllocProc; /* may be NULL */
PGPMemoryMgrSecureDeallocationProc secureDeallocProc; /* may be NULL */
#if MEMORY_MGR_TRACK_LEAKS
PGPRMWOLock leaksRMWOLock;
DataHeader * leaksList;
DataHeader dummyItem;
PGPSize numAllocations;
#endif
} ;
PGPBoolean
PGPMemoryMgrIsValid( PGPMemoryMgrRef mgr )
{
return( IsntNull( mgr ) &&
mgr->magic == kPGPMemoryMgrMagic );
}
#if MEMORY_MGR_TRACK_LEAKS /* [ */
static void
sCheckListIntegrity( DataHeader const * list )
{
DataHeader * cur = list->next;
const DataHeader * prev = list;
/* verify that item isn't already in list */
while ( cur != list )
{
pgpAssert( cur->magic == kDataHeaderMagic );
pgpAssert( cur->prev->magic == kDataHeaderMagic );
pgpAssert( cur->next->magic == kDataHeaderMagic );
pgpAssert( cur->next->prev == cur && cur->prev->next == cur);
prev = cur;
cur = cur->next;
}
}
static void
sAddToLeaksList(
PGPMemoryMgrRef mgr,
DataHeader * item )
{
DataHeader * list;
PGPRMWOLockStartWriting(&mgr->leaksRMWOLock);
list = mgr->leaksList;
sCheckListIntegrity( list );
pgpAssert( IsntNull( list->next ) && IsntNull( list->prev ) );
#if PGP_DEBUG
{
DataHeader * cur = list->next;
/* verify that item isn't already in list */
while ( cur != list )
{
pgpAssert( cur != item );
cur = cur->next;
}
}
#endif
/* insert new item into circular linked list */
item->next = list;
item->prev = list->prev;
list->prev->next = item;
list->prev = item;
mgr->numAllocations += 1;
sCheckListIntegrity( list );
pgpAssert( IsntNull( item->next ) && IsntNull( item->prev ) );
PGPRMWOLockStopWriting(&mgr->leaksRMWOLock);
}
static void
sRemoveFromLeaksList(
PGPMemoryMgrRef mgr,
DataHeader * item )
{
DataHeader * next;
DataHeader * prev;
PGPRMWOLockStartWriting(&mgr->leaksRMWOLock);
next = item->next;
prev = item->prev;
sCheckListIntegrity( mgr->leaksList );
pgpAssert( prev->next == item && next->prev == item );
next->prev = prev;
prev->next = next;
item->next = NULL;
item->prev = NULL;
mgr->numAllocations -= 1;
sCheckListIntegrity( mgr->leaksList );
PGPRMWOLockStopWriting(&mgr->leaksRMWOLock);
}
#else
#define sAddToLeaksList( mgr, item ) /* nothing */
#define sRemoveFromLeaksList( mgr, item ) /* nothing */
#endif /* ] */
static void
sInitDataHeader(
PGPMemoryMgrRef mgr,
PGPSize requestSize,
DataHeader * header )
{
pgpClearMemory( header, sizeof(*header) );
header->mgr = mgr;
header->secureAlloc = FALSE;
header->nonPageable = FALSE;
header->requestSize = requestSize;
header->magic = kDataHeaderMagic;
#if MEMORY_MGR_TRACK_LEAKS
header->next = NULL;
header->prev = NULL;
#endif
}
/*____________________________________________________________________________
Reallocate a secure block.
To preserve the semantics of the block not changing if it shrinks,
we take no action if the block is shrinking. If it's growing, we
always discard it and create a new one.
____________________________________________________________________________*/
static PGPError
sSecureMemoryReallocProc(
PGPMemoryMgrRef mgr,
void ** allocation,
PGPSize newAllocationSize,
PGPMemoryMgrFlags flags,
PGPSize existingSize )
{
PGPError err = kPGPError_NoErr;
pgpAssert( IsntNull( *allocation ) );
#if 0
if ( newAllocationSize <= existingSize )
{
PGPUInt32 excessByteCount;
char * dataToClear = NULL;
/* leave existing size intact, but clear excess bytes now
to avoid leaving sensitive data in memory unnecessarily */
excessByteCount = existingSize - newAllocationSize;
dataToClear = ((char *)*allocation) + newAllocationSize;
pgpClearMemory( dataToClear, excessByteCount );
err = kPGPError_NoErr;
}
else
#endif
{ /* block is increasing in size */
PGPBoolean isNonPageable;
void * newBlock = NULL;
newBlock = (mgr->secureAllocProc)( mgr, mgr->customValue,
newAllocationSize, flags, &isNonPageable);
if ( IsntNull( newBlock ) )
{
DataHeader * oldHeader = (DataHeader *)*allocation;
pgpCopyMemory( *allocation, newBlock,
pgpMin( existingSize, newAllocationSize ) );
(mgr->secureDeallocProc)( mgr, mgr->customValue,
*allocation, existingSize,
(PGPBoolean)oldHeader->nonPageable );
*allocation = newBlock;
}
else
{
err = kPGPError_OutOfMemory;
}
}
return( err );
}
/*____________________________________________________________________________
Allocate a new Memory Mgr using custom memory allocators.
____________________________________________________________________________*/
PGPError
PGPNewMemoryMgrCustom(
PGPNewMemoryMgrStruct const * custom,
PGPMemoryMgrRef * newMgr )
{
PGPError err = kPGPError_NoErr;
PGPMemoryMgrRef mgr = NULL;
PGPUInt32 idx;
PGPValidatePtr( newMgr );
*newMgr = NULL;
PGPValidatePtr( custom );
PGPValidatePtr( custom->allocProc );
PGPValidatePtr( custom->reallocProc );
PGPValidatePtr( custom->deallocProc );
PGPValidatePtr( custom->secureAllocProc );
PGPValidatePtr( custom->secureDeallocProc );
PGPValidateParam( custom->sizeofStruct >= sizeof( *custom ) );
PGPValidateParam( custom->reserved == NULL );
#define kNumPads sizeof( custom->pad ) / sizeof( custom->pad[ 0 ] )
for( idx = 0; idx < kNumPads; ++idx )
{
PGPValidateParam( custom->pad[ idx ] == NULL );
}
/* NOTE: do not depend on kPGPMemoryMgrFlags_Clear here;
allocator is not required to support it */
mgr = (PGPMemoryMgr *) (*(custom->allocProc))( NULL, custom->customValue,
sizeof( *mgr ), 0 );
if( IsntNull( mgr ) )
{
pgpClearMemory( mgr, sizeof( *mgr ) );
mgr->magic = kPGPMemoryMgrMagic;
mgr->allocProc = custom->allocProc;
mgr->reallocProc = custom->reallocProc;
mgr->deallocProc = custom->deallocProc;
mgr->secureAllocProc = custom->secureAllocProc;
mgr->secureDeallocProc = custom->secureDeallocProc;
mgr->customValue = custom->customValue;
mgr->isDefault = FALSE;
#if MEMORY_MGR_TRACK_LEAKS
/* Create read many/write once mutex. */
InitializePGPRMWOLock(&mgr->leaksRMWOLock);
/* set up doubly-linked leaks list */
mgr->leaksList = &mgr->dummyItem;
mgr->dummyItem.next = &mgr->dummyItem;
mgr->dummyItem.prev = &mgr->dummyItem;
mgr->dummyItem.magic = kDataHeaderMagic;
mgr->numAllocations = 0;
#endif
}
else
{
err = kPGPError_OutOfMemory;
}
*newMgr = mgr;
#if TESTING
if ( IsntPGPError( err ) )
{
sTestMemoryMgr( mgr );
}
#endif
return( err );
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
PGPNewMemoryMgr(
PGPFlags reserved,
PGPMemoryMgrRef * newMgr )
{
PGPError err = kPGPError_NoErr;
PGPValidatePtr( newMgr );
*newMgr = NULL;
PGPValidateParam( reserved == 0 );
err = pgpCreateStandardMemoryMgr( newMgr );
if ( IsntPGPError( err ) )
{
(*newMgr)->isDefault = TRUE;
}
return( err );
}
/*____________________________________________________________________________
Delete an existing PFLContext and all resources associated with it.
____________________________________________________________________________*/
PGPError
PGPFreeMemoryMgr(PGPMemoryMgrRef mgr)
{
PGPError err = kPGPError_NoErr;
PGPValidateParam( PGPMemoryMgrIsValid( mgr ) );
if( PGPMemoryMgrIsValid( mgr ) )
{
PGPUserValue customValue = mgr->customValue;
PGPBoolean isDefault = mgr->isDefault;
#if MEMORY_MGR_TRACK_LEAKS
DeletePGPRMWOLock(&mgr->leaksRMWOLock);
pgpAssertMsg( mgr->numAllocations == 0,
"PGPFreeData(): mgr being freed with outstanding allocations" );
#endif
(*mgr->deallocProc)( NULL, customValue, mgr, sizeof( *mgr ));
if ( isDefault )
{
pgpDisposeStandardMemoryMgrUserValue( customValue );
}
}
else
{
err = kPGPError_BadParams;
}
return( err );
}
PGPError
PGPGetMemoryMgrCustomValue(
PGPMemoryMgrRef mgr,
PGPUserValue * customValue)
{
PGPError err = kPGPError_NoErr;
PGPValidatePtr( customValue );
*customValue = NULL;
PGPValidateMemoryMgr( mgr );
/* illegal to change user value of default allocator */
PGPValidateParam( ! mgr->isDefault );
if( PGPMemoryMgrIsValid( mgr ) &&
IsntNull( customValue ) )
{
*customValue = mgr->customValue;
}
else
{
err = kPGPError_BadParams;
}
return( err );
}
PGPError
PGPSetMemoryMgrCustomValue(
PGPMemoryMgrRef mgr,
PGPUserValue customValue)
{
PGPError err = kPGPError_NoErr;
PGPValidateMemoryMgr( mgr );
/* illegal to change user value of default allocator */
PGPValidateParam( ! mgr->isDefault );
if( PGPMemoryMgrIsValid( mgr ) )
{
mgr->customValue = customValue;
}
else
{
err = kPGPError_BadParams;
}
return( err );
}
/*____________________________________________________________________________
Allocate a block of memory using the allocator stored in a PFLContext.
____________________________________________________________________________*/
void *
PGPNewData(
PGPMemoryMgrRef mgr,
PGPSize requestSize,
PGPMemoryMgrFlags flags)
{
void *allocation = NULL;
PGPSize allocationSize = requestSize;
allocationSize += kRealHeaderSize;
pgpAssert( PGPMemoryMgrIsValid( mgr ) );
if( PGPMemoryMgrIsValid( mgr ) )
{
allocation = (*mgr->allocProc)( mgr, mgr->customValue,
allocationSize, flags );
}
if ( IsntNull( allocation ) )
{
DataHeader * header = NULL;
if ( (flags & kPGPMemoryMgrFlags_Clear ) != 0 )
{
pgpClearMemory( allocation, allocationSize );
}
else
{
pgpDebugWhackMemory( allocation, allocationSize );
}
header = (DataHeader *)allocation;
sInitDataHeader( mgr, requestSize, header );
allocation = HeaderToUserBlock( allocation );
AssertBlockValid( allocation );
sAddToLeaksList( mgr, header );
}
return( allocation );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -