Explorar o código

new way to control stack overflow, controling only total size of the stack

Roberto Ierusalimschy %!s(int64=16) %!d(string=hai) anos
pai
achega
f76f4cb79d
Modificáronse 10 ficheiros con 100 adicións e 78 borrados
  1. 9 8
      lapi.c
  2. 18 7
      lauxlib.c
  3. 50 18
      ldo.c
  4. 2 1
      ldo.h
  5. 3 3
      llimits.h
  6. 5 14
      lstate.c
  7. 1 2
      lstate.h
  8. 1 2
      ltests.c
  9. 2 2
      lua.h
  10. 9 21
      luaconf.h

+ 9 - 8
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 2.83 2009/06/18 18:59:18 roberto Exp roberto $
+** $Id: lapi.c,v 2.84 2009/06/19 14:21:23 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -86,14 +86,15 @@ LUA_API int lua_checkstack (lua_State *L, int size) {
   int res = 1;
   CallInfo *ci = L->ci;
   lua_lock(L);
-  if (size > LUAI_MAXCSTACK ||
-      (L->top - (ci->func + 1) + size) > LUAI_MAXCSTACK)
-    res = 0;  /* stack overflow */
-  else if (size > 0) {
-    luaD_checkstack(L, size);
-    if (ci->top < L->top + size)
-      ci->top = L->top + size;
+  if (L->stack_last - L->top <= size) {  /* need to grow stack? */
+    int inuse = L->top - L->stack + EXTRA_STACK;
+    if (inuse > LUAI_MAXSTACK - size)  /* can grow without overflow? */
+      res = 0;  /* no */
+    else
+      luaD_growstack(L, size);
   }
+  if (res && ci->top < L->top + size)
+    ci->top = L->top + size;  /* adjust frame top */
   lua_unlock(L);
   return res;
 }

+ 18 - 7
lauxlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.c,v 1.187 2009/06/18 18:59:58 roberto Exp roberto $
+** $Id: lauxlib.c,v 1.188 2009/06/19 14:21:57 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -106,9 +106,16 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) {
 
 static int countlevels (lua_State *L) {
   lua_Debug ar;
-  int level = 1;
-  while (lua_getstack(L, level, &ar)) level++;
-  return level;
+  int li = 1, le = 1;
+  /* find an upper bound */
+  while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
+  /* do a binary search */
+  while (li < le) {
+    int m = (li + le)/2;
+    if (lua_getstack(L, m, &ar)) li = m + 1;
+    else le = m;
+  }
+  return le - 1;
 }
 
 
@@ -263,9 +270,13 @@ LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
 }
 
 
-LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
-  if (!lua_checkstack(L, space))
-    luaL_error(L, "stack overflow (%s)", mes);
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
+  if (!lua_checkstack(L, space)) {
+    if (msg)
+      luaL_error(L, "stack overflow (%s)", msg);
+    else
+      luaL_error(L, "stack overflow");
+  }
 }
 
 

+ 50 - 18
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.64 2009/05/21 20:06:11 roberto Exp roberto $
+** $Id: ldo.c,v 2.65 2009/06/01 19:09:26 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -70,12 +70,6 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
 }
 
 
