complete control over number of each kind of object allocated

This commit is contained in:
Roberto Ierusalimschy 2010-04-19 13:38:25 -03:00
parent 26d4a73962
commit 973d81efb3
1 changed files with 53 additions and 46 deletions

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ltests.c,v 2.94 2010/04/13 20:48:12 roberto Exp roberto $ ** $Id: ltests.c,v 2.95 2010/04/16 17:42:49 roberto Exp roberto $
** Internal Module for Debugging of the Lua Implementation ** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -74,90 +74,97 @@ static int tpanic (lua_State *L) {
#define MARK 0x55 /* 01010101 (a nice pattern) */ #define MARK 0x55 /* 01010101 (a nice pattern) */
typedef union Header {
L_Umaxalign a; /* ensures maximum alignment for Header */
struct {
size_t size;
int type;
} d;
} Header;
#ifndef EXTERNMEMCHECK #ifndef EXTERNMEMCHECK
/* full memory check */ /* full memory check */
#define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */
#define MARKSIZE 16 /* size of marks after each block */ #define MARKSIZE 16 /* size of marks after each block */
#define blockhead(b) (cast(char *, b) - HEADER)
#define setsize(newblock, size) (*cast(size_t *, newblock) = size)
#define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b))))
#define fillmem(mem,size) memset(mem, -MARK, size) #define fillmem(mem,size) memset(mem, -MARK, size)
#else #else
/* external memory check: don't do it twice */ /* external memory check: don't do it twice */
#define HEADER 0
#define MARKSIZE 0 #define MARKSIZE 0
#define blockhead(b) (b)
#define setsize(newblock, size) /* empty */
#define checkblocksize(b,size) (1)
#define fillmem(mem,size) /* empty */ #define fillmem(mem,size) /* empty */
#endif #endif
Memcontrol l_memcontrol = Memcontrol l_memcontrol =
{0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; {0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}};
static void *checkblock (void *block, size_t size) { static void freeblock (Memcontrol *mc, Header *block) {
void *b = blockhead(block);
int i;
for (i=0;i<MARKSIZE;i++)
lua_assert(*(cast(char *, b)+HEADER+size+i) == MARK+i); /* corrupted block? */
return b;
}
static void freeblock (Memcontrol *mc, void *block, size_t size) {
if (block) { if (block) {
lua_assert(checkblocksize(block, size)); size_t size = block->d.size;
block = checkblock(block, size); int i;
fillmem(block, size+HEADER+MARKSIZE); /* erase block */ for (i = 0; i < MARKSIZE; i++) /* check marks after block */
free(block); /* free original block */ lua_assert(*(cast(char *, block + 1) + size + i) == MARK);
mc->numblocks--; mc->objcount[block->d.type]--;
fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */
free(block); /* actually free block */
mc->numblocks--; /* update counts */
mc->total -= size; mc->total -= size;
} }
} }
void *debug_realloc (void *ud, void *block, size_t oldsize, size_t size) { void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
Memcontrol *mc = cast(Memcontrol *, ud); Memcontrol *mc = cast(Memcontrol *, ud);
if (block == NULL) { Header *block = cast(Header *, b);
if (oldsize < LUA_NUMTAGS) int type;
mc->objcount[oldsize]++;
oldsize = 0;
}
lua_assert((oldsize == 0) ? block == NULL :
block && checkblocksize(block, oldsize));
if (mc->memlimit == 0) { /* first time? */ if (mc->memlimit == 0) { /* first time? */
char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ char *limit = getenv("MEMLIMIT"); /* initialize memory limit */
mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX;
} }
if (block == NULL) {
type = (oldsize < LUA_NUMTAGS) ? oldsize : 0;
oldsize = 0;
}
else {
block--; /* go to real header */
type = block->d.type;
lua_assert(oldsize == block->d.size);
}
if (size == 0) { if (size == 0) {
freeblock(mc, block, oldsize); freeblock(mc, block);
return NULL; return NULL;
} }
else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) else if (size > oldsize && mc->total+size-oldsize > mc->memlimit)
return NULL; /* to test memory allocation errors */ return NULL; /* fake a memory allocation error */
else { else {
void *newblock; Header *newblock;
int i; int i;
size_t realsize = HEADER+size+MARKSIZE;
size_t commonsize = (oldsize < size) ? oldsize : size; size_t commonsize = (oldsize < size) ? oldsize : size;
if (realsize < size) return NULL; /* overflow! */ size_t realsize = sizeof(Header) + size + MARKSIZE;
newblock = malloc(realsize); /* alloc a new block */ if (realsize < size) return NULL; /* arithmetic overflow! */
if (newblock == NULL) return NULL; newblock = cast(Header *, malloc(realsize)); /* alloc a new block */
if (newblock == NULL) return NULL; /* really out of memory? */
if (block) { if (block) {
memcpy(cast(char *, newblock)+HEADER, block, commonsize); memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */
freeblock(mc, block, oldsize); /* erase (and check) old copy */ freeblock(mc, block); /* erase (and check) old copy */
} }
/* initialize new part of the block with something `weird' */ /* initialize new part of the block with something `weird' */
fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize); fillmem(cast(char *, newblock + 1) + commonsize, size - commonsize);
/* initialize marks after block */
for (i = 0; i < MARKSIZE; i++)
*(cast(char *, newblock + 1) + size + i) = MARK;
newblock->d.size = size;
newblock->d.type = type;
mc->total += size; mc->total += size;
if (mc->total > mc->maxmem) if (mc->total > mc->maxmem)
mc->maxmem = mc->total; mc->maxmem = mc->total;
mc->numblocks++; mc->numblocks++;
setsize(newblock, size); mc->objcount[type]++;
for (i=0;i<MARKSIZE;i++) return newblock + 1;
*(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i);
return cast(char *, newblock)+HEADER;
} }
} }