diff options
| -rw-r--r-- | ltests.c | 99 |
1 files changed, 53 insertions, 46 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.c,v 2.94 2010/04/13 20:48:12 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.95 2010/04/16 17:42:49 roberto Exp roberto $ |
| 3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -74,90 +74,97 @@ static int tpanic (lua_State *L) { | |||
| 74 | 74 | ||
| 75 | #define MARK 0x55 /* 01010101 (a nice pattern) */ | 75 | #define MARK 0x55 /* 01010101 (a nice pattern) */ |
| 76 | 76 | ||
| 77 | typedef union Header { | ||
| 78 | L_Umaxalign a; /* ensures maximum alignment for Header */ | ||
| 79 | struct { | ||
| 80 | size_t size; | ||
| 81 | int type; | ||
| 82 | } d; | ||
| 83 | } Header; | ||
| 84 | |||
| 85 | |||
| 77 | #ifndef EXTERNMEMCHECK | 86 | #ifndef EXTERNMEMCHECK |
| 87 | |||
| 78 | /* full memory check */ | 88 | /* full memory check */ |
| 79 | #define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */ | ||
| 80 | #define MARKSIZE 16 /* size of marks after each block */ | 89 | #define MARKSIZE 16 /* size of marks after each block */ |
| 81 | #define blockhead(b) (cast(char *, b) - HEADER) | ||
| 82 | #define setsize(newblock, size) (*cast(size_t *, newblock) = size) | ||
| 83 | #define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b)))) | ||
| 84 | #define fillmem(mem,size) memset(mem, -MARK, size) | 90 | #define fillmem(mem,size) memset(mem, -MARK, size) |
| 91 | |||
| 85 | #else | 92 | #else |
| 93 | |||
| 86 | /* external memory check: don't do it twice */ | 94 | /* external memory check: don't do it twice */ |
| 87 | #define HEADER 0 | ||
| 88 | #define MARKSIZE 0 | 95 | #define MARKSIZE 0 |
| 89 | #define blockhead(b) (b) | ||
| 90 | #define setsize(newblock, size) /* empty */ | ||
| 91 | #define checkblocksize(b,size) (1) | ||
| 92 | #define fillmem(mem,size) /* empty */ | 96 | #define fillmem(mem,size) /* empty */ |
| 97 | |||
| 93 | #endif | 98 | #endif |
| 94 | 99 | ||
| 100 | |||
| 95 | Memcontrol l_memcontrol = | 101 | Memcontrol l_memcontrol = |
| 96 | {0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; | 102 | {0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; |
| 97 | 103 | ||
| 98 | 104 | ||
| 99 | static void *checkblock (void *block, size_t size) { | 105 | static void freeblock (Memcontrol *mc, Header *block) { |
| 100 | void *b = blockhead(block); | ||
| 101 | int i; | ||
| 102 | for (i=0;i<MARKSIZE;i++) | ||
| 103 | lua_assert(*(cast(char *, b)+HEADER+size+i) == MARK+i); /* corrupted block? */ | ||
| 104 | return b; | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | static void freeblock (Memcontrol *mc, void *block, size_t size) { | ||
| 109 | if (block) { | 106 | if (block) { |
| 110 | lua_assert(checkblocksize(block, size)); | 107 | size_t size = block->d.size; |
| 111 | block = checkblock(block, size); | 108 | int i; |
| 112 | fillmem(block, size+HEADER+MARKSIZE); /* erase block */ | 109 | for (i = 0; i < MARKSIZE; i++) /* check marks after block */ |
| 113 | free(block); /* free original block */ | 110 | lua_assert(*(cast(char *, block + 1) + size + i) == MARK); |
| 114 | mc->numblocks--; | 111 | mc->objcount[block->d.type]--; |
| 112 | fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */ | ||
| 113 | free(block); /* actually free block */ | ||
| 114 | mc->numblocks--; /* update counts */ | ||
| 115 | mc->total -= size; | 115 | mc->total -= size; |
| 116 | } | 116 | } |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | 119 | ||
| 120 | void *debug_realloc (void *ud, void *block, size_t oldsize, size_t size) { | 120 | void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { |
| 121 | Memcontrol *mc = cast(Memcontrol *, ud); | 121 | Memcontrol *mc = cast(Memcontrol *, ud); |
| 122 | if (block == NULL) { | 122 | Header *block = cast(Header *, b); |
| 123 | if (oldsize < LUA_NUMTAGS) | 123 | int type; |
| 124 | mc->objcount[oldsize]++; | ||
| 125 | oldsize = 0; | ||
| 126 | } | ||
| 127 | lua_assert((oldsize == 0) ? block == NULL : | ||
| 128 | block && checkblocksize(block, oldsize)); | ||
| 129 | if (mc->memlimit == 0) { /* first time? */ | 124 | if (mc->memlimit == 0) { /* first time? */ |
| 130 | char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ | 125 | char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ |
| 131 | mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; | 126 | mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; |
| 132 | } | 127 | } |
| 128 | if (block == NULL) { | ||
| 129 | type = (oldsize < LUA_NUMTAGS) ? oldsize : 0; | ||
| 130 | oldsize = 0; | ||
| 131 | } | ||
| 132 | else { | ||
| 133 | block--; /* go to real header */ | ||
| 134 | type = block->d.type; | ||
| 135 | lua_assert(oldsize == block->d.size); | ||
| 136 | } | ||
| 133 | if (size == 0) { | 137 | if (size == 0) { |
| 134 | freeblock(mc, block, oldsize); | 138 | freeblock(mc, block); |
| 135 | return NULL; | 139 | return NULL; |
| 136 | } | 140 | } |
| 137 | else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) | 141 | else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) |
| 138 | return NULL; /* to test memory allocation errors */ | 142 | return NULL; /* fake a memory allocation error */ |
| 139 | else { | 143 | else { |
| 140 | void *newblock; | 144 | Header *newblock; |
| 141 | int i; | 145 | int i; |
| 142 | size_t realsize = HEADER+size+MARKSIZE; | ||
| 143 | size_t commonsize = (oldsize < size) ? oldsize : size; | 146 | size_t commonsize = (oldsize < size) ? oldsize : size; |
| 144 | if (realsize < size) return NULL; /* overflow! */ | 147 | size_t realsize = sizeof(Header) + size + MARKSIZE; |
| 145 | newblock = malloc(realsize); /* alloc a new block */ | 148 | if (realsize < size) return NULL; /* arithmetic overflow! */ |
| 146 | if (newblock == NULL) return NULL; | 149 | newblock = cast(Header *, malloc(realsize)); /* alloc a new block */ |
| 150 | if (newblock == NULL) return NULL; /* really out of memory? */ | ||
| 147 | if (block) { | 151 | if (block) { |
| 148 | memcpy(cast(char *, newblock)+HEADER, block, commonsize); | 152 | memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */ |
| 149 | freeblock(mc, block, oldsize); /* erase (and check) old copy */ | 153 | freeblock(mc, block); /* erase (and check) old copy */ |
| 150 | } | 154 | } |
| 151 | /* initialize new part of the block with something `weird' */ | 155 | /* initialize new part of the block with something `weird' */ |
| 152 | fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize); | 156 | fillmem(cast(char *, newblock + 1) + commonsize, size - commonsize); |
| 157 | /* initialize marks after block */ | ||
| 158 | for (i = 0; i < MARKSIZE; i++) | ||
| 159 | *(cast(char *, newblock + 1) + size + i) = MARK; | ||
| 160 | newblock->d.size = size; | ||
| 161 | newblock->d.type = type; | ||
| 153 | mc->total += size; | 162 | mc->total += size; |
| 154 | if (mc->total > mc->maxmem) | 163 | if (mc->total > mc->maxmem) |
| 155 | mc->maxmem = mc->total; | 164 | mc->maxmem = mc->total; |
| 156 | mc->numblocks++; | 165 | mc->numblocks++; |
| 157 | setsize(newblock, size); | 166 | mc->objcount[type]++; |
| 158 | for (i=0;i<MARKSIZE;i++) | 167 | return newblock + 1; |
| 159 | *(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i); | ||
| 160 | return cast(char *, newblock)+HEADER; | ||
| 161 | } | 168 | } |
| 162 | } | 169 | } |
| 163 | 170 | ||
