瀏覽代碼

Revision of stackless implementation

- more organized handling of 'nCcalls'
- comments
- deprecation of 'setcstacklimit'
Roberto Ierusalimschy 4 年之前
父節點
當前提交
287b302acb
共有 12 個文件被更改,包括 127 次插入283 次删除
  1. 1 1
      all
  2. 1 4
      ldblib.c
  3. 26 26
      ldo.c
  4. 11 0
      llimits.h
  5. 1 5
      lparser.c
  6. 25 20
      lstate.c
  7. 10 46
      lstate.h
  8. 0 15
      luaconf.h
  9. 3 3
      lvm.c
  10. 17 55
      manual/manual.of
  11. 30 107
      testes/cstack.lua
  12. 2 1
      testes/errors.lua

+ 1 - 1
all

@@ -1,7 +1,7 @@
 make -s -j
 cd testes/libs; make -s
 cd ..     # back to directory 'testes'
-ulimit -S -s 2000
+ulimit -S -s 1000
 if { ../lua -W all.lua; } then
   echo -e "\n\n    final OK!!!!\n\n"
 else

+ 1 - 4
ldblib.c

@@ -440,10 +440,7 @@ static int db_traceback (lua_State *L) {
 static int db_setcstacklimit (lua_State *L) {
   int limit = (int)luaL_checkinteger(L, 1);
   int res = lua_setcstacklimit(L, limit);
-  if (res == 0)
-    lua_pushboolean(L, 0);
-  else
-    lua_pushinteger(L, res);
+  lua_pushinteger(L, res);
   return 1;
 }
 

+ 26 - 26
ldo.c

@@ -448,10 +448,11 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
 
 
 /*
-** Call a function (C or Lua). The function to be called is at *func.
-** The arguments are on the stack, right after the function.
-** When returns, all the results are on the stack, starting at the original
-** function position.
+** Prepares the call to a function (C or Lua). For C functions, also do
+** the call.  The function to be called is at '*func'.  The arguments are
+** on the stack, right after the function.  Returns true if the call was
+** made (it was a C function).  When returns true, all the results are
+** on the stack, starting at the original function position.
 */
 int luaD_precall (lua_State *L, StkId func, int nresults) {
   lua_CFunction f;
@@ -511,32 +512,34 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
 }
 
 
-static void stackerror (lua_State *L) {
-  if (getCcalls(L) == LUAI_MAXCCALLS)
-    luaG_runerror(L, "C stack overflow");
-  else if (getCcalls(L) >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
-    luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
-}
-
-
-void luaD_call (lua_State *L, StkId func, int nResults) {
-  L->nCcalls++;
+/*
+** Call a function (C or Lua). 'inc' can be 1 (increment number
+** of recursive invocations in the C stack) or nyci (the same plus
+** increment number of non-yieldable calls).
+*/
+static void docall (lua_State *L, StkId func, int nResults, int inc) {
+  L->nCcalls += inc;
   if (getCcalls(L) >= LUAI_MAXCCALLS)
-    stackerror(L);
+    luaE_checkcstack(L);
   if (!luaD_precall(L, func, nResults))  /* is a Lua function? */
     luaV_execute(L, L->ci);  /* call it */
-  L->nCcalls--;
+  L->nCcalls -= inc;
 }
 
 
+/*
+** External interface for 'docall'
+*/
+void luaD_call (lua_State *L, StkId func, int nResults) {
+  return docall(L, func, nResults, 1);
+}
+
 
 /*
 ** Similar to 'luaD_call', but does not allow yields during the call.
 */
 void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
-  incnny(L);
-  luaD_call(L, func, nResults);
-  decnny(L);
+  return docall(L, func, nResults, nyci);
 }
 
 
@@ -650,13 +653,12 @@ static void resume (lua_State *L, void *ud) {
   int n = *(cast(int*, ud));  /* number of arguments */
   StkId firstArg = L->top - n;  /* first argument */
   CallInfo *ci = L->ci;
-  if (L->status == LUA_OK) {  /* starting a coroutine? */
-    if (!luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* Lua function? */
-      luaV_execute(L, L->ci);  /* call it */
-  }
+  if (L->status == LUA_OK)  /* starting a coroutine? */
+    docall(L, firstArg - 1, LUA_MULTRET, 1);  /* just call its body */
   else {  /* resuming from previous yield */
     lua_assert(L->status == LUA_YIELD);
     L->status = LUA_OK;  /* mark that it is running (again) */
+    luaE_incCstack(L);  /* control the C stack */
     if (isLua(ci))  /* yielded inside a hook? */
       luaV_execute(L, ci);  /* just continue running Lua code */
     else {  /* 'common' yield */
@@ -684,9 +686,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
   }
   else if (L->status != LUA_YIELD)  /* ended with errors? */
     return resume_error(L, "cannot resume dead coroutine", nargs);
-  L->nCcalls = (from) ? getCcalls(from) + 1 : 1;
-  if (getCcalls(L) >= LUAI_MAXCCALLS)
-    return resume_error(L, "C stack overflow", nargs);
+  L->nCcalls = (from) ? getCcalls(from) : 0;
   luai_userstateresume(L, nargs);
   api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
   status = luaD_rawrunprotected(L, resume, &nargs);

+ 11 - 0
llimits.h

@@ -234,6 +234,17 @@ typedef l_uint32 Instruction;
 #endif
 
 
+/*
+** Maximum depth for nested C calls, syntactical nested non-terminals,
+** and other features implemented through recursion in C. (Value must
+** fit in a 16-bit unsigned integer. It must also be compatible with
+** the size of the C stack.)
+*/
+#if !defined(LUAI_MAXCCALLS)
+#define LUAI_MAXCCALLS		200
+#endif
+
+
 /*
 ** macros that are executed whenever program enters the Lua core
 ** ('lua_lock') and leaves the core ('lua_unlock')

+ 1 - 5
lparser.c

@@ -489,11 +489,7 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
 }
 
 
-static void enterlevel (LexState *ls) {
-  lua_State *L = ls->L;
-  L->nCcalls++;
-  checklimit(ls->fs, getCcalls(L), LUAI_MAXCCALLS, "C levels");
-}
+#define enterlevel(ls)	luaE_incCstack(ls->L)
 
 
 #define leavelevel(ls) ((ls)->L->nCcalls--)

+ 25 - 20
lstate.c

@@ -97,25 +97,8 @@ void luaE_setdebt (global_State *g, l_mem debt) {
 
 
 LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
-  global_State *g = G(L);
-  int ccalls;
-  luaE_freeCI(L);  /* release unused CIs */
-  ccalls = getCcalls(L);
-  if (limit >= 40000)
-    return 0;  /* out of bounds */
-  limit += CSTACKERR;
-  if (L != g-> mainthread)
-    return 0;  /* only main thread can change the C stack */
-  else if (ccalls <= CSTACKERR)
-    return 0;  /* handling overflow */
-  else {
-    int diff = limit - g->Cstacklimit;
-    if (ccalls + diff <= CSTACKERR)
-      return 0;  /* new limit would cause an overflow */
-    g->Cstacklimit = limit;  /* set new limit */
-    L->nCcalls += diff;  /* correct 'nCcalls' */
-    return limit - diff - CSTACKERR;  /* success; return previous limit */
-  }
+  UNUSED(L); UNUSED(limit);
+  return LUAI_MAXCCALLS;  /* warning?? */
 }
 
 
@@ -172,6 +155,28 @@ void luaE_shrinkCI (lua_State *L) {
 }
 
 
+/*
+** Called when 'getCcalls(L)' larger or equal to LUAI_MAXCCALLS.
+** If equal, raises an overflow error. If value is larger than
+** LUAI_MAXCCALLS (which means it is handling an overflow) but
+** not much larger, does not report an error (to allow overflow
+** handling to work).
+*/
+void luaE_checkcstack (lua_State *L) {
+  if (getCcalls(L) == LUAI_MAXCCALLS)
+    luaG_runerror(L, "C stack overflow");
+  else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
+    luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
+}
+
+
+LUAI_FUNC void luaE_incCstack (lua_State *L) {
+  L->nCcalls++;
+  if (getCcalls(L) >= LUAI_MAXCCALLS)
+    luaE_checkcstack(L);
+}
+
+
 static void stack_init (lua_State *L1, lua_State *L) {
   int i; CallInfo *ci;
   /* initialize stack array */
@@ -357,7 +362,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   preinit_thread(L, g);
   g->allgc = obj2gco(L);  /* by now, only object is the main thread */
   L->next = NULL;
-  g->Cstacklimit = L->nCcalls = 0;
+  L->nCcalls = 0;
   incnny(L);  /* main thread is always non yieldable */
   g->frealloc = f;
   g->ud = ud;

+ 10 - 46
lstate.h

@@ -87,48 +87,12 @@
 
 
 /*
-** About 'nCcalls': each thread in Lua (a lua_State) keeps a count of
-** how many "C calls" it still can do in the C stack, to avoid C-stack
-** overflow.  This count is very rough approximation; it considers only
-** recursive functions inside the interpreter, as non-recursive calls
-** can be considered using a fixed (although unknown) amount of stack
-** space.
-**
-** The count has two parts: the lower part is the count itself; the
-** higher part counts the number of non-yieldable calls in the stack.
-** (They are together so that we can change both with one instruction.)
-**
-** Because calls to external C functions can use an unknown amount
-** of space (e.g., functions using an auxiliary buffer), calls
-** to these functions add more than one to the count (see CSTACKCF).
-**
-** The proper count excludes the number of CallInfo structures allocated
-** by Lua, as a kind of "potential" calls. So, when Lua calls a function
-** (and "consumes" one CallInfo), it needs neither to decrement nor to
-** check 'nCcalls', as its use of C stack is already accounted for.
-*/
-
-/* number of "C stack slots" used by an external C function */
-#define CSTACKCF	10
-
-
-/*
-** The C-stack size is sliced in the following zones:
-** - larger than CSTACKERR: normal stack;
-** - [CSTACKMARK, CSTACKERR]: buffer zone to signal a stack overflow;
-** - [CSTACKCF, CSTACKERRMARK]: error-handling zone;
-** - below CSTACKERRMARK: buffer zone to signal overflow during overflow;
-** (Because the counter can be decremented CSTACKCF at once, we need
-** the so called "buffer zones", with at least that size, to properly
-** detect a change from one zone to the next.)
+** About 'nCcalls':  This count has two parts: the lower 16 bits counts
+** the number of recursive invocations in the C stack; the higher
+** 16 bits counts the number of non-yieldable calls in the stack.
+** (They are together so that we can change and save both with one
+** instruction.)
 */
-#define CSTACKERR	(8 * CSTACKCF)
-#define CSTACKMARK	(CSTACKERR - (CSTACKCF + 2))
-#define CSTACKERRMARK	(CSTACKCF + 2)
-
-
-/* initial limit for the C-stack of threads */
-#define CSTACKTHREAD	(2 * CSTACKERR)
 
 
 /* true if this thread does not have non-yieldable calls in the stack */
@@ -144,7 +108,8 @@
 /* Decrement the number of non-yieldable calls */
 #define decnny(L)	((L)->nCcalls -= 0x10000)
 
-
+/* Non-yieldable call increment */
+#define nyci	(0x10000 | 1)
 
 
 
@@ -290,7 +255,6 @@ typedef struct global_State {
   TString *strcache[STRCACHE_N][STRCACHE_M];  /* cache for strings in API */
   lua_WarnFunction warnf;  /* warning function */
   void *ud_warn;         /* auxiliary data to 'warnf' */
-  unsigned int Cstacklimit;  /* current limit for the C stack */
 } global_State;
 
 
@@ -314,7 +278,7 @@ struct lua_State {
   CallInfo base_ci;  /* CallInfo for first level (C calling Lua) */
   volatile lua_Hook hook;
   ptrdiff_t errfunc;  /* current error handling function (stack index) */
-  l_uint32 nCcalls;  /* number of allowed nested C calls - 'nci' */
+  l_uint32 nCcalls;  /* number of nested (non-yieldable | C)  calls */
   int oldpc;  /* last pc traced */
   int stacksize;
   int basehookcount;
@@ -383,11 +347,11 @@ LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
 LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
 LUAI_FUNC void luaE_freeCI (lua_State *L);
 LUAI_FUNC void luaE_shrinkCI (lua_State *L);
+LUAI_FUNC void luaE_checkcstack (lua_State *L);
+LUAI_FUNC void luaE_incCstack (lua_State *L);
 LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
 LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
 
 
-#define luaE_exitCcall(L)	((L)->nCcalls++)
-
 #endif
 

+ 0 - 15
luaconf.h

@@ -36,21 +36,6 @@
 ** =====================================================================
 */
 
-/* >>> move back to llimits.h
-@@ LUAI_MAXCCALLS defines the maximum depth for nested calls and
-** also limits the maximum depth of other recursive algorithms in
-** the implementation, such as syntactic analysis. A value too
-** large may allow the interpreter to crash (C-stack overflow).
-** The default value seems ok for regular machines, but may be
-** too high for restricted hardware.
-** The test file 'cstack.lua' may help finding a good limit.
-** (It will crash with a limit too high.)
-*/
-#if !defined(LUAI_MAXCCALLS)
-#define LUAI_MAXCCALLS		200
-#endif
-
-
 /*
 @@ LUA_USE_C89 controls the use of non-ISO-C89 features.
 ** Define it if you want Lua to avoid the use of a few C99 features

+ 3 - 3
lvm.c

@@ -1124,7 +1124,7 @@ void luaV_finishOp (lua_State *L) {
 
 
 void luaV_execute (lua_State *L, CallInfo *ci) {
-  const CallInfo *origci = ci;
+  CallInfo * const origci = ci;
   LClosure *cl;
   TValue *k;
   StkId base;
@@ -1624,7 +1624,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
       vmcase(OP_TAILCALL) {
         int b = GETARG_B(i);  /* number of arguments + 1 (function) */
         int nparams1 = GETARG_C(i);
-        /* delat is virtual 'func' - real 'func' (vararg functions) */
+        /* delta is virtual 'func' - real 'func' (vararg functions) */
         int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
         if (b != 0)
           L->top = ra + b;
@@ -1648,7 +1648,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
           updatetrap(ci);
           updatestack(ci);  /* stack may have been relocated */
           ci->func -= delta;
-          luaD_poscall(L, ci, cast_int(L->top - ra));
+          luaD_poscall(L, ci, cast_int(L->top - ra));  /* finish caller */
           goto ret;
         }
         ci->func -= delta;

+ 17 - 55
manual/manual.of

@@ -2436,8 +2436,16 @@ When you interact with the Lua API,
 you are responsible for ensuring consistency.
 In particular,
 @emph{you are responsible for controlling stack overflow}.
-You can use the function @Lid{lua_checkstack}
-to ensure that the stack has enough space for pushing new elements.
+When you call any API function,
+you must ensure the stack has enough room to accommodate the results.
+
+There is one exception to the above rule:
+When you call a Lua function
+without a fixed number of results @seeF{lua_call},
+Lua ensures that the stack has enough space for all results.
+However, it does not ensure any extra space.
+So, before pushing anything on the stack after such a call
+you should use @Lid{lua_checkstack}.
 
 Whenever Lua calls C,
 it ensures that the stack has space for
@@ -2446,13 +2454,9 @@ that is, you can safely push up to @id{LUA_MINSTACK} values into it.
 @id{LUA_MINSTACK} is defined as 20,
 so that usually you do not have to worry about stack space
 unless your code has loops pushing elements onto the stack.
-
-When you call a Lua function
-without a fixed number of results @seeF{lua_call},
-Lua ensures that the stack has enough space for all results,
-but it does not ensure any extra space.
-So, before pushing anything on the stack after such a call
-you should use @Lid{lua_checkstack}.
+Whenever necessary,
+you can use the function @Lid{lua_checkstack}
+to ensure that the stack has enough space for pushing new elements.
 
 }
 
@@ -2695,7 +2699,7 @@ Therefore, if a @N{C function} @id{foo} calls an API function
 and this API function yields
 (directly or indirectly by calling another function that yields),
 Lua cannot return to @id{foo} any more,
-because the @id{longjmp} removes its frame from the C stack.
+because the @id{longjmp} removes its frame from the @N{C stack}.
 
 To avoid this kind of problem,
 Lua raises an error whenever it tries to yield across an API call,
@@ -2719,7 +2723,7 @@ After the thread resumes,
 it eventually will finish running the callee function.
 However,
 the callee function cannot return to the original function,
-because its frame in the C stack was destroyed by the yield.
+because its frame in the @N{C stack} was destroyed by the yield.
 Instead, Lua calls a @def{continuation function},
 which was given as an argument to the callee function.
 As the name implies,
@@ -2841,7 +2845,7 @@ and therefore may raise any errors.
 
 Converts the @x{acceptable index} @id{idx}
 into an equivalent @x{absolute index}
-(that is, one that does not depend on the stack top).
+(that is, one that does not depend on the stack size).
 
 }
 
@@ -4340,7 +4344,7 @@ as if it was already marked.
 Note that, both in case of errors and of a regular return,
 by the time the @idx{__close} metamethod runs,
 the @N{C stack} was already unwound,
-so that any automatic C variable declared in the calling function
+so that any automatic @N{C variable} declared in the calling function
 will be out of scope.
 
 }
@@ -4955,20 +4959,6 @@ calling @Lid{lua_yield} with @id{nresults} equal to zero
 
 }
 
-@APIEntry{int (lua_setcstacklimit) (lua_State *L, unsigned int limit);|
-@apii{0,0,-}
-
-Sets a new limit for the C stack.
-This limit controls how deeply nested calls can go in Lua,
-with the intent of avoiding a stack overflow.
-Returns the old limit in case of success,
-or zero in case of error.
-For more details about this function,
-see @Lid{debug.setcstacklimit},
-its equivalent in the standard library.
-
-}
-
 @APIEntry{void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);|
 @apii{0,0,-}
 
@@ -8756,34 +8746,6 @@ to the userdata @id{u} plus a boolean,
 
 }
 
