summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xall2
-rw-r--r--ldblib.c5
-rw-r--r--ldo.c52
-rw-r--r--llimits.h11
-rw-r--r--lparser.c6
-rw-r--r--lstate.c45
-rw-r--r--lstate.h56
-rw-r--r--luaconf.h15
-rw-r--r--lvm.c6
-rw-r--r--manual/manual.of72
-rw-r--r--testes/cstack.lua137
-rw-r--r--testes/errors.lua3
12 files changed, 127 insertions, 283 deletions
diff --git a/all b/all
index 2a8cb92f..039f6095 100755
--- a/all
+++ b/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
diff --git a/ldblib.c b/ldblib.c
index 59eb8f0e..26058b50 100644
--- a/ldblib.c
+++ b/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;
}
diff --git a/ldo.c b/ldo.c
index dc3cc9fd..0a6a7169 100644
--- a/ldo.c
+++ b/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);
diff --git a/llimits.h b/llimits.h
index 48c97f95..d6866d7c 100644
--- a/llimits.h
+++ b/llimits.h
@@ -235,6 +235,17 @@ typedef l_uint32 Instruction;
/*
+** 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')
*/
diff --git a/lparser.c b/lparser.c
index 502a9b2d..bcdcfb6d 100644
--- a/lparser.c
+++ b/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--)
diff --git a/lstate.c b/lstate.c
index 8cda3072..bd1b5120 100644
--- a/lstate.c
+++ b/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;
diff --git a/lstate.h b/lstate.h
index 983aa0d5..a05db376 100644
--- a/lstate.h
+++ b/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
diff --git a/luaconf.h b/luaconf.h
index 229413d2..d9cf18ca 100644
--- a/luaconf.h
+++ b/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
diff --git a/lvm.c b/lvm.c
index a232e1e7..eadf66bf 100644
--- a/lvm.c
+++ b/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;
diff --git a/manual/manual.of b/manual/manual.of
index 8b34b5bd..86631bbc 100644
--- a/manual/manual.of
+++ b/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.
diff --git a/testes/cstack.lua b/testes/cstack.lua
index c1177f3b..5767adf6 100644
--- a/testes/cstack.lua
+++ b/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'
diff --git a/testes/errors.lua b/testes/errors.lua
index 88918df7..f975b3dd 100644
--- a/testes/errors.lua
+++ b/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