-static void restore_stack_limit (lua_State *L) {
-  if (L->nci >= LUAI_MAXCALLS)  /* stack overflow? */
-    luaE_freeCI(L);  /* erase all extras CIs */
-}
-
-
 void luaD_throw (lua_State *L, int errcode) {
   if (L->errorJmp) {  /* thread has an error handler? */
     L->errorJmp->status = errcode;  /* set status */
@@ -130,25 +124,63 @@ static void correctstack (lua_State *L, TValue *oldstack) {
 }
 
 
+/* some space for error handling */
+#define ERRORSTACKSIZE	(LUAI_MAXSTACK + 200)
+
+
 void luaD_reallocstack (lua_State *L, int newsize) {
   TValue *oldstack = L->stack;
   int lim = L->stacksize;
-  int realsize = newsize + 1 + EXTRA_STACK;
-  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
-  luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
-  for (; lim < realsize; lim++)
+  lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
+  luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);
+  for (; lim < newsize; lim++)
     setnilvalue(L->stack + lim); /* erase new segment */
-  L->stacksize = realsize;
-  L->stack_last = L->stack+newsize;
+  L->stacksize = newsize;
+  L->stack_last = L->stack + newsize - EXTRA_STACK;
   correctstack(L, oldstack);
 }
 
 
 void luaD_growstack (lua_State *L, int n) {
-  if (n <= L->stacksize)  /* double size is enough? */
-    luaD_reallocstack(L, 2*L->stacksize);
+  int size = L->stacksize;
+  if (size > LUAI_MAXSTACK)  /* error after extra size? */
+    luaD_throw(L, LUA_ERRERR);
+  else {
+    int needed = L->top - L->stack + n + EXTRA_STACK;
+    int newsize = 2 * size;
+    if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
+    if (newsize < needed) newsize = needed;
+    if (newsize > LUAI_MAXSTACK) {  /* stack overflow? */
+      luaD_reallocstack(L, ERRORSTACKSIZE);
+      luaG_runerror(L, "stack overflow");
+    }
+    else
+      luaD_reallocstack(L, newsize);
+  }
+}
+
+
+static int stackinuse (lua_State *L) {
+  CallInfo *ci;
+  StkId lim = L->top;
+  for (ci = L->ci; ci != NULL; ci = ci->previous) {
+    lua_assert(ci->top <= L->stack_last);
+    if (lim < ci->top) lim = ci->top;
+  }
+  return cast_int(lim - L->stack) + 1;  /* part of stack in use */
+}
+
+
+void luaD_shrinkstack (lua_State *L) {
+  int inuse = stackinuse(L);
+  int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
+  if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
+  if (inuse > LUAI_MAXSTACK ||  /* handling stack overflow? */
+      goodsize >= L->stacksize)  /* would grow instead of shrink? */
+    condmovestack(L);  /* don't change stack (change only for debugging) */
   else
-    luaD_reallocstack(L, L->stacksize + n);
+    luaD_reallocstack(L, goodsize);  /* shrink it */
 }
 
 
@@ -427,7 +459,7 @@ static int recover (lua_State *L, int status) {
   L->ci = ci;
   L->allowhook = ci->u.c.old_allowhook;
   L->nny = 0;  /* should be zero to be yieldable */
-  restore_stack_limit(L);
+  luaD_shrinkstack(L);
   L->errfunc = ci->u.c.old_errfunc;
   ci->callstatus |= CIST_STAT;  /* call has error status */
   ci->u.c.status = status;  /* (here it is) */
@@ -499,7 +531,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
     L->ci = old_ci;
     L->allowhook = old_allowhooks;
     L->nny = old_nny;
-    restore_stack_limit(L);
+    luaD_shrinkstack(L);
   }
   L->errfunc = old_errfunc;
   return status;

+ 2 - 1
ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 2.13 2009/06/08 19:35:59 roberto Exp roberto $
+** $Id: ldo.h,v 2.14 2009/07/08 16:06:51 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -37,6 +37,7 @@ LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
 LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize);
 LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
 LUAI_FUNC void luaD_growstack (lua_State *L, int n);
+LUAI_FUNC void luaD_shrinkstack (lua_State *L);
 
 LUAI_FUNC void luaD_throw (lua_State *L, int errcode);
 LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);

+ 3 - 3
llimits.h

@@ -1,5 +1,5 @@
 /*
-** $Id: llimits.h,v 1.71 2009/06/08 19:35:59 roberto Exp roberto $
+** $Id: llimits.h,v 1.72 2009/07/01 16:14:15 roberto Exp roberto $
 ** Limits, basic types, and some other `installation-dependent' definitions
 ** See Copyright Notice in lua.h
 */
@@ -122,8 +122,8 @@ typedef lu_int32 Instruction;
 #ifndef HARDSTACKTESTS
 #define condmovestack(L)	((void)0)
 #else
-#define condmovestack(L) /* realloc stack keeping its size */ \
-	luaD_reallocstack((L), (L)->stacksize - EXTRA_STACK - 1)
+/* realloc stack keeping its size */
+#define condmovestack(L)	luaD_reallocstack((L), (L)->stacksize)
 #endif
 
 #endif

+ 5 - 14
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.55 2009/06/01 19:09:26 roberto Exp roberto $
+** $Id: lstate.c,v 2.56 2009/06/18 18:59:18 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -52,12 +52,6 @@ CallInfo *luaE_extendCI (lua_State *L) {
   L->ci->next = ci;
   ci->previous = L->ci;
   ci->next = NULL;
-  if (++L->nci >= LUAI_MAXCALLS) {
-    if (L->nci == LUAI_MAXCALLS)  /* overflow? */
-      luaG_runerror(L, "stack overflow");
-    if (L->nci >= LUAI_MAXCALLS + LUAI_EXTRACALLS)  /* again? */
-      luaD_throw(L, LUA_ERRERR);  /* error while handling overflow */
-  }
   return ci;
 }
 
@@ -69,7 +63,6 @@ void luaE_freeCI (lua_State *L) {
   while ((ci = next) != NULL) {
     next = ci->next;
     luaM_free(L, ci);
-    L->nci--;
   }
 }
 
@@ -77,12 +70,12 @@ void luaE_freeCI (lua_State *L) {
 static void stack_init (lua_State *L1, lua_State *L) {
   int i;
   /* initialize stack array */
-  L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue);
-  L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;
-  for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
+  L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue);
+  L1->stacksize = BASIC_STACK_SIZE;
+  for (i = 0; i < BASIC_STACK_SIZE; i++)
     setnilvalue(L1->stack + i);  /* erase new stack */
   L1->top = L1->stack;