-@LibEntry{debug.setcstacklimit (limit)|
-
-Sets a new limit for the C stack.
-This limit controls how deeply nested calls can go in Lua,
-with the intent of avoiding a stack overflow.
-A limit too small restricts recursive calls pointlessly;
-a limit too large exposes the interpreter to stack-overflow crashes.
-Unfortunately, there is no way to know a priori
-the maximum safe limit for a platform.
-
-Each call made from Lua code counts one unit.
-Other operations (e.g., calls made from C to Lua or resuming a coroutine)
-may have a higher cost.
-
-This function has the following restrictions:
-@description{
-@item{It can only be called from the main coroutine (thread);}
-@item{It cannot be called while handling a stack-overflow error;}
-@item{@id{limit} must be less than 40000;}
-@item{@id{limit} cannot be less than the amount of C stack in use.}
-}
-If a call does not respect some restriction,
-it returns a false value.
-Otherwise,
-the call returns the old limit.
-
-}
-
 @LibEntry{debug.sethook ([thread,] hook, mask [, count])|
 
 Sets the given function as the debug hook.

+ 30 - 107
testes/cstack.lua

@@ -1,75 +1,29 @@
 -- $Id: testes/cstack.lua $
 -- See Copyright Notice in file all.lua
 
-do return end
-
-local debug = require "debug"
 
 print"testing C-stack overflow detection"
-print"If this test crashes, see its file ('cstack.lua')"
 
 -- Segmentation faults in these tests probably result from a C-stack
--- overflow. To avoid these errors, you can use the function
--- 'debug.setcstacklimit' to set a smaller limit for the use of
--- C stack by Lua. After finding a reliable limit, you might want
--- to recompile Lua with this limit as the value for
--- the constant 'LUAI_MAXCCALLS', which defines the default limit.
--- (The default limit is printed by this test.)
+-- overflow. To avoid these errors, you should set a smaller limit for
+-- the use of C stack by Lua, by changing the constant 'LUAI_MAXCCALLS'.
 -- Alternatively, you can ensure a larger stack for the program.
 
--- For Linux, a limit up to 30_000 seems Ok. Windows cannot go much
--- higher than 2_000.
-
-
--- get and print original limit
-local origlimit <const> = debug.setcstacklimit(400)
-print("default stack limit: " .. origlimit)
-
-
--- Do the tests using the original limit. Or else you may want to change
--- 'currentlimit' to lower values to avoid a seg. fault or to higher
--- values to check whether they are reliable.
-local currentlimit <const> =  origlimit
-debug.setcstacklimit(currentlimit)
-print("current stack limit: " .. currentlimit)
-
 
 local function checkerror (msg, f, ...)
   local s, err = pcall(f, ...)
   assert(not s and string.find(err, msg))
 end
 
--- auxiliary function to keep 'count' on the screen even if the program
--- crashes.
-local count
-local back = string.rep("\b", 8)
-local function progress ()
-  count = count + 1
-  local n = string.format("%-8d", count)
-  io.stderr:write(back, n)   -- erase previous value and write new one
-end
-
-
-do    print("testing simple recursion:")
-  count = 0
-  local function foo ()
-    progress()
-    foo()   -- do recursive calls until a stack error (or crash)
-  end
-  checkerror("stack overflow", foo)
-  print("\tfinal count: ", count)
-end
-
-
 do  print("testing stack overflow in message handling")
-  count = 0
+  local count = 0
   local function loop (x, y, z)
-    progress()
+    count = count + 1
     return 1 + loop(x, y, z)
   end
   local res, msg = xpcall(loop, loop)
   assert(msg == "error in error handling")
-  print("\tfinal count: ", count)
+  print("final count: ", count)
 end
 
 
@@ -82,97 +36,66 @@ do  print("testing recursion inside pattern matching")
   end
   local m = f(80)
   assert(#m == 80)
-  checkerror("too complex", f, 200000)
+  checkerror("too complex", f, 2000)
 end
 
 
 do  print("testing stack-overflow in recursive 'gsub'")
-  count = 0
+  local count = 0
   local function foo ()
-    progress()
+    count = count + 1
     string.gsub("a", ".", foo)
   end
   checkerror("stack overflow", foo)
-  print("\tfinal count: ", count)
+  print("final count: ", count)
 
   print("testing stack-overflow in recursive 'gsub' with metatables")
-  count = 0
+  local count = 0
   local t = setmetatable({}, {__index = foo})
   foo = function ()
     count = count + 1
-    progress(count)
     string.gsub("a", ".", t)
   end
   checkerror("stack overflow", foo)
-  print("\tfinal count: ", count)
+  print("final count: ", count)
 end
 
+
 do   -- bug in 5.4.0
   print("testing limits in coroutines inside deep calls")
-  count = 0
+  local count = 0
   local lim = 1000
   local function stack (n)
-    progress()
     if n > 0 then return stack(n - 1) + 1
     else coroutine.wrap(function ()
+           count = count + 1
            stack(lim)
          end)()
     end
   end
 
-  print(xpcall(stack, function () return "ok" end, lim))
+  local st, msg = xpcall(stack, function () return "ok" end, lim)
+  assert(not st and msg == "ok")
+  print("final count: ", count)
 end
 
 
-do  print("testing changes in C-stack limit")
+do
+  print("nesting of resuming yielded coroutines")
+  local count = 0
 
-  -- Just an alternative limit, different from the current one
-  -- (smaller to avoid stack overflows)
-  local alterlimit <const> = currentlimit * 8 // 10
-
-  assert(not debug.setcstacklimit(0))        -- limit too small
-  assert(not debug.setcstacklimit(50000))    -- limit too large
-  local co = coroutine.wrap (function ()
-               return debug.setcstacklimit(alterlimit)
-             end)
-  assert(not co())         -- cannot change C stack inside coroutine
-
-  local n
-  local function foo () n = n + 1; foo () end
-
-  local function check ()
-    n = 0
-    pcall(foo)
-    return n
+  local function body ()
+    coroutine.yield()
+    local f = coroutine.wrap(body)
+    f();  -- start new coroutine (will stop in previous yield)
+    count = count + 1
+    f()   -- call it recursively
   end
 
-  -- set limit to 'alterlimit'
-  assert(debug.setcstacklimit(alterlimit) == currentlimit)
-  local limalter <const> = check()
-  -- set a very low limit (given that there are already several active
-  -- calls to arrive here)
-  local lowlimit <const> = 38
-  assert(debug.setcstacklimit(lowlimit) == alterlimit)
-  -- usable limit is much lower, due to active calls
-  local actuallow = check()
-  assert(actuallow < lowlimit - 30)
-  -- now, add 'lowlimit' extra slots, which should all be available
-  assert(debug.setcstacklimit(lowlimit + lowlimit) == lowlimit)
-  local lim2 <const> = check()
-  assert(lim2 == actuallow + lowlimit)
-
-
-  -- 'setcstacklimit' works inside protected calls. (The new stack
-  -- limit is kept when 'pcall' returns.)
-  assert(pcall(function ()
-    assert(debug.setcstacklimit(alterlimit) == lowlimit * 2)
-    assert(check() <= limalter)
-  end))
-
-  assert(check() == limalter)
-  -- restore original limit
-  assert(debug.setcstacklimit(origlimit) == alterlimit)
+  local f = coroutine.wrap(body)
+  f()
+  assert(not pcall(f))
+  print("final count: ", count)
 end
 
-
 print'OK'

+ 2 - 1
testes/errors.lua

@@ -532,7 +532,8 @@ local function testrep (init, rep, close, repc, finalresult)
   end
   s = init .. string.rep(rep, 500)
   local res, msg = load(s)   -- 500 levels not ok
-  assert(not res and string.find(msg, "too many"))
+  assert(not res and (string.find(msg, "too many") or
+                      string.find(msg, "overflow")))
 end
 
 testrep("local a; a", ",a", "= 1", ",1")    -- multiple assignment