mirror of
https://github.com/google/pebble.git
synced 2025-03-15 08:41:21 +00:00
309 lines
8.8 KiB
C
309 lines
8.8 KiB
C
|
|
||
|
/*
|
||
|
* DUMA - Red-Zone memory allocator.
|
||
|
* Copyright (C) 2002-2005 Hayati Ayguen <h_ayguen@web.de>, Procitec GmbH
|
||
|
* License: GNU LGPL (GNU Lesser General Public License, see COPYING-GPL)
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
* FILE CONTENTS:
|
||
|
* internal implementation file
|
||
|
* contains helper functions for DUMA
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* Function: reduceProtectedMemory
|
||
|
*
|
||
|
* delete reductionSizekB amount of memory, which has already
|
||
|
* been freed but got protected
|
||
|
* return != 0 when more memory reducable
|
||
|
*/
|
||
|
static int
|
||
|
reduceProtectedMemory( size_t reductionSizekB )
|
||
|
{
|
||
|
struct _DUMA_Slot * slot = _duma_g.allocList;
|
||
|
size_t count = _duma_s.slotCount;
|
||
|
size_t alreadyReducekB = 0;
|
||
|
|
||
|
#ifndef WIN32
|
||
|
/* Windows VirtualFree(,,MEM_RELEASE) can only free whole allocations. not parts */
|
||
|
|
||
|
size_t delSize, newSize;
|
||
|
|
||
|
/* 1- try reducing memory to just keep page(s) with userAddress */
|
||
|
for ( ; count > 0 && alreadyReducekB < reductionSizekB; --count, ++slot )
|
||
|
if ( DUMAST_ALL_PROTECTED == slot->state )
|
||
|
{
|
||
|
/* free memory above userAddr; keep userAddr protected */
|
||
|
newSize = (char*)slot->userAddress - (char*)slot->internalAddress;
|
||
|
newSize = (newSize + DUMA_PAGE_SIZE) & ~(DUMA_PAGE_SIZE -1);
|
||
|
delSize = slot->internalSize - newSize;
|
||
|
Page_Delete( (char*)slot->internalAddress + newSize, delSize );
|
||
|
alreadyReducekB += (delSize+1023) >>10;
|
||
|
slot->state = DUMAST_BEGIN_PROTECTED;
|
||
|
/* but keep the slot and userAddr */
|
||
|
slot->internalSize = newSize;
|
||
|
|
||
|
if ( alreadyReducekB >= reductionSizekB )
|
||
|
{
|
||
|
_duma_s.sumProtectedMem -= alreadyReducekB;
|
||
|
_duma_s.sumAllocatedMem -= alreadyReducekB;
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
/* 2- deallocate all page(s) with userAddress, empty whole slot */
|
||
|
slot = _duma_g.allocList;
|
||
|
count = _duma_s.slotCount;
|
||
|
for ( ; count > 0 && alreadyReducekB < reductionSizekB; --count, ++slot )
|
||
|
if ( DUMAST_BEGIN_PROTECTED == slot->state
|
||
|
#if defined(WIN32)
|
||
|
|| DUMAST_ALL_PROTECTED == slot->state
|
||
|
#endif
|
||
|
)
|
||
|
{
|
||
|
/* free all the memory */
|
||
|
Page_Delete(slot->internalAddress, slot->internalSize);
|
||
|
alreadyReducekB += (slot->internalSize+1023) >>10;
|
||
|
/* free slot and userAddr */
|
||
|
slot->internalAddress = slot->userAddress = 0;
|
||
|
slot->internalSize = slot->userSize = 0;
|
||
|
slot->state = DUMAST_EMPTY;
|
||
|
slot->allocator = EFA_INT_ALLOC;
|
||
|
#ifndef DUMA_NO_LEAKDETECTION
|
||
|
slot->fileSource = DUMAFS_EMPTY;
|
||
|
slot->filename = 0;
|
||
|
slot->lineno = 0;
|
||
|
#endif
|
||
|
|
||
|
if ( alreadyReducekB >= reductionSizekB )
|
||
|
{
|
||
|
_duma_s.sumProtectedMem -= alreadyReducekB;
|
||
|
_duma_s.sumAllocatedMem -= alreadyReducekB;
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Function: slotForUserAddress
|
||
|
*
|
||
|
* Find the slot structure for a user address.
|
||
|
*/
|
||
|
static struct _DUMA_Slot *
|
||
|
slotForUserAddress(void * address)
|
||
|
{
|
||
|
struct _DUMA_Slot * slot = _duma_g.allocList;
|
||
|
size_t count = _duma_s.slotCount;
|
||
|
|
||
|
for ( ; count > 0; --count, ++slot )
|
||
|
if ( slot->userAddress == address )
|
||
|
return slot;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Function: nearestSlotForUserAddress
|
||
|
*
|
||
|
* Find the nearest slot structure for a user address.
|
||
|
*/
|
||
|
static struct _DUMA_Slot *
|
||
|
nearestSlotForUserAddress(void * userAddress)
|
||
|
{
|
||
|
struct _DUMA_Slot * slot = _duma_g.allocList;
|
||
|
size_t count = _duma_s.slotCount;
|
||
|
|
||
|
for ( ; count > 0; --count, ++slot )
|
||
|
if ( (char*)slot->internalAddress <= (char*)userAddress
|
||
|
&& (char*)userAddress <= (char*)slot->internalAddress + slot->internalSize
|
||
|
)
|
||
|
return slot;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
/* next to functions not needed so far .. */
|
||
|
|
||
|
/* Function: slotForInternalAddrNextTo
|
||
|
*
|
||
|
* Find the slot structure for an internal address.
|
||
|
*/
|
||
|
static struct _DUMA_Slot *
|
||
|
slotForInternalAddrNextTo(void * address)
|
||
|
{
|
||
|
struct _DUMA_Slot * slot = _duma_g.allocList;
|
||
|
size_t count = _duma_s.slotCount;
|
||
|
|
||
|
for ( ; count > 0; --count, ++slot )
|
||
|
if ( slot->internalAddress == address )
|
||
|
return slot;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Function: slotForInternalAddrPrevTo
|
||
|
*
|
||
|
* Given the internal address of a buffer, find the buffer immediately
|
||
|
* before that buffer in the address space. This is used by free() to
|
||
|
* coalesce two free buffers into one.
|
||
|
*/
|
||
|
static struct _DUMA_Slot *
|
||
|
slotForInternalAddrPrevTo(void * address)
|
||
|
{
|
||
|
struct _DUMA_Slot * slot = _duma_g.allocList;
|
||
|
size_t count = _duma_s.slotCount;
|
||
|
|
||
|
for ( ; count > 0; --count, ++slot )
|
||
|
if ( (char*)slot->internalAddress + slot->internalSize == address )
|
||
|
return slot;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* Function: _duma_init_slack
|
||
|
*
|
||
|
* Initialise the no mans land, for a given slot
|
||
|
*/
|
||
|
static
|
||
|
void _duma_init_slack( struct _DUMA_Slot * slot )
|
||
|
{
|
||
|
char * accBegAddr, * accEndAddr;
|
||
|
char * tmpBegAddr, * tmpEndAddr;
|
||
|
|
||
|
#ifdef DUMA_EXPLICIT_INIT
|
||
|
slot->slackfill = _duma_s.SLACKFILL;
|
||
|
#endif
|
||
|
|
||
|
/* nothing to do for zero userSize */
|
||
|
if ( !slot->userSize )
|
||
|
return;
|
||
|
|
||
|
/* calculate accessible non-protectable address area */
|
||
|
if ( (char*)slot->protAddress < (char*)slot->userAddress )
|
||
|
{
|
||
|
/* DUMA_PROTECT_BELOW was 1 when allocating this piece of memory */
|
||
|
accBegAddr = (char*)slot->userAddress;
|
||
|
accEndAddr = (char*)slot->internalAddress + slot->internalSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* DUMA_PROTECT_BELOW was 0 when allocating this piece of memory */
|
||
|
accBegAddr = (char*)slot->internalAddress;
|
||
|
accEndAddr = (char*)slot->protAddress;
|
||
|
}
|
||
|
|
||
|
tmpBegAddr = accBegAddr;
|
||
|
tmpEndAddr = (char*)slot->userAddress;
|
||
|
while (tmpBegAddr < tmpEndAddr)
|
||
|
*tmpBegAddr++ = (char)_duma_s.SLACKFILL;
|
||
|
|
||
|
tmpBegAddr = (char*)slot->userAddress + slot->userSize;
|
||
|
tmpEndAddr = accEndAddr;
|
||
|
while (tmpBegAddr < tmpEndAddr)
|
||
|
*tmpBegAddr++ = (char)_duma_s.SLACKFILL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Function: _duma_check_slack
|
||
|
*
|
||
|
* Checks the integrity of no mans land, for a given slot
|
||
|
*/
|
||
|
static
|
||
|
void _duma_check_slack( struct _DUMA_Slot * slot )
|
||
|
{
|
||
|
char * accBegAddr, * accEndAddr;
|
||
|
char * tmpBegAddr, * tmpEndAddr;
|
||
|
char slackfill;
|
||
|
#ifdef DUMA_EXPLICIT_INIT
|
||
|
slackfill = (char)slot->slackfill;
|
||
|
#else
|
||
|
slackfill = (char)_duma_s.SLACKFILL;
|
||
|
#endif
|
||
|
|
||
|
/* nothing to do for zero userSize */
|
||
|
if ( !slot->userSize )
|
||
|
return;
|
||
|
|
||
|
/* calculate accessible non-protectable address area */
|
||
|
if ( (char*)slot->protAddress < (char*)slot->userAddress )
|
||
|
{
|
||
|
/* DUMA_PROTECT_BELOW was 1 when allocating this piece of memory */
|
||
|
accBegAddr = (char*)slot->userAddress;
|
||
|
accEndAddr = (char*)slot->internalAddress + slot->internalSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* DUMA_PROTECT_BELOW was 0 when allocating this piece of memory */
|
||
|
accBegAddr = (char*)slot->internalAddress;
|
||
|
accEndAddr = (char*)slot->protAddress;
|
||
|
}
|
||
|
|
||
|
tmpBegAddr = accBegAddr;
|
||
|
tmpEndAddr = (char*)slot->userAddress;
|
||
|
while (tmpBegAddr < tmpEndAddr)
|
||
|
{
|
||
|
if ( (char)slackfill != *tmpBegAddr++ )
|
||
|
{
|
||
|
#ifndef DUMA_NO_LEAKDETECTION
|
||
|
DUMA_Abort("ptr=%a: detected overwrite of ptrs no mans land below userSpace, size=%d alloced from %s(%i)",
|
||
|
(DUMA_ADDR)slot->userAddress, (DUMA_SIZE)slot->userSize, slot->filename, slot->lineno);
|
||
|
#else
|
||
|
DUMA_Abort("ptr=%a: detected overwrite of ptrs no mans land below userSpace", (DUMA_ADDR)slot->userAddress);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tmpBegAddr = (char*)slot->userAddress + slot->userSize;
|
||
|
tmpEndAddr = accEndAddr;
|
||
|
while (tmpBegAddr < tmpEndAddr)
|
||
|
{
|
||
|
if ( (char)slackfill != *tmpBegAddr++ )
|
||
|
{
|
||
|
#ifndef DUMA_NO_LEAKDETECTION
|
||
|
DUMA_Abort("detected overwrite of no mans land above userSpace: ptr=%a, size=%d\nalloced from %s(%i)",
|
||
|
(DUMA_ADDR)slot->userAddress, (DUMA_SIZE)slot->userSize, slot->filename, slot->lineno);
|
||
|
#else
|
||
|
DUMA_Abort("detected overwrite of no mans land above userSpace: ptr=%a", (DUMA_ADDR)slot->userAddress);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Function: _duma_check_all_slacks
|
||
|
*
|
||
|
* Checks the integrity of all no mans land
|
||
|
*/
|
||
|
static void
|
||
|
_duma_check_all_slacks( void )
|
||
|
{
|
||
|
struct _DUMA_Slot * slot = _duma_g.allocList;
|
||
|
size_t count = _duma_s.slotCount;
|
||
|
|
||
|
for ( ; count > 0; --count, ++slot )
|
||
|
{
|
||
|
/* CHECK INTEGRITY OF NO MANS LAND */
|
||
|
if ( DUMAST_IN_USE == slot->state && slot->userSize )
|
||
|
_duma_check_slack( slot );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// end
|