mirror of
https://github.com/lua/lua
synced 2025-04-02 19:12:53 +03:00
(much) better handling of memory alloction errors
This commit is contained in:
parent
ae55f3eead
commit
435f587ed0
@ -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
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
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
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
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!");
|
||||
|
@ -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
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
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
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
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…
x
Reference in New Issue
Block a user