-  L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
+  L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
   /* initialize first ci */
   L1->ci->func = L1->top;
   setnilvalue(L1->top++);  /* 'function' entry for this 'ci' */
@@ -94,7 +87,6 @@ static void stack_init (lua_State *L1, lua_State *L) {
 static void freestack (lua_State *L) {
   L->ci = &L->base_ci;  /* reset 'ci' list */
   luaE_freeCI(L);
-  lua_assert(L->nci == 0);
   luaM_freearray(L, L->stack, L->stacksize);
 }
 
@@ -131,7 +123,6 @@ static void preinit_state (lua_State *L, global_State *g) {
   L->status = LUA_OK;
   L->base_ci.next = L->base_ci.previous = NULL;
   L->ci = &L->base_ci;
-  L->nci = 0;
   L->errfunc = 0;
   setnilvalue(gt(L));
 }

+ 1 - 2
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.44 2009/06/01 19:09:26 roberto Exp roberto $
+** $Id: lstate.h,v 2.45 2009/06/18 18:59:18 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -163,7 +163,6 @@ struct lua_State {
   StkId top;  /* first free slot in the stack */
   global_State *l_G;
   CallInfo *ci;  /* call info for current function */
-  int nci;  /* number of total CallInfo structures linked */
   const Instruction *oldpc;  /* last pc traced */
   StkId stack_last;  /* last free slot in the stack */
   StkId stack;  /* stack base */

+ 1 - 2
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 2.65 2009/06/15 19:51:31 roberto Exp roberto $
+** $Id: ltests.c,v 2.66 2009/06/17 17:53:14 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -570,7 +570,6 @@ static int stacklevel (lua_State *L) {
   unsigned long a = 0;
   lua_pushinteger(L, (L->top - L->stack));
   lua_pushinteger(L, (L->stack_last - L->stack));
-  lua_pushinteger(L, L->nci);
   lua_pushinteger(L, (unsigned long)&a);
   return 5;
 }

+ 2 - 2
lua.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.h,v 1.239 2009/06/17 17:49:44 roberto Exp roberto $
+** $Id: lua.h,v 1.240 2009/06/18 18:59:18 roberto Exp roberto $
 ** Lua - An Extensible Extension Language
 ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
 ** See Copyright Notice at the end of this file
@@ -33,7 +33,7 @@
 /*
 ** pseudo-indices
 */
-#define LUA_REGISTRYINDEX	(-(LUAI_MCS_AUX) - 1)
+#define LUA_REGISTRYINDEX	LUAI_FIRSTPSEUDOIDX
 #define LUA_ENVIRONINDEX	(LUA_REGISTRYINDEX - 1)
 #define LUA_GLOBALSINDEX	(LUA_ENVIRONINDEX - 1)
 #define lua_upvalueindex(i)	(LUA_GLOBALSINDEX-(i))

+ 9 - 21
luaconf.h

@@ -1,5 +1,5 @@
 /*
-** $Id: luaconf.h,v 1.105 2009/06/18 18:19:36 roberto Exp roberto $
+** $Id: luaconf.h,v 1.106 2009/07/01 16:16:40 roberto Exp roberto $
 ** Configuration file for Lua
 ** See Copyright Notice in lua.h
 */
@@ -417,31 +417,19 @@
 
 
 /*
-@@ LUAI_MAXCALLS limits the number of nested calls.
-** CHANGE it if you need really deep recursive calls. This limit is
-** arbitrary; its only purpose is to stop infinite recursion before
-** exhausting memory.
-*/
-#define LUAI_MAXCALLS	20000
-
-
-/*
-@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function
-@* can use.
+@@ LUAI_MAXSTACK limits the size of the Lua stack.
 ** CHANGE it if you need a different limit. This limit is arbitrary;
-** its only purpose is to stop C functions to consume unlimited stack
-** space.
+** its only purpose is to stop Lua to consume unlimited stack
+** space (and to reserve some numbers for pseudo-indices).
 */
-/* life is simpler if stack size fits in an int (16 is an estimate
-   for the size of a Lua value) */
-#if SHRT_MAX < (INT_MAX / 16)
-#define LUAI_MCS_AUX	SHRT_MAX
+#if LUAI_BITSINT >= 32
+#define LUAI_MAXSTACK		1000000
 #else
-#define LUAI_MCS_AUX	(INT_MAX / 16)
+#define LUAI_MAXSTACK		15000
 #endif
 
-/* reserve some space for pseudo-indices */
-#define LUAI_MAXCSTACK  (LUAI_MCS_AUX - 1000)
+/* reserve some space for error handling */
+#define LUAI_FIRSTPSEUDOIDX  (-LUAI_MAXSTACK - 1000)