Browse Source

(much) better handling of memory alloction errors

v5-2
Roberto Ierusalimschy 25 years ago
parent
commit
435f587ed0
  1. 8
      lbuiltin.c
  2. 6
      lcode.c
  3. 94
      ldo.c
  4. 14
      lmem.c
  5. 39
      lstate.c
  6. 6
      lstring.c
  7. 10
      ltable.c
  8. 34
      ltests.c
  9. 6
      ltm.c
  10. 8
      lua.c

8
lbuiltin.c

@ -1,5 +1,5 @@
/*
** $Id: lbuiltin.c,v 1.116 2000/06/12 13:52:05 roberto Exp roberto $
** $Id: lbuiltin.c,v 1.117 2000/06/30 14:35:17 roberto Exp roberto $
** Built-in functions
** See Copyright Notice in lua.h
*/
@ -365,8 +365,8 @@ void luaB_tostring (lua_State *L) {
sprintf(buff, "function: %p", clvalue(o));
break;
case TAG_USERDATA:
sprintf(buff, "userdata: %p(%d)", tsvalue(o)->u.d.value,
tsvalue(o)->u.d.tag);
sprintf(buff, "userdata(%d): %p", tsvalue(o)->u.d.tag,
tsvalue(o)->u.d.value);
break;
case TAG_NIL:
lua_pushstring(L, "nil");
@ -680,8 +680,6 @@ static const struct luaL_reg builtin_funcs[] = {
void luaB_predefine (lua_State *L) {
/* pre-register mem error messages, to avoid loop when error arises */
luaS_newfixed(L, memEM);
luaL_openl(L, builtin_funcs);
#ifdef DEBUG
luaB_opentests(L); /* internal test functions */

6
lcode.c

@ -1,5 +1,5 @@
/*
** $Id: lcode.c,v 1.40 2000/06/28 20:20:36 roberto Exp roberto $
** $Id: lcode.c,v 1.41 2000/06/30 14:35:17 roberto Exp roberto $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@ -620,8 +620,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
}
if (fs->debug) {
LexState *ls = fs->ls;
luaX_checklimit(ls, ls->lastline, MAXARG_U, "lines in a chunk");
luaM_growvector(fs->L, fs->f->lines, fs->pc, 1, int, "??", MAXARG_U);
luaM_growvector(fs->L, fs->f->lines, fs->pc, 1, int,
"code size overflow", MAX_INT);
fs->f->lines[fs->pc] = ls->lastline;
}
/* put new instruction in code array */

94
ldo.c

@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 1.80 2000/06/26 19:28:31 roberto Exp roberto $
** $Id: ldo.c,v 1.81 2000/06/28 20:20:36 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@ -237,17 +237,41 @@ static void message (lua_State *L, const char *s) {
}
}
void luaD_breakrun (lua_State *L, int errcode) {
if (L->errorJmp) {
L->errorJmp->status = errcode;
longjmp(L->errorJmp->b, 1);
}
else {
if (errcode != LUA_ERRMEM)
message(L, "unable to recover; exiting\n");
exit(1);
}
}
/*
** Reports an error, and jumps up to the available recovery label
*/
void lua_error (lua_State *L, const char *s) {
if (s) message(L, s);
if (L->errorJmp)
longjmp(L->errorJmp->b, 1);
else {
message(L, "unable to recover; exiting\n");
exit(1);
}
luaD_breakrun(L, LUA_ERRRUN);
}
static void chain_longjmp (lua_State *L, struct lua_longjmp *lj) {
lj->base = L->Cstack.base;
lj->numCblocks = L->numCblocks;
lj->previous = L->errorJmp;
L->errorJmp = lj;
}
static void restore_longjmp (lua_State *L, struct lua_longjmp *lj) {
L->Cstack.num = 0; /* no results */
L->top = L->Cstack.base = L->Cstack.lua2C = lj->base;
L->numCblocks = lj->numCblocks;
L->errorJmp = lj->previous;
}
@ -257,58 +281,44 @@ void lua_error (lua_State *L, const char *s) {
*/
int luaD_protectedrun (lua_State *L) {
struct lua_longjmp myErrorJmp;
StkId base = L->Cstack.base;
int numCblocks = L->numCblocks;
int status;
struct lua_longjmp *volatile oldErr = L->errorJmp;
L->errorJmp = &myErrorJmp;
chain_longjmp(L, &myErrorJmp);
if (setjmp(myErrorJmp.b) == 0) {
StkId base = L->Cstack.base;
luaD_call(L, base, MULT_RET);
L->Cstack.lua2C = base; /* position of the new results */
L->Cstack.num = L->top - base;
L->Cstack.base = base + L->Cstack.num; /* incorporate results on stack */
status = 0;
L->errorJmp = myErrorJmp.previous;
return 0;
}
else { /* an error occurred: restore the stack */
L->Cstack.num = 0; /* no results */
L->top = L->Cstack.base = L->Cstack.lua2C = base;
L->numCblocks = numCblocks;
restore_longjmp(L, &myErrorJmp);
restore_stack_limit(L);
status = 1;
return myErrorJmp.status;
}
L->errorJmp = oldErr;
return status;
}
/*
** returns 0 = chunk loaded; 1 = error; 2 = no more chunks to load
** returns 0 = chunk loaded; >0 : error; -1 = no more chunks to load
*/
static int protectedparser (lua_State *L, ZIO *z, int bin) {
struct lua_longjmp myErrorJmp;
StkId base = L->Cstack.base;
int numCblocks = L->numCblocks;
int status;
Proto *volatile tf;
struct lua_longjmp *volatile oldErr = L->errorJmp;
L->errorJmp = &myErrorJmp;
L->top = base; /* clear C2Lua */
chain_longjmp(L, &myErrorJmp);
L->top = L->Cstack.base; /* clear C2Lua */
if (setjmp(myErrorJmp.b) == 0) {
tf = bin ? luaU_undump1(L, z) : luaY_parser(L, z);
status = 0;
Proto *tf = bin ? luaU_undump1(L, z) : luaY_parser(L, z);
L->errorJmp = myErrorJmp.previous;
if (tf == NULL) return -1; /* `natural' end */
luaV_Lclosure(L, tf, 0);
return 0;
}
else { /* an error occurred: restore Cstack and top */
L->Cstack.num = 0; /* no results */
L->top = L->Cstack.base = L->Cstack.lua2C = base;
L->numCblocks = numCblocks;
tf = NULL;
status = 1;
else { /* an error occurred */
restore_longjmp(L, &myErrorJmp);
if (myErrorJmp.status == LUA_ERRRUN)
myErrorJmp.status = LUA_ERRSYNTAX;
return myErrorJmp.status; /* error code */
}
L->errorJmp = oldErr;
if (status) return 1; /* error code */
if (tf == NULL) return 2; /* `natural' end */
luaV_Lclosure(L, tf, 0);
return 0;
}
@ -320,8 +330,8 @@ static int do_main (lua_State *L, ZIO *z, int bin) {
luaC_checkGC(L);
old_blocks = L->nblocks;
status = protectedparser(L, z, bin);
if (status == 1) return 1; /* error */
else if (status == 2) return 0; /* `natural' end */
if (status > 0) return status; /* error */
else if (status < 0) return 0; /* `natural' end */
else {
unsigned long newelems2 = 2*(L->nblocks-old_blocks);
L->GCthreshold += newelems2;

14
lmem.c

@ -1,5 +1,5 @@
/*
** $Id: lmem.c,v 1.33 2000/06/12 13:52:05 roberto Exp roberto $
** $Id: lmem.c,v 1.34 2000/06/26 19:28:31 roberto Exp roberto $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@ -11,6 +11,7 @@
#include "lua.h"
#include "ldo.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
@ -36,6 +37,7 @@
#include <assert.h>
#include <limits.h>
#include <string.h>
#undef realloc
@ -59,6 +61,7 @@ union L_U { double d; char *s; long l; };
unsigned long memdebug_numblocks = 0;
unsigned long memdebug_total = 0;
unsigned long memdebug_maxmem = 0;
unsigned long memdebug_memlimit = LONG_MAX;
static void *checkblock (void *block) {
@ -88,6 +91,8 @@ static void *debug_realloc (void *block, size_t size) {
freeblock(block);
return NULL;
}
else if (memdebug_total+size > memdebug_memlimit)
return NULL; /* to test memory allocation errors */
else {
size_t realsize = HEADER+size+MARKSIZE;
char *newblock = (char *)(malloc)(realsize); /* alloc a new block */
@ -139,8 +144,11 @@ void *luaM_realloc (lua_State *L, void *block, lint32 size) {
else if (size >= MAX_SIZET)
lua_error(L, "memory allocation error: block too big");
block = realloc(block, size);
if (block == NULL)
lua_error(L, memEM);
if (block == NULL) {
if (L)
luaD_breakrun(L, LUA_ERRMEM); /* break run without error message */
else return NULL; /* error before creating state! */
}
return block;
}

39
lstate.c

@ -1,5 +1,5 @@
/*
** $Id: lstate.c,v 1.28 2000/06/30 14:35:17 roberto Exp roberto $
** $Id: lstate.c,v 1.29 2000/06/30 19:17:08 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@ -28,8 +28,14 @@ lua_State *lua_state = NULL;
lua_State *lua_newstate (int stacksize, int put_builtin) {
struct lua_longjmp myErrorJmp;
lua_State *L = luaM_new(NULL, lua_State);
L->errorJmp = NULL;
if (L == NULL) return NULL; /* memory allocation error */
L->stack = NULL;
L->strt.size = L->udt.size = 0;
L->strt.nuse = L->udt.nuse = 0;
L->strt.hash = NULL;
L->udt.hash = NULL;
L->Mbuffer = NULL;
L->Mbuffbase = 0;
L->Mbuffsize = 0;
@ -40,6 +46,7 @@ lua_State *lua_newstate (int stacksize, int put_builtin) {
L->rootcl = NULL;
L->roottable = NULL;
L->IMtable = NULL;
L->last_tag = -1;
L->refArray = NULL;
L->refSize = 0;
L->refFree = NONEXT;
@ -49,16 +56,23 @@ lua_State *lua_newstate (int stacksize, int put_builtin) {
L->callhook = NULL;
L->linehook = NULL;
L->allowhooks = 1;
L->gt = luaH_new(L, 10);
if (stacksize == 0) stacksize = DEFAULT_STACK_SIZE;
luaD_init(L, stacksize);
luaS_init(L);
luaX_init(L);
luaT_init(L);
if (put_builtin)
luaB_predefine(L);
L->GCthreshold = L->nblocks*4;
return L;
L->errorJmp = &myErrorJmp;
if (setjmp(myErrorJmp.b) == 0) { /* to catch memory allocation errors */
L->gt = luaH_new(L, 10);
luaD_init(L, (stacksize == 0) ? DEFAULT_STACK_SIZE : stacksize);
luaS_init(L);
luaX_init(L);
luaT_init(L);
if (put_builtin)
luaB_predefine(L);
L->GCthreshold = L->nblocks*4;
L->errorJmp = NULL;
return L;
}
else { /* memory allocation error: free partial state */
lua_close(L);
return NULL;
}
}
@ -75,7 +89,6 @@ void lua_close (lua_State *L) {
luaM_free(L, L->Cblocks);
LUA_ASSERT(L->numCblocks == 0, "Cblocks still open");
LUA_ASSERT(L->nblocks == 0, "wrong count for nblocks");
LUA_ASSERT(L->Cstack.base == L->top, "C2Lua not empty");
luaM_free(L, L);
if (L == lua_state) {
LUA_ASSERT(memdebug_numblocks == 0, "memory leak!");

6
lstring.c

@ -1,5 +1,5 @@
/*
** $Id: lstring.c,v 1.39 2000/06/15 17:01:12 roberto Exp roberto $
** $Id: lstring.c,v 1.40 2000/06/30 14:35:17 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@ -19,10 +19,10 @@
void luaS_init (lua_State *L) {
L->strt.size = L->udt.size = 1;
L->strt.nuse = L->udt.nuse = 0;
L->strt.hash = luaM_newvector(L, 1, TString *);
L->udt.hash = luaM_newvector(L, 1, TString *);
L->strt.size = L->udt.size = 1;
L->strt.nuse = L->udt.nuse = 0;
L->strt.hash[0] = L->udt.hash[0] = NULL;
}

10
ltable.c

@ -1,5 +1,5 @@
/*
** $Id: ltable.c,v 1.49 2000/06/28 17:03:56 roberto Exp roberto $
** $Id: ltable.c,v 1.50 2000/06/30 14:35:17 roberto Exp roberto $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@ -154,19 +154,22 @@ static void setnodevector (lua_State *L, Hash *t, lint32 size) {
ttype(&t->node[i].key) = ttype(&t->node[i].val) = TAG_NIL;
t->node[i].next = NULL;
}
L->nblocks += gcsize(L, size) - gcsize(L, t->size);
t->size = size;
t->firstfree = &t->node[size-1]; /* first free position to be used */
L->nblocks += gcsize(L, size);
}
Hash *luaH_new (lua_State *L, int size) {
Hash *t = luaM_new(L, Hash);
setnodevector(L, t, luaO_power2(size));
t->htag = TagDefault;
t->next = L->roottable;
L->roottable = t;
t->marked = 0;
t->size = 0;
L->nblocks += gcsize(L, 0);
t->node = NULL;
setnodevector(L, t, luaO_power2(size));
return t;
}
@ -204,7 +207,6 @@ static void rehash (lua_State *L, Hash *t) {
setnodevector(L, t, oldsize/2);
else
setnodevector(L, t, oldsize);
L->nblocks -= gcsize(L, oldsize);
for (i=0; i<oldsize; i++) {
Node *old = nold+i;
if (ttype(&old->val) != TAG_NIL)

34
ltests.c

@ -1,5 +1,5 @@
/*
** $Id: ltests.c,v 1.28 2000/06/28 17:06:07 roberto Exp roberto $
** $Id: ltests.c,v 1.29 2000/06/30 19:17:08 roberto Exp roberto $
** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
@ -169,9 +169,14 @@ static void get_limits (void) {
static void mem_query (void) {
lua_pushnumber(memdebug_total);
lua_pushnumber(memdebug_numblocks);
lua_pushnumber(memdebug_maxmem);
lua_Object arg = lua_getparam(1);
if (arg == LUA_NOOBJECT) {
lua_pushnumber(memdebug_total);
lua_pushnumber(memdebug_numblocks);
lua_pushnumber(memdebug_maxmem);
}
else
memdebug_memlimit = luaL_check_int(1);
}
@ -375,7 +380,10 @@ static void testC (void) {
else if EQ("newstate") {
int stacksize = getnum(&pc);
lua_State *L1 = lua_newstate(stacksize, getnum(&pc));
lua_pushuserdata(L1);
if (L1)
lua_pushuserdata(L1);
else
lua_pushnil();
}
else if EQ("closestate") {
(lua_close)((lua_State *)lua_getuserdata(reg[getreg(&pc)]));
@ -385,14 +393,20 @@ static void testC (void) {
lua_Object str = reg[getreg(&pc)];
lua_State *L1;
lua_Object temp;
int i;
int status;
if (!lua_isuserdata(ol1) || !lua_isstring(str))
lua_error("bad arguments for `doremote'");
L1 = (lua_State *)lua_getuserdata(ol1);
(lua_dostring)(L1, lua_getstring(str));
i = 1;
while ((temp = (lua_getresult)(L1, i++)) != LUA_NOOBJECT)
lua_pushstring((lua_getstring)(L1, temp));
status = (lua_dostring)(L1, lua_getstring(str));
if (status != 0) {
lua_pushnil();
lua_pushnumber(status);
}
else {
int i = 1;
while ((temp = (lua_getresult)(L1, i++)) != LUA_NOOBJECT)
lua_pushstring((lua_getstring)(L1, temp));
}
}
#if LUA_DEPRECATETFUNCS
else if EQ("rawsetglobal") {

6
ltm.c

@ -1,5 +1,5 @@
/*
** $Id: ltm.c,v 1.42 2000/06/08 17:48:31 roberto Exp roberto $
** $Id: ltm.c,v 1.43 2000/06/12 13:52:05 roberto Exp roberto $
** Tag methods
** See Copyright Notice in lua.h
*/
@ -69,17 +69,17 @@ static void init_entry (lua_State *L, int tag) {
void luaT_init (lua_State *L) {
int t;
L->last_tag = NUM_TAGS-1;
luaM_growvector(L, L->IMtable, 0, NUM_TAGS, struct IM, "", MAX_INT);
L->last_tag = NUM_TAGS-1;
for (t=0; t<=L->last_tag; t++)
init_entry(L, t);
}
int lua_newtag (lua_State *L) {
++L->last_tag;
luaM_growvector(L, L->IMtable, L->last_tag, 1, struct IM,
"tag table overflow", MAX_INT);
L->last_tag++;
init_entry(L, L->last_tag);
return L->last_tag;
}

8
lua.c

@ -1,5 +1,5 @@
/*
** $Id: lua.c,v 1.41 2000/06/19 13:15:15 roberto Exp roberto $
** $Id: lua.c,v 1.42 2000/06/30 19:17:08 roberto Exp roberto $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@ -62,6 +62,10 @@ static int ldo (int (*f)(lua_State *L, const char *), const char *name) {
handler h = lreset();
res = f(lua_state, name); /* dostring | dofile */
signal(SIGINT, h); /* restore old action */
if (res == LUA_ERRMEM) {
/* Lua gives no message in such case, so lua.c provides one */
fprintf(stderr, "lua: memory allocation error\n");
}
return res;
}
@ -121,7 +125,7 @@ static void l_getargs (void) {
static void file_input (const char *argv) {
int result = ldo(lua_dofile, argv);
if (result) {
if (result == 2) {
if (result == LUA_ERRFILE) {
fprintf(stderr, "lua: cannot execute file ");
perror(argv);
}

Loading…
Cancel
Save