123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353 |
- /*
- * KDUMA - Kernel Mode Red-Zone memory allocator.
- * Copyright (C) 2006 Michael Eddington <meddington@gmail.com>
- * Copyright (C) 2006 Eric Rachner <eric@rachner.us>
- * Copyright (C) 2002-2005 Hayati Ayguen <h_ayguen@web.de>, Procitec GmbH
- * Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>
- * License: GNU GPL (GNU General Public License, see COPYING-GPL)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- /* $Id$ */
- /* Variable: version
- *
- * KDUMA version string
- */
- static const char version[] =
- "KDUMA v0.1 -- Kernel Mode Red-Zone Memory Allocator\n"
- " Copyright (C) 2006 Michael Eddington\n"
- " Copyright (C) 2006 Eric Rachner\n"
- " Copyright (C) 2002-2005 Hayati Ayguen <h_ayguen@web.de>, Procitec GmbH\n"
- " Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>\n"
- " License: GNU GPL (GNU General Public License, see COPYING-GPL)\n";
- /* Variable: MEMORY_CREATION_SIZE
- *
- * MEMORY_CREATION_SIZE is the amount of memory to get from the operating
- * system at one time. We'll break that memory down into smaller pieces for
- * malloc buffers. One megabyte is probably a good value.
- */
- #define MEMORY_CREATION_SIZE 1024 * 1024
- /* Enum: _DUMA_SlotState
- *
- * State of slot values (empty, free, etc)
- */
- enum _DUMA_SlotState
- {
- DUMAST_EMPTY /* slot not in use */
- , DUMAST_FREE /* internal memory reserved, unused by user */
- , DUMAST_IN_USE /* memory in use by allocator; see following enum AllocType */
- , DUMAST_ALL_PROTECTED /* memory no more used by allocator; memory is not deallocated but protected */
- , DUMAST_BEGIN_PROTECTED /* most memory deallocated, but not page covering userAddress:
- * slot holds userAddress, userSize and allocator.
- */
- };
- /* Enum: _DUMA_Slot_FileSource
- *
- * Where did we get file info
- */
- enum _DUMA_Slot_FileSource
- {
- DUMAFS_EMPTY /* no filename, lineno */
- , DUMAFS_ALLOCATION /* filename, lineno from allocation */
- , DUMAFS_DEALLOCATION /* filename, lineno from deallocation */
- };
- /* Enum: _DUMA_InitState
- *
- * Whats are initialization start
- */
- enum _DUMA_InitState
- {
- DUMAIS_UNINITIALIZED = 0x1611 /* not initialized */
- , DUMAIS_IN_CONSTRUCTOR /* in constructor _duma_init() */
- , DUMAIS_OUT_CONSTRUCTOR /* construction _duma_init() finished */
- , DUMAIS_IN_INIT /* in initializer duma_init() */
- , DUMAIS_OUT_INIT /* initialization duma_init() finished */
- };
- /* Enum: _DUMA_MemRegion
- *
- * Memory region of slot. Really we should only
- * hang onto NORMAL memory. DMA should be released
- * fast.
- */
- enum _DUMA_MemRegion
- {
- DUMAMR_DMA,
- DUMAMR_NORMAL,
- DUMAMR_HIGH
- }
- /* Struct: _DUMA_Slot
- *
- * Struct Slot contains all of the information about a malloc buffer except
- * for the contents of its memory.
- */
- struct _DUMA_Slot
- {
- void *internalAddress;
- void *userAddress;
- void *protAddress;
- size_t internalSize;
- size_t userSize;
- /* save (some) space in production */
- unsigned short state :16;
- unsigned short allocator :8;
- unsigned short fileSource :8;
- #ifdef DUMA_USE_FRAMENO
- int frame;
- #endif
- char *filename; /* filename of allocation */
- int lineno; /* linenumber of allocation */
- #endif
- #ifdef DUMA_EXPLICIT_INIT
- int slackfill;
- #endif
- };
- /* Variable: DUMA_ALIGNMENT
- *
- * DUMA_ALIGNMENT is a global variable used to control the default alignment
- * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps
- * so that its name matches the name of the environment variable that is used
- * to set it. This gives the programmer one less name to remember.
- */
- size_t DUMA_ALIGNMENT = DUMA_MIN_ALIGNMENT;
- /* Variable: DUMA_PROTECT_BELOW
- *
- * DUMA_PROTECT_BELOW is used to modify the behavior of the allocator. When
- * its value is non-zero, the allocator will place an inaccessable page
- * immediately _before_ the malloc buffer in the address space, instead
- * of _after_ it. Use this to detect malloc buffer under-runs, rather than
- * over-runs. It won't detect both at the same time, so you should test your
- * software twice, once with this value clear, and once with it set.
- */
- int DUMA_PROTECT_BELOW = 0;
- /* Variable: DUMA_FILL
- *
- * DUMA_FILL is set to 0-255 if DUMA should fill all new allocated
- * memory with the specified value. Set to -1 when DUMA should not
- * initialise allocated memory.
- * default is set to initialise with 255, cause many programs rely on
- * initialisation to 0!
- */
- int DUMA_FILL = 255;
- /* Variable: DUMA_SLACKFILL
- *
- * DUMA_SLACKFILL is set to 0-255. The slack / no mans land of all new allocated
- * memory is filled with the specified value.
- * default is set to initialise with 0xAA (=binary 10101010)
- * initialisation to 0!
- */
- static int DUMA_SLACKFILL = 0xAA;
- /* Variable: DUMA_PROTECT_FREE
- *
- * DUMA_PROTECT_FREE is used to control the disposition of memory that is
- * released using free(). It is all-caps so that its name
- * matches the name of the environment variable that is used to set it.
- * If its value is non-zero, memory released by free is made inaccessable.
- * Any software that touches free memory will then get a segmentation fault.
- * Depending on your application and your resources you may tell
- * DUMA not to use this memory ever again by setting a negative
- * value f.e. -1.
- * You can tell DUMA to limit the sum of protected memory by setting
- * a positive value, which is interpreted in kB.
- * If its value is zero, freed memory will be available for reallocation,
- * but will still be inaccessable until it is reallocated.
- */
- static long DUMA_PROTECT_FREE = -1L;
- /* Variable: DUMA_MAX_ALLOC
- *
- * DUMA_MAX_ALLOC is used to control the maximum memory print of the program
- * in total: When the sum of allocated and protected memory would exceed
- * this value in kB, the protected memory is freed/deleted.
- */
- static long DUMA_MAX_ALLOC = -1L;
- /* Variable: DUMA_ALLOW_MALLOC_0
- *
- * DUMA_ALLOW_MALLOC_0 is set if DUMA is to allow malloc(0). I
- * trap malloc(0) by default because it is a common source of bugs.
- * But you should know the allocation with size 0 is ANSI conform.
- */
- static int DUMA_ALLOW_MALLOC_0 = 1;
- /* Variable: DUMA_MALLOC_FAILEXIT
- *
- * DUMA_MALLOC_FAILEXIT controls the behaviour of DUMA when
- * malloc() fails and would return NULL. But most applications don't
- * check the return value for errors ... so
- * default to Exit on Fail
- */
- static int DUMA_MALLOC_FAILEXIT = 1;
- /* Variable: DUMA_FREE_ACCESS
- *
- * DUMA_FREE_ACCESS is set if DUMA is to write access memory before
- * freeing it. This makes easier using watch expressions in debuggers as the
- * process is interrupted even if the memory is going to be freed.
- */
- static int DUMA_FREE_ACCESS = 0;
- /* Variable: DUMA_SHOW_ALLOC
- *
- * DUMA_SHOW_ALLOC is set if DUMA is to print all allocations
- * and deallocations to the console. Although this generates a lot
- * of messages, the option can be useful to detect inefficient code
- * containing many allocations / deallocations
- */
- static int DUMA_SHOW_ALLOC = 0;
- /* Variable: _duma_allocList
- *
- * _DUMA_allocList points to the array of slot structures used to manage the
- * malloc arena.
- */
- struct _DUMA_Slot * _duma_allocList = 0;
- /* Variable: _duma_allocListSize
- *
- * _duma_allocListSize is the size of the allocation list. This will always
- * be a multiple of the page size.
- */
- static size_t _duma_allocListSize = 0;
- /* Variable: slotCount
- *
- * slotCount is the number of Slot structures in allocationList.
- */
- static size_t slotCount = 0;
- /* Variable: unUsedSlots
- *
- * unUsedSlots is the number of Slot structures that are currently available
- * to represent new malloc buffers. When this number gets too low, we will
- * create new slots.
- */
- static size_t unUsedSlots = 0;
- /* Variable: slotsPerPage
- *
- * slotsPerPage is the number of slot structures that fit in a virtual
- * memory page.
- */
- static size_t slotsPerPage = 0;
- /* Variable: sumAllocatedMem
- *
- * internal variable: sum of allocated -freed +protected memory in kB
- */
- static long sumAllocatedMem = 0;
- /* Variable: sumTotalAllocatedMem
- *
- * internal variable: sum of allocated memory in kB
- */
- static long sumTotalAllocatedMem = 0;
- /* Variable: sumProtectedMem
- *
- * internal variable: sum of protected memory in kB
- */
- static long sumProtectedMem = 0;
- /* Variable: numDeallocs
- *
- * internal variable: number of deallocations processed so far
- */
- static long numDeallocs = 0;
- /* Variable: numAllocs
- *
- * internal variable: number of allocations processed so far
- */
- static long numAllocs = 0;
- /* Variable: duma_init_done
- *
- * internal variable: state of initialization
- */
- static enum _DUMA_InitState duma_init_state = DUMAIS_UNINITIALIZED;
- /* Function: _duma_assert
- *
- * Print message and halt program execution in crazy way.
- */
- void _duma_assert(const char * exprstr, const char * filename, int lineno)
- {
- // !!!! Needs to be re implemented for KDUMA
- int *pcAddr = 0;
- DUMA_Print("\nDUMA: DUMA_ASSERT(%s) failed at\n%s(%i)\n", exprstr, filename, lineno );
- /* this is "really" bad, but it works. assert() from assert.h system header
- * stops only the current thread but the program goes on running under MS Visual C++.
- * This way the program definitely halts.
- */
- while (1)
- *pcAddr++ = 0;
- }
- /* Function: duma_init
- *
- * duma_init sets configuration settings. Can sometimes cause problems
- * when called from _duma_init.
- *
- * See Also: <_duma_init>
- */
- void duma_init(void)
- {
- char * string;
- void * testAlloc;
- /* avoid double call, when initialization already in progress */
- if ( duma_init_state >= DUMAIS_IN_INIT && duma_init_state <= DUMAIS_OUT_INIT )
- return;
- else
- duma_init_state = DUMAIS_IN_INIT;
- DUMA_Print(version);
- DUMA_Print("DUMA: Registration was successful.\n");
- /* initialize semaphoring */
- DUMA_INIT_SEMAPHORE();
- /*
- * Check whether malloc and free is available
- */
- testAlloc = kmalloc(123);
- if (numAllocs == 0)
- DUMA_Abort("kmalloc() is not bound to kduma.\nKDUMA Aborting.\n");
- kfree(testAlloc);
- if (numDeallocs == 0)
- DUMA_Abort("kfree() is not bound to kduma.\nKDUMA Aborting.\n");
- /* initialization finished */
- duma_init_state = DUMAIS_OUT_INIT;
- }
- /* Function: _duma_init
- *
- * _duma_init sets up the memory allocation arena and the run-time
- * configuration information. We will call duma_init unless DUMA_EXPLICIT_INIT
- * is defined at compile time.
- *
- * See Also: <duma_init>
- */
- void
- _duma_init(void)
- {
- size_t size = MEMORY_CREATION_SIZE;
- struct _DUMA_Slot * slot;
- int inRecursion = (duma_init_state >= DUMAIS_IN_CONSTRUCTOR && duma_init_state <= DUMAIS_OUT_INIT);
- /* constuction already done? this should not happen! */
- if (duma_init_state >= DUMAIS_OUT_CONSTRUCTOR && duma_init_state <= DUMAIS_OUT_INIT)
- goto duma_constructor_callinit;
- else
- duma_init_state = DUMAIS_IN_CONSTRUCTOR;
- if ( DUMA_PAGE_SIZE != Page_Size() )
- DUMA_Abort("DUMA_PAGE_SIZE is not correct. Run createconf and save results as duma_config.h");
- if(!inRecursion)
- DUMA_GET_SEMAPHORE();
- /* call of DUMA_GET_SEMAPHORE() may already have done the construction recursively! */
- if ( duma_init_state >= DUMAIS_OUT_CONSTRUCTOR )
- goto duma_constructor_relsem;
- /*
- * Figure out how many Slot structures to allocate at one time.
- */
- slotCount = slotsPerPage = DUMA_PAGE_SIZE / sizeof(struct _DUMA_Slot);
- _duma_allocListSize = DUMA_PAGE_SIZE;
- if ( size < _duma_allocListSize )
- size = _duma_allocListSize;
- size = ( size + DUMA_PAGE_SIZE -1 ) & ~( DUMA_PAGE_SIZE -1 );
- /*
- * Allocate memory, and break it up into two malloc buffers. The
- * first buffer will be used for Slot structures, the second will
- * be marked free.
- */
- slot = _duma_allocList = (struct _DUMA_Slot *)Page_Create(size, 0/*=exitonfail*/, 0/*=printerror*/);
- if ( 0 == _duma_allocList && 0L != DUMA_PROTECT_FREE )
- {
- int reduce_more;
- do
- {
- /* reduce as much protected memory as we need - or at least try so */
- reduce_more = reduceProtectedMemory( (size+1023) >>10 );
- /* simply try again */
- slot = _duma_allocList = (struct _DUMA_Slot *)Page_Create( size, 0/*=exitonfail*/, 0/*= printerror*/ );
- }
- while ( reduce_more && 0 == _duma_allocList );
- if ( 0 == _duma_allocList )
- slot = _duma_allocList = (struct _DUMA_Slot *)Page_Create( size, 1/*=exitonfail*/, 1/*= printerror*/ );
- }
- memset((char *)_duma_allocList, 0, _duma_allocListSize);
- /* enter _duma_allocList as slot to allow call to free() when doing allocateMoreSlots() */
- slot[0].internalAddress = slot[0].userAddress = _duma_allocList;
- slot[0].internalSize = slot[0].userSize = _duma_allocListSize;
- slot[0].state = DUMAST_IN_USE;
- slot[0].allocator = EFA_INT_ALLOC;
- slot[0].fileSource = DUMAFS_ALLOCATION;
- #ifdef DUMA_USE_FRAMENO
- slot[0].frame = 0;
- #endif
- slot[0].filename = __FILE__;
- slot[0].lineno = __LINE__;
- #endif
- if ( size > _duma_allocListSize )
- {
- slot[1].internalAddress = slot[1].userAddress
- = ((char *)slot[0].internalAddress) + slot[0].internalSize;
- slot[1].internalSize = slot[1].userSize
- = size - slot[0].internalSize;
- slot[1].state = DUMAST_FREE;
- slot[1].allocator = EFA_INT_ALLOC;
- slot[1].fileSource = DUMAFS_ALLOCATION;
- #ifdef DUMA_USE_FRAMENO
- slot[1].frame = 0;
- #endif
- slot[1].filename = __FILE__;
- slot[1].lineno = __LINE__;
- #endif
- }
- /*
- * Deny access to the free page, so that we will detect any software
- * that treads upon free memory.
- */
- Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);
- /*
- * Account for the two slot structures that we've used.
- */
- unUsedSlots = slotCount - 2;
- /* construction done */
- if ( duma_init_state < DUMAIS_OUT_CONSTRUCTOR )
- duma_init_state = DUMAIS_OUT_CONSTRUCTOR;
- /***********************/
- duma_constructor_relsem:
- if ( !inRecursion )
- DUMA_RELEASE_SEMAPHORE();
- /*************************/
- duma_constructor_callinit:
- if ( duma_init_state < DUMAIS_OUT_INIT )
- duma_init();
- }
- /* Function: allocateMoreSlots
- *
- * allocateMoreSlots is called when there are only enough slot structures
- * left to support the allocation of a single malloc buffer.
- *
- * See Also: <_duma_allocate>
- */
- static void allocateMoreSlots(void)
- {
- size_t newSize = _duma_allocListSize + DUMA_PAGE_SIZE;
- void * newAllocation;
- void * oldAllocation = _duma_allocList;
- newAllocation = _duma_allocate( 1 /*=alignment*/, newSize,
- 0 /*=protectBelow*/, -1 /*=fillByte*/, 0 /*=protectAllocList*/,
- EFA_INT_ALLOC, DUMA_FAIL_NULL, __FILE__, __LINE__ );
- if ( ! newAllocation )
- return;
- memcpy(newAllocation, _duma_allocList, _duma_allocListSize);
- memset(&(((char *)newAllocation)[_duma_allocListSize]), 0, DUMA_PAGE_SIZE);
- _duma_allocList = (struct _DUMA_Slot *)newAllocation;
- _duma_allocListSize = newSize;
- slotCount += slotsPerPage;
- unUsedSlots += slotsPerPage;
- #ifndef DUMA_NO_LEAKDETECTION
- _duma_deallocate( oldAllocation, 0 /*=protectAllocList*/, EFA_INT_DEALLOC, __FILE__, __LINE__ );
- #else
- _duma_deallocate( oldAllocation, 0 /*=protectAllocList*/, EFA_INT_DEALLOC);
- #endif
- }
- /* Function: _duma_allocate
- *
- * This is the memory allocator. When asked to allocate a buffer, allocate
- * it in such a way that the end of the buffer is followed by an inaccessable
- * memory page. If software overruns that buffer, it will touch the bad page
- * and get an immediate segmentation fault. It's then easy to zero in on the
- * offending code with a debugger.
- *
- * There are a few complications. If the user asks for an odd-sized buffer,
- * we would have to have that buffer start on an odd address if the byte after
- * the end of the buffer was to be on the inaccessable page. Unfortunately,
- * there is lots of software that asks for odd-sized buffers and then
- * requires that the returned address be word-aligned, or the size of the
- * buffer be a multiple of the word size. An example are the string-processing
- * functions on Sun systems, which do word references to the string memory
- * and may refer to memory up to three bytes beyond the end of the string.
- * For this reason, I take the alignment requests to memalign() and valloc()
- * seriously, and
- *
- * DUMA wastes lots of memory.
- *
- * See Also: <_duma_deallocate>
- */
- void * _duma_allocate(size_t alignment, size_t userSize, int protectBelow,
- int fillByte, int protectAllocList, enum _DUMA_Allocator allocator, enum _DUMA_FailReturn fail DUMA_PARAMLIST_FL)
- {
- size_t count;
- struct _DUMA_Slot *slot;
- struct _DUMA_Slot *fullSlot;
- struct _DUMA_Slot *emptySlots[2];
- DUMA_ADDR intAddr, userAddr, protAddr, endAddr;
- size_t internalSize;
- char stacktrace[601];
- char* ptrStacktrace;
- DUMA_ASSERT( 0 != _duma_allocList );
- /* initialize return value */
- userAddr = 0;
- /* check userSize */
- if ( 0 == userSize )
- {
- if ( !DUMA_ALLOW_MALLOC_0 )
- {
- DUMA_Abort("Allocating 0 bytes, probably a bug: %s(%i)", filename, lineno);
- }
- else
- return (void*)userAddr;
- }
- /* check alignment */
- if ( ! alignment )
- {
- DUMA_SIZE a = (DUMA_SIZE)DUMA_ALIGNMENT;
- DUMA_SIZE s = (DUMA_SIZE)userSize;
- if ( s < a )
- {
- /* to next lower power of 2 */
- for (a = s; a & (a-1); a &= a-1) ;
- }
- alignment = (size_t)a; /* this is new alignment */
- }
- if ( (int)alignment != ((int)alignment & -(int)alignment) )
- {
- #ifndef DUMA_NO_LEAKDETECTION
- DUMA_Abort("Alignment (=%d) is not a power of 2 requested from %s(%i)", (DUMA_SIZE)alignment, filename, lineno);
- #else
- DUMA_Abort("Alignment (=%d) is not a power of 2", (DUMA_SIZE)alignment);
- #endif
- }
- /* count and show allocation, if requested */
- numAllocs++;
- if (DUMA_SHOW_ALLOC)
- {
- #ifndef DUMA_NO_LEAKDETECTION
- DUMA_Print("\nDUMA: Allocating %d bytes at %s(%i).", (DUMA_SIZE)userSize, filename, lineno);
- #else
- DUMA_Print("\nDUMA: Allocating %d bytes.", (DUMA_SIZE)userSize);
- #endif
- }
- /*
- * If protectBelow is set, all addresses returned by malloc()
- * and company will be page-aligned.
- *
- * The internal size of the buffer is rounded up to the next alignment and page-size
- * boundary, and then we add another page's worth of memory for the dead page.
- */
- /* a bit tricky but no modulo and no if () */
- internalSize = ( (userSize + DUMA_PAGE_SIZE -1) & ~(DUMA_PAGE_SIZE -1) ) + DUMA_PAGE_SIZE;
- if ( alignment > DUMA_PAGE_SIZE )
- internalSize += alignment - DUMA_PAGE_SIZE;
- /*
- * These will hold the addresses of two empty Slot structures, that
- * can be used to hold information for any memory I create, and any
- * memory that I mark free.
- */
- fullSlot = emptySlots[0] = emptySlots[1] = 0;
- /*
- * The internal memory used by the allocator is currently
- * inaccessable, so that errant programs won't scrawl on the
- * allocator's arena. I'll un-protect it here so that I can make
- * a new allocation. I'll re-protect it before I return.
- */
- if ( protectAllocList )
- {
- IF__DUMA_INIT_DONE
- DUMA_GET_SEMAPHORE();
- Page_AllowAccess(_duma_allocList, _duma_allocListSize);
- }
- /*
- * If I'm running out of empty slots, create some more before
- * I don't have enough slots left to make an allocation.
- */
- if ( DUMAAT_INTERNAL != _duma_allocDesc[allocator].type && unUsedSlots < 7 )
- allocateMoreSlots();
- /*
- * Iterate through all of the slot structures. Attempt to find a slot
- * containing free memory of the exact right size. Accept a slot with
- * more memory than we want, if the exact right size is not available.
- * Find two slot structures that are not in use. We will need one if
- * we split a buffer into free and allocated parts, and the second if
- * we have to create new memory and mark it as free.
- *
- */
- for ( slot = _duma_allocList, count = slotCount ; count > 0; --count, ++slot )
- {
- /*
- * Windows needs special treatment, cause Page_Delete() needs exactly
- * the same memory region as Page_Create()!
- * Thus as a quick hack no memory management is done by DUMA.
- */
- #if !defined(WIN32)
- if ( DUMAST_FREE == slot->state && slot->internalSize >= internalSize )
- {
- if ( !fullSlot || slot->internalSize < fullSlot->internalSize )
- {
- fullSlot = slot;
- if ( slot->internalSize == internalSize )
- break; /* All done; no empty slot needed in this case */
- }
- }
- else
- #endif
- if ( DUMAST_EMPTY == slot->state )
- {
- if(!emptySlots[0])
- emptySlots[0] = slot;
- else if ( !emptySlots[1] )
- emptySlots[1] = slot;
- #if defined(WIN32)
- break;
- #endif
- }
- }
- if ( !fullSlot )
- {
- /*
- * I get here if I haven't been able to find a free buffer
- * with all of the memory I need. I'll have to create more
- * memory. I'll mark it all as free, and then split it into
- * free and allocated portions later.
- */
- size_t chunkSize;
- size_t chunkSizekB;
- #if defined(WIN32)
- chunkSize = internalSize;
- #else
- chunkSize = MEMORY_CREATION_SIZE;
- if ( chunkSize < internalSize )
- chunkSize = internalSize;
- chunkSize = ( chunkSize + DUMA_PAGE_SIZE -1 ) & ~( DUMA_PAGE_SIZE -1 );
- #endif
- chunkSizekB = (chunkSize+1023) >>10;
- /* Use up one of the empty slots to make the full slot. */
- if ( !emptySlots[0] )
- DUMA_Abort("Internal error in allocator: No empty slot 0.\n");
- #if !defined(WIN32)
- if ( !emptySlots[1] )
- DUMA_Abort("Internal error in allocator: No empty slot 1.\n");
- #endif
- fullSlot = emptySlots[0];
- emptySlots[0] = emptySlots[1];
- /* reduce protected memory when we would exceed DUMA_MAX_ALLOC */
- if ( DUMA_MAX_ALLOC > 0 && sumAllocatedMem + chunkSizekB > DUMA_MAX_ALLOC )
- reduceProtectedMemory( chunkSizekB );
- fullSlot->internalAddress = Page_Create( chunkSize, 0/*= exitonfail*/, 0/*= printerror*/ );
- if ( 0 == fullSlot->internalAddress && 0L != DUMA_PROTECT_FREE )
- {
- int reduce_more;
- do
- {
- /* reduce as much protected memory as we need - or at least try so */
- reduce_more = reduceProtectedMemory( (chunkSize+1023) >>10 );
- /* simply try again */
- fullSlot->internalAddress = Page_Create( chunkSize, 0/*= exitonfail*/, 0/*= printerror*/ );
- }
- while ( reduce_more && 0 == fullSlot->internalAddress );
- if ( 0 == fullSlot->internalAddress && DUMA_FAIL_ENV == fail )
- fullSlot->internalAddress = Page_Create( chunkSize, DUMA_MALLOC_FAILEXIT, 1/*= printerror*/ );
- }
- if ( fullSlot->internalAddress )
- {
- sumAllocatedMem += ( (chunkSize +1023) >>10 );
- sumTotalAllocatedMem += ( (chunkSize +1023) >>10 );
- fullSlot->internalSize = chunkSize;
- fullSlot->state = DUMAST_FREE;
- --unUsedSlots;
- }
- } /* end if ( !fullSlot ) */
- if ( fullSlot->internalSize )
- {
- if ( !protectBelow )
- {
- /*
- * Arrange the buffer so that it is followed by an inaccessable
- * memory page. A buffer overrun that touches that page will
- * cause a segmentation fault.
- * internalAddr <= userAddr < protectedAddr
- */
- /* Figure out what address to give the user. */
- intAddr = (DUMA_ADDR)fullSlot->internalAddress;
- endAddr = intAddr + internalSize;
- userAddr = ( intAddr + internalSize - DUMA_PAGE_SIZE - userSize )
- & ~(alignment -1);
- protAddr = ( userAddr + userSize + DUMA_PAGE_SIZE -1)
- & ~(DUMA_PAGE_SIZE -1);
- /* DUMA_ASSERT(intAddr <= userAddr && intAddr < protAddr ); */
- /* Set up the "live" page(s). */
- Page_AllowAccess( (char*)intAddr, protAddr - intAddr );
- /* Set up the "dead" page(s). */
- Page_DenyAccess( (char*)protAddr, endAddr - protAddr );
- }
- else /* if (protectBelow) */
- {
- /*
- * Arrange the buffer so that it is preceded by an inaccessable
- * memory page. A buffer underrun that touches that page will
- * cause a segmentation fault.
- */
- /* Figure out what address to give the user. */
- intAddr = (DUMA_ADDR)fullSlot->internalAddress;
- endAddr = intAddr + internalSize;
- userAddr = ( intAddr + DUMA_PAGE_SIZE + alignment -1)
- & ~(alignment -1);
- protAddr = ( userAddr & ~(DUMA_PAGE_SIZE -1) ) - DUMA_PAGE_SIZE;
- /* DUMA_ASSERT(intAddr < userAddr && intAddr <= protAddr ); */
- /* Set up the "live" page(s). userAddr == protAddr + DUMA_PAGE_SIZE ! */
- Page_AllowAccess( (char*)userAddr, internalSize - (userAddr - protAddr) );
- /* Set up the "dead" page(s). */
- Page_DenyAccess( (char*)intAddr, userAddr - intAddr );
- }
- /* => userAddress = internalAddress + DUMA_PAGE_SIZE */
- fullSlot->userAddress = (char*)userAddr;
- fullSlot->protAddress = (char*)protAddr;
- fullSlot->userSize = userSize;
- fullSlot->state = DUMAST_IN_USE;
- fullSlot->allocator = allocator;
- #ifndef DUMA_NO_LEAKDETECTION
- fullSlot->fileSource = DUMAFS_ALLOCATION;
- #ifdef DUMA_USE_FRAMENO
- fullSlot->frame = frameno;
- #endif
- fullSlot->filename = (char*)filename;
- #ifdef DUMA_EXPLICIT_INIT
- /* mark allocations from standard libraries
- * before duma_init() is finished with lineno = -1
- * to allow special treatment in leak_checking
- */
- fullSlot->lineno = (DUMAIS_OUT_INIT == duma_init_state) ? lineno : -1;
- #else
- fullSlot->lineno = lineno;
- #endif
- #endif
- /* initialise no mans land of slot */
- _duma_init_slack( fullSlot );
- } /* end if ( fullSlot->internalSize ) */
- /*
- * Make the pool's internal memory inaccessable, so that the program
- * being debugged can't stomp on it.
- */
- if ( protectAllocList )
- {
- Page_DenyAccess(_duma_allocList, _duma_allocListSize);
- IF__DUMA_INIT_DONE
- DUMA_RELEASE_SEMAPHORE();
- }
- /* Fill the memory if it was specified to do so. */
- if ( ((char*)userAddr) && fillByte != -1 )
- memset( (char*)userAddr, fillByte, userSize);
- return (char*)userAddr;
- }
- /* Function: _duma_deallocate
- *
- * Deallocate allocated memory after running some checks, then open
- * slot for use. Uses Page_Delete to free the underlying memory.
- *
- * See Also: <Page_Delete> <_duma_allocate>
- */
- void _duma_deallocate(void * address, int protectAllocList, enum _DUMA_Allocator allocator DUMA_PARAMLIST_FL)
- {
- struct _DUMA_Slot * slot;
- long internalSizekB;
- if ( 0 == _duma_allocList )
- {
- DUMA_Abort("free() called before first malloc().");
- }
- if ( 0 == address )
- return;
- if ( protectAllocList )
- {
- IF__DUMA_INIT_DONE
- DUMA_GET_SEMAPHORE();
- Page_AllowAccess(_duma_allocList, _duma_allocListSize);
- }
- if ( !(slot = slotForUserAddress(address)) )
- {
- if ( (slot = nearestSlotForUserAddress(address)) )
- {
- if ( DUMAFS_ALLOCATION == slot->fileSource )
- DUMA_Abort("free(%a): address not from DUMA or already freed. Address may be corrupted from %a allocated from %s(%i)",
- (DUMA_ADDR)address, (DUMA_ADDR)slot->userAddress, slot->filename, slot->lineno);
- else if ( DUMAFS_DEALLOCATION == slot->fileSource )
- DUMA_Abort("free(%a): address not from DUMA or already freed. Address may be corrupted from %a deallocated at %s(%i)",
- (DUMA_ADDR)address, (DUMA_ADDR)slot->userAddress, slot->filename, slot->lineno);
- else
- }
- else
- {
- DUMA_Abort("free(%a): address not from DUMA or already freed.", (DUMA_ADDR)address);
- }
- }
- if ( DUMAST_ALL_PROTECTED == slot->state || DUMAST_BEGIN_PROTECTED == slot->state )
- {
- if ( DUMAFS_ALLOCATION == slot->fileSource )
- DUMA_Abort("free(%a): memory already freed. allocated from %s(%i)",
- (DUMA_ADDR)address, slot->filename, slot->lineno);
- else if ( DUMAFS_DEALLOCATION == slot->fileSource )
- DUMA_Abort("free(%a): memory already freed at %s(%i)",
- (DUMA_ADDR)address, slot->filename, slot->lineno);
- else
- DUMA_Abort("free(%a): memory already freed.", (DUMA_ADDR)address);
- }
- else if ( _duma_allocDesc[slot->allocator].type != _duma_allocDesc[allocator].type )
- {
- if ( DUMAFS_ALLOCATION == slot->fileSource )
- DUMA_Abort("Free mismatch: allocator '%s' used at %s(%i)\n but deallocator '%s' called at %s(%i)!",
- _duma_allocDesc[slot->allocator].name, slot->filename, slot->lineno,
- _duma_allocDesc[allocator].name, filename, lineno );
- else if ( DUMAFS_DEALLOCATION == slot->fileSource )
- DUMA_Abort("Free mismatch: allocator '%s' used \nbut deallocator '%s' called at %s(%i)!",
- _duma_allocDesc[slot->allocator].name,
- _duma_allocDesc[allocator].name, filename, lineno );
- else
- DUMA_Abort("Free mismatch: allocator '%s' used but deallocator '%s' called!",
- _duma_allocDesc[slot->allocator].name, _duma_allocDesc[allocator].name );
- }
- /* count and show deallocation, if requested */
- numDeallocs++;
- if (DUMA_SHOW_ALLOC)
- DUMA_Print("\nDUMA: Freeing %d bytes at %s(%i) (Allocated from %s(%i)).",
- (DUMA_SIZE)slot->userSize, filename, lineno, slot->filename, slot->lineno);
- /* CHECK INTEGRITY OF NO MANS LAND */
- _duma_check_slack( slot );
- if ( DUMA_FREE_ACCESS )
- {
- volatile char *start = slot->userAddress;
- volatile char *cur;
- for (cur = (char*)slot->userAddress+slot->userSize; --cur >= start; )
- {
- char c = *cur;
- *cur = c-1;
- *cur = c;
- }
- }
- internalSizekB = (slot->internalSize+1023) >>10;
- /* protect memory, that nobody can access it */
- /* Free as much protected memory, that we can protect this one */
- /* is there need? and is there a way to free such much? */
- if ( DUMA_PROTECT_FREE > 0L
- && sumProtectedMem + internalSizekB > DUMA_PROTECT_FREE
- && internalSizekB < DUMA_PROTECT_FREE
- && sumProtectedMem >= internalSizekB)
- {
- reduceProtectedMemory( internalSizekB );
- }
- if (( EFA_INT_ALLOC != slot->allocator )
- && ( DUMA_PROTECT_FREE < 0L
- || ( DUMA_PROTECT_FREE > 0L
- && sumProtectedMem + internalSizekB <= DUMA_PROTECT_FREE
- ) )
- )
- {
- slot->state = DUMAST_ALL_PROTECTED;
- Page_DenyAccess(slot->internalAddress, slot->internalSize);
- sumProtectedMem += internalSizekB;
- if ( lineno )
- {
- slot->fileSource = DUMAFS_DEALLOCATION;
- slot->filename = (char*)filename;
- slot->lineno = lineno;
- }
- }
- else
- {
- /* free all the memory */
- Page_Delete(slot->internalAddress, slot->internalSize);
- sumAllocatedMem -= internalSizekB;
- /* free slot and userAddr */
- slot->internalAddress = slot->userAddress = 0;
- slot->internalSize = slot->userSize = 0;
- slot->state = DUMAST_EMPTY;
- slot->allocator = EFA_INT_ALLOC;
- slot->fileSource = DUMAFS_EMPTY;
- #ifdef DUMA_USE_FRAMENO
- slot->frame = 0;
- #endif
- slot->filename = 0;
- slot->lineno = 0;
- }
- if ( protectAllocList )
- {
- Page_DenyAccess(_duma_allocList, _duma_allocListSize);
- IF__DUMA_INIT_DONE
- DUMA_RELEASE_SEMAPHORE();
- }
- }
- /*********************************************************/
- /* Function: _duma_kmalloc
- *
- * A version of kmalloc.
- */
- void * _duma_kmalloc(size_t size, int flags DUMA_PARAMLIST_FL)
- {
- if ( _duma_allocList == 0 )
- _duma_init(); /* This sets DUMA_ALIGNMENT, DUMA_PROTECT_BELOW, DUMA_FILL, ... */
- return _duma_allocate(0, size, flags, DUMA_PROTECT_BELOW,
- DUMA_FILL, 1 /*=protectAllocList*/, EFA_MALLOC,
- DUMA_FAIL_ENV DUMA_PARAMS_FL);
- }
- /* Function: _duma_kfree
- *
- * A version of free.
- */
- void _duma_kfree(void * baseAdr DUMA_PARAMLIST_FL)
- {
- if ( _duma_allocList == 0 )
- _duma_init(); /* This sets DUMA_ALIGNMENT, DUMA_PROTECT_BELOW, DUMA_FILL, ... */
- _duma_deallocate(baseAdr, 1 /*=protectAllocList*/, EFA_FREE DUMA_PARAMS_FL);
- }
- /* Function: _duma_valloc
- *
- * A version of valloc.
- */
- void * _duma_valloc(size_t size DUMA_PARAMLIST_FL)
- {
- if ( _duma_allocList == 0 )
- _duma_init(); /* This sets DUMA_ALIGNMENT, DUMA_PROTECT_BELOW, DUMA_FILL, ... */
- return _duma_allocate(DUMA_PAGE_SIZE, size, DUMA_PROTECT_BELOW,
- DUMA_FILL, 1 /*=protectAllocList*/, EFA_VALLOC,
- DUMA_FAIL_ENV DUMA_PARAMS_FL);
- }
- /* Function: _duma_vfree
- *
- * A version of free.
- */
- void _duma_vfree(void * baseAdr DUMA_PARAMLIST_FL)
- {
- if ( _duma_allocList == 0 )
- _duma_init(); /* This sets DUMA_ALIGNMENT, DUMA_PROTECT_BELOW, DUMA_FILL, ... */
- _duma_deallocate(baseAdr, 1 /*=protectAllocList*/, EFA_FREE DUMA_PARAMS_FL);
- }
- /* Function: _duma_strdup
- *
- * A version of strdup.
- */
- char * _duma_strdup(const char * str DUMA_PARAMLIST_FL)
- {
- size_t size;
- char * dup;
- unsigned i;
- if ( _duma_allocList == 0 )
- _duma_init(); /* This sets DUMA_ALIGNMENT, DUMA_PROTECT_BELOW, DUMA_FILL, ... */
- size = 0;
- while (str[size])
- ++size;
- dup = _duma_allocate(0, size +1, DUMA_PROTECT_BELOW,
- -1 /*=fillByte*/, 1 /*=protectAllocList*/, EFA_STRDUP,
- DUMA_FAIL_ENV DUMA_PARAMS_FL);
- if (dup) /* if successful */
- for (i=0; i<=size; ++i) /* copy string */
- dup[i] = str[i];
- return dup;
- }
- /* Function: _duma_memcpy
- *
- * A version of memcpy that provides extra checks based on
- * information we know about HEAP.
- *
- * Currently the only check we perform is overlapping memory
- * regions. This should be expanded to include checking size
- * of dest to verify assumptions.
- */
- void * _duma_memcpy(void *dest, const void *src, size_t size DUMA_PARAMLIST_FL)
- {
- char * d = (char *)dest;
- const char * s = (const char *)src;
- unsigned i;
- if ( (s < d && d < s + size) || (d < s && s < d + size && !_duma_s.MEMCPY_OVERLAP) )
- DUMA_Abort("memcpy(%a, %a, %d): memory regions overlap.",
- (DUMA_ADDR)dest, (DUMA_ADDR)src, (DUMA_SIZE)size);
- for (i=0; i<size; ++i)
- d[i] = s[i];
- return dest;
- }
- /* Function: _duma_memmove
- *
- * An implementation of memmove is provied by Duma to prevent some optimized
- * memmove implementations from calling memcpy and generate false positive overlap
- * errors.
- */
- void * _duma_memmove(void *dest, const void *src, size_t size)
- {
- char * d = (char *)dest;
- const char * s = (const char *)src;
- if (d < s) {
- const char *end = src + size;
- while (s < end) {
- *d++ = *s++;
- }
- } else {
- d += size;
- s += size;
- while (s > (const char*)src) {
- *--d = *--s;
- }
- }
- return dest;
- }
- /* Function: _duma_strcpy
- *
- * A version of strcpy that provides extra checks based on
- * information we know about HEAP.
- *
- * Currently the only check we perform is overlapping memory
- * regions. This should be expanded to include checking size
- * of dest to verify assumptions.
- */
- char * _duma_strcpy(char *dest, const char *src DUMA_PARAMLIST_FL)
- {
- unsigned i;
- size_t size = strlen(src) +1;
- if ( src < dest && dest < src + size )
- DUMA_Abort("strcpy(%a, %a): memory regions overlap.", (DUMA_ADDR)dest, (DUMA_ADDR)src);
- for (i=0; i<size; ++i)
- dest[i] = src[i];
- return dest;
- }
- /* Function: _duma_strncpy
- *
- * A version of strncpy that provides extra checks based on
- * information we know about HEAP.
- *
- * Currently the only check we perform is overlapping memory
- * regions. This should be expanded to include checking size
- * of dest to verify assumptions.
- */
- char * _duma_strncpy(char *dest, const char *src, size_t size DUMA_PARAMLIST_FL)
- {
- size_t srcsize;
- unsigned i;
- if ( size > 0 && src < dest && dest < src + size )
- DUMA_Abort("strncpy(%a, %a, %d): memory regions overlap.",
- (DUMA_ADDR)dest, (DUMA_ADDR)src, (DUMA_SIZE)size);
- /* calculate number of characters to copy from src to dest */
- srcsize = strlen(src) + 1;
- if ( srcsize > size )
- srcsize = size;
- /* copy src to dest */
- for (i=0; i<srcsize; ++i)
- dest[i] = src[i];
- /* fill rest with '\0' character */
- for ( ; i<size; ++i)
- dest[i] = 0;
- return dest;
- }
- /* Function: _duma_strcat
- *
- * A version of strcat that provides extra checks based on
- * information we know about HEAP.
- *
- * Currently the only check we perform is overlapping memory
- * regions. This should be expanded to include checking size
- * of dest to verify assumptions.
- */
- char * _duma_strcat(char *dest, const char *src DUMA_PARAMLIST_FL)
- {
- unsigned i;
- size_t destlen = strlen(dest);
- size_t srcsize = strlen(src) + 1;
- if ( src < dest +destlen && dest + destlen < src + srcsize )
- DUMA_Abort("strcat(%a, %a): memory regions overlap.", (DUMA_ADDR)dest, (DUMA_ADDR)src);
- for (i=0; i<srcsize; ++i)
- dest[destlen+i] = src[i];
- return dest;
- }
- /* Function: _duma_strncat
- *
- * A version of strncat that provides extra checks based on
- * information we know about HEAP.
- *
- * Currently the only check we perform is overlapping memory
- * regions. This should be expanded to include checking size
- * of dest to verify assumptions (like is size right).
- */
- char * _duma_strncat(char *dest, const char *src, size_t size DUMA_PARAMLIST_FL)
- {
- unsigned i;
- size_t destlen, srclen;
- /* do nothing, when size not > 0 */
- if ( size <= 0 )
- return dest;
- /* calculate number of characters to copy from src to dest */
- destlen = strlen(dest);
- srclen = strlen(src);
- if ( srclen > size )
- srclen = size;
- /* CHECK: Verify memory regions do not overlap */
- if ( src < (dest + destlen) && (dest + destlen) < (src + srclen + 1) )
- DUMA_Abort("strncat(%a, %a, %d): memory regions overlap.",
- (DUMA_ADDR)dest, (DUMA_ADDR)src, (DUMA_SIZE)size);
- /* copy up to size characters from src to dest */
- for (i=0; i<srclen; ++i)
- dest[destlen+i] = src[i];
- /* append single '\0' character */
- dest[destlen+srclen] = 0;
- return dest;
- }
- /*********************************************************/
- /* Function DUMA_newFrame
- *
- * Increments the frameno variable. Not sure why we do this :)
- */
- void DUMA_newFrame(void)
- {
- #ifdef DUMA_USE_FRAMENO
- ++frameno;
- #endif
- }
- /* Function DUMA_delFrame
- *
- * Will output DUMA message for all in use frames along with totals.
- * This method is called to when all memory should have been free'd by
- * the application to locate memory leaks.
- *
- * Note: No frames are deleted or modified by this function.
- */
- void DUMA_delFrame(void)
- {
- if (-1 != frameno)
- {
- struct _DUMA_Slot * slot = _duma_allocList;
- size_t count = slotCount;
- int nonFreed = 0;
- IF__DUMA_INIT_DONE
- DUMA_GET_SEMAPHORE();
- Page_AllowAccess(_duma_allocList, _duma_allocListSize);
- for ( ; count > 0; --count, ++slot )
- {
- if ( DUMAST_IN_USE == slot->state
- #ifdef DUMA_USE_FRAMENO
- && frameno == slot->frame
- #endif
- && EFA_INT_ALLOC != slot->allocator
- #ifdef DUMA_EXPLICIT_INIT
- && -1 != slot->lineno
- #endif
- )
- {
- DUMA_Print("\nDUMA: ptr=0x%a size=%d alloced from %s(%i) not freed\n",
- (DUMA_ADDR)slot->userAddress,
- (DUMA_SIZE)slot->userSize,
- slot->filename,
- slot->lineno);
- ++nonFreed;
- }
- }
- if (nonFreed)
- DUMA_Abort("DUMA_delFrame(): Found non free'd pointers.\n");
- Page_DenyAccess(_duma_allocList, _duma_allocListSize);
- IF__DUMA_INIT_DONE
- DUMA_RELEASE_SEMAPHORE();
- --frameno;
- }
- if (DUMA_SHOW_ALLOC)
- DUMA_Print("\nDUMA: DUMA_delFrame(): Processed %l allocations and %l deallocations in total.\n", numAllocs, numDeallocs);
- }
- /* Function: _duma_exit
- *
- * DUMA's exit function, called atexit() or with GNU C Compiler's destructor attribute.
- * This function also calls DUMA_delFrame to check for still in use memory and allert
- * the user.
- */
- void
- _duma_exit(void)
- {
- /* DUMA_ASSERT(0); */
- while (-1 != frameno)
- DUMA_delFrame();
- }
- /* end */
|