|
|
@ -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 |
|
|
|
** See Copyright Notice in lua.h |
|
|
|
*/ |
|
|
@ -74,90 +74,97 @@ static int tpanic (lua_State *L) { |
|
|
|
|
|
|
|
#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 |
|
|
|
|
|
|
|
/* full memory check */ |
|
|
|
#define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */ |
|
|
|
#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) |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
/* external memory check: don't do it twice */ |
|
|
|
#define HEADER 0 |
|
|
|
#define MARKSIZE 0 |
|
|
|
#define blockhead(b) (b) |
|
|
|
#define setsize(newblock, size) /* empty */ |
|
|
|
#define checkblocksize(b,size) (1) |
|
|
|
#define fillmem(mem,size) /* empty */ |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
Memcontrol l_memcontrol = |
|
|
|
{0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; |
|
|
|
|
|
|
|
|
|
|
|
static void *checkblock (void *block, size_t size) { |
|
|
|
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) { |
|
|
|
static void freeblock (Memcontrol *mc, Header *block) { |
|
|
|
if (block) { |
|
|
|
lua_assert(checkblocksize(block, size)); |
|
|
|
block = checkblock(block, size); |
|
|
|
fillmem(block, size+HEADER+MARKSIZE); /* erase block */ |
|
|
|
free(block); /* free original block */ |
|
|
|
mc->numblocks--; |
|
|
|
size_t size = block->d.size; |
|
|
|
int i; |
|
|
|
for (i = 0; i < MARKSIZE; i++) /* check marks after block */ |
|
|
|
lua_assert(*(cast(char *, block + 1) + size + i) == MARK); |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
if (block == NULL) { |
|
|
|
if (oldsize < LUA_NUMTAGS) |
|
|
|
mc->objcount[oldsize]++; |
|
|
|
oldsize = 0; |
|
|
|
} |
|
|
|
lua_assert((oldsize == 0) ? block == NULL : |
|
|
|
block && checkblocksize(block, oldsize)); |
|
|
|
Header *block = cast(Header *, b); |
|
|
|
int type; |
|
|
|
if (mc->memlimit == 0) { /* first time? */ |
|
|
|
char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ |
|
|
|
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) { |
|
|
|
freeblock(mc, block, oldsize); |
|
|
|
freeblock(mc, block); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
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 { |
|
|
|
void *newblock; |
|
|
|
Header *newblock; |
|
|
|
int i; |
|
|
|
size_t realsize = HEADER+size+MARKSIZE; |
|
|
|
size_t commonsize = (oldsize < size) ? oldsize : size; |
|
|
|
if (realsize < size) return NULL; /* overflow! */ |
|
|
|
newblock = malloc(realsize); /* alloc a new block */ |
|
|
|
if (newblock == NULL) return NULL; |
|
|
|
size_t realsize = sizeof(Header) + size + MARKSIZE; |
|
|
|
if (realsize < size) return NULL; /* arithmetic overflow! */ |
|
|
|
newblock = cast(Header *, malloc(realsize)); /* alloc a new block */ |
|
|
|
if (newblock == NULL) return NULL; /* really out of memory? */ |
|
|
|
if (block) { |
|
|
|
memcpy(cast(char *, newblock)+HEADER, block, commonsize); |
|
|
|
freeblock(mc, block, oldsize); /* erase (and check) old copy */ |
|
|
|
memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */ |
|
|
|
freeblock(mc, block); /* erase (and check) old copy */ |
|
|
|
} |
|
|
|
/* 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; |
|
|
|
if (mc->total > mc->maxmem) |
|
|
|
mc->maxmem = mc->total; |
|
|
|
mc->numblocks++; |
|
|
|
setsize(newblock, size); |
|
|
|
for (i=0;i<MARKSIZE;i++) |
|
|
|
*(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i); |
|
|
|
return cast(char *, newblock)+HEADER; |
|
|
|
mc->objcount[type]++; |
|
|
|
return newblock + 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|