aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-09-23 10:18:01 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-10-12 12:29:09 -0300
commit287b302acb8d925178e9edb800f0a8d18c7d35f6 (patch)
treebd662481ea995dc8c050324d553146e870434d93
parent5d8ce05b3f6fad79e37ed21c1076e47a322472c6 (diff)
downloadlua-287b302acb8d925178e9edb800f0a8d18c7d35f6.tar.gz
lua-287b302acb8d925178e9edb800f0a8d18c7d35f6.tar.bz2
lua-287b302acb8d925178e9edb800f0a8d18c7d35f6.zip
Revision of stackless implementation
- more organized handling of 'nCcalls' - comments - deprecation of 'setcstacklimit'
-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 @@
1make -s -j 1make -s -j
2cd testes/libs; make -s 2cd testes/libs; make -s
3cd .. # back to directory 'testes' 3cd .. # back to directory 'testes'
4ulimit -S -s 2000 4ulimit -S -s 1000
5if { ../lua -W all.lua; } then 5if { ../lua -W all.lua; } then
6 echo -e "\n\n final OK!!!!\n\n" 6 echo -e "\n\n final OK!!!!\n\n"
7else 7else
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) {
440static int db_setcstacklimit (lua_State *L) { 440static int db_setcstacklimit (lua_State *L) {
441 int limit = (int)luaL_checkinteger(L, 1); 441 int limit = (int)luaL_checkinteger(L, 1);
442 int res = lua_setcstacklimit(L, limit); 442 int res = lua_setcstacklimit(L, limit);
443 if (res == 0) 443 lua_pushinteger(L, res);
444 lua_pushboolean(L, 0);
445 else
446 lua_pushinteger(L, res);
447 return 1; 444 return 1;
448} 445}
449 446
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) {
448 448
449 449
450/* 450/*
451** Call a function (C or Lua). The function to be called is at *func. 451** Prepares the call to a function (C or Lua). For C functions, also do
452** The arguments are on the stack, right after the function. 452** the call. The function to be called is at '*func'. The arguments are
453** When returns, all the results are on the stack, starting at the original 453** on the stack, right after the function. Returns true if the call was
454** function position. 454** made (it was a C function). When returns true, all the results are
455** on the stack, starting at the original function position.
455*/ 456*/
456int luaD_precall (lua_State *L, StkId func, int nresults) { 457int luaD_precall (lua_State *L, StkId func, int nresults) {
457 lua_CFunction f; 458 lua_CFunction f;
@@ -511,32 +512,34 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
511} 512}
512 513
513 514
514static void stackerror (lua_State *L) { 515/*
515 if (getCcalls(L) == LUAI_MAXCCALLS) 516** Call a function (C or Lua). 'inc' can be 1 (increment number
516 luaG_runerror(L, "C stack overflow"); 517** of recursive invocations in the C stack) or nyci (the same plus
517 else if (getCcalls(L) >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) 518** increment number of non-yieldable calls).
518 luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ 519*/
519} 520static void docall (lua_State *L, StkId func, int nResults, int inc) {
520 521 L->nCcalls += inc;
521
522void luaD_call (lua_State *L, StkId func, int nResults) {
523 L->nCcalls++;
524 if (getCcalls(L) >= LUAI_MAXCCALLS) 522 if (getCcalls(L) >= LUAI_MAXCCALLS)
525 stackerror(L); 523 luaE_checkcstack(L);
526 if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ 524 if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
527 luaV_execute(L, L->ci); /* call it */ 525 luaV_execute(L, L->ci); /* call it */
528 L->nCcalls--; 526 L->nCcalls -= inc;
529} 527}
530 528
531 529
530/*
531** External interface for 'docall'
532*/
533void luaD_call (lua_State *L, StkId func, int nResults) {
534 return docall(L, func, nResults, 1);
535}
536
532 537
533/* 538/*
534** Similar to 'luaD_call', but does not allow yields during the call. 539** Similar to 'luaD_call', but does not allow yields during the call.
535*/ 540*/
536void luaD_callnoyield (lua_State *L, StkId func, int nResults) { 541void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
537 incnny(L); 542 return docall(L, func, nResults, nyci);
538 luaD_call(L, func, nResults);
539 decnny(L);
540} 543}
541 544
542 545
@@ -650,13 +653,12 @@ static void resume (lua_State *L, void *ud) {
650 int n = *(cast(int*, ud)); /* number of arguments */ 653 int n = *(cast(int*, ud)); /* number of arguments */
651 StkId firstArg = L->top - n; /* first argument */ 654 StkId firstArg = L->top - n; /* first argument */
652 CallInfo *ci = L->ci; 655 CallInfo *ci = L->ci;
653 if (L->status == LUA_OK) { /* starting a coroutine? */ 656 if (L->status == LUA_OK) /* starting a coroutine? */
654 if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ 657 docall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */
655 luaV_execute(L, L->ci); /* call it */
656 }
657 else { /* resuming from previous yield */ 658 else { /* resuming from previous yield */
658 lua_assert(L->status == LUA_YIELD); 659 lua_assert(L->status == LUA_YIELD);
659 L->status = LUA_OK; /* mark that it is running (again) */ 660 L->status = LUA_OK; /* mark that it is running (again) */
661 luaE_incCstack(L); /* control the C stack */
660 if (isLua(ci)) /* yielded inside a hook? */ 662 if (isLua(ci)) /* yielded inside a hook? */
661 luaV_execute(L, ci); /* just continue running Lua code */ 663 luaV_execute(L, ci); /* just continue running Lua code */
662 else { /* 'common' yield */ 664 else { /* 'common' yield */
@@ -684,9 +686,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
684 } 686 }
685 else if (L->status != LUA_YIELD) /* ended with errors? */ 687 else if (L->status != LUA_YIELD) /* ended with errors? */
686 return resume_error(L, "cannot resume dead coroutine", nargs); 688 return resume_error(L, "cannot resume dead coroutine", nargs);
687 L->nCcalls = (from) ? getCcalls(from) + 1 : 1; 689 L->nCcalls = (from) ? getCcalls(from) : 0;
688 if (getCcalls(L) >= LUAI_MAXCCALLS)
689 return resume_error(L, "C stack overflow", nargs);
690 luai_userstateresume(L, nargs); 690 luai_userstateresume(L, nargs);
691 api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); 691 api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
692 status = luaD_rawrunprotected(L, resume, &nargs); 692 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;
235 235
236 236
237/* 237/*
238** Maximum depth for nested C calls, syntactical nested non-terminals,
239** and other features implemented through recursion in C. (Value must
240** fit in a 16-bit unsigned integer. It must also be compatible with
241** the size of the C stack.)
242*/
243#if !defined(LUAI_MAXCCALLS)
244#define LUAI_MAXCCALLS 200
245#endif
246
247
248/*
238** macros that are executed whenever program enters the Lua core 249** macros that are executed whenever program enters the Lua core
239** ('lua_lock') and leaves the core ('lua_unlock') 250** ('lua_lock') and leaves the core ('lua_unlock')
240*/ 251*/
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) {
489} 489}
490 490
491 491
492static void enterlevel (LexState *ls) { 492#define enterlevel(ls) luaE_incCstack(ls->L)
493 lua_State *L = ls->L;
494 L->nCcalls++;
495 checklimit(ls->fs, getCcalls(L), LUAI_MAXCCALLS, "C levels");
496}
497 493
498 494
499#define leavelevel(ls) ((ls)->L->nCcalls--) 495#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) {
97 97
98 98
99LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) { 99LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
100 global_State *g = G(L); 100 UNUSED(L); UNUSED(limit);
101 int ccalls; 101 return LUAI_MAXCCALLS; /* warning?? */
102 luaE_freeCI(L); /* release unused CIs */
103 ccalls = getCcalls(L);
104 if (limit >= 40000)
105 return 0; /* out of bounds */
106 limit += CSTACKERR;
107 if (L != g-> mainthread)
108 return 0; /* only main thread can change the C stack */
109 else if (ccalls <= CSTACKERR)
110 return 0; /* handling overflow */
111 else {
112 int diff = limit - g->Cstacklimit;
113 if (ccalls + diff <= CSTACKERR)
114 return 0; /* new limit would cause an overflow */
115 g->Cstacklimit = limit; /* set new limit */
116 L->nCcalls += diff; /* correct 'nCcalls' */
117 return limit - diff - CSTACKERR; /* success; return previous limit */
118 }
119} 102}
120 103
121 104
@@ -172,6 +155,28 @@ void luaE_shrinkCI (lua_State *L) {
172} 155}
173 156
174 157
158/*
159** Called when 'getCcalls(L)' larger or equal to LUAI_MAXCCALLS.
160** If equal, raises an overflow error. If value is larger than
161** LUAI_MAXCCALLS (which means it is handling an overflow) but
162** not much larger, does not report an error (to allow overflow
163** handling to work).
164*/
165void luaE_checkcstack (lua_State *L) {
166 if (getCcalls(L) == LUAI_MAXCCALLS)
167 luaG_runerror(L, "C stack overflow");
168 else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
169 luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
170}
171
172
173LUAI_FUNC void luaE_incCstack (lua_State *L) {
174 L->nCcalls++;
175 if (getCcalls(L) >= LUAI_MAXCCALLS)
176 luaE_checkcstack(L);
177}
178
179
175static void stack_init (lua_State *L1, lua_State *L) { 180static void stack_init (lua_State *L1, lua_State *L) {
176 int i; CallInfo *ci; 181 int i; CallInfo *ci;
177 /* initialize stack array */ 182 /* initialize stack array */
@@ -357,7 +362,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
357 preinit_thread(L, g); 362 preinit_thread(L, g);
358 g->allgc = obj2gco(L); /* by now, only object is the main thread */ 363 g->allgc = obj2gco(L); /* by now, only object is the main thread */
359 L->next = NULL; 364 L->next = NULL;
360 g->Cstacklimit = L->nCcalls = 0; 365 L->nCcalls = 0;
361 incnny(L); /* main thread is always non yieldable */ 366 incnny(L); /* main thread is always non yieldable */
362 g->frealloc = f; 367 g->frealloc = f;
363 g->ud = ud; 368 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 @@
87 87
88 88
89/* 89/*
90** About 'nCcalls': each thread in Lua (a lua_State) keeps a count of 90** About 'nCcalls': This count has two parts: the lower 16 bits counts
91** how many "C calls" it still can do in the C stack, to avoid C-stack 91** the number of recursive invocations in the C stack; the higher
92** overflow. This count is very rough approximation; it considers only 92** 16 bits counts the number of non-yieldable calls in the stack.
93** recursive functions inside the interpreter, as non-recursive calls 93** (They are together so that we can change and save both with one
94** can be considered using a fixed (although unknown) amount of stack 94** instruction.)
95** space.
96**
97** The count has two parts: the lower part is the count itself; the
98** higher part counts the number of non-yieldable calls in the stack.
99** (They are together so that we can change both with one instruction.)
100**
101** Because calls to external C functions can use an unknown amount
102** of space (e.g., functions using an auxiliary buffer), calls
103** to these functions add more than one to the count (see CSTACKCF).
104**
105** The proper count excludes the number of CallInfo structures allocated
106** by Lua, as a kind of "potential" calls. So, when Lua calls a function
107** (and "consumes" one CallInfo), it needs neither to decrement nor to
108** check 'nCcalls', as its use of C stack is already accounted for.
109*/
110
111/* number of "C stack slots" used by an external C function */
112#define CSTACKCF 10
113
114
115/*
116** The C-stack size is sliced in the following zones:
117** - larger than CSTACKERR: normal stack;
118** - [CSTACKMARK, CSTACKERR]: buffer zone to signal a stack overflow;
119** - [CSTACKCF, CSTACKERRMARK]: error-handling zone;
120** - below CSTACKERRMARK: buffer zone to signal overflow during overflow;
121** (Because the counter can be decremented CSTACKCF at once, we need
122** the so called "buffer zones", with at least that size, to properly
123** detect a change from one zone to the next.)
124*/ 95*/
125#define CSTACKERR (8 * CSTACKCF)
126#define CSTACKMARK (CSTACKERR - (CSTACKCF + 2))
127#define CSTACKERRMARK (CSTACKCF + 2)
128
129
130/* initial limit for the C-stack of threads */
131#define CSTACKTHREAD (2 * CSTACKERR)
132 96
133 97
134/* true if this thread does not have non-yieldable calls in the stack */ 98/* true if this thread does not have non-yieldable calls in the stack */
@@ -144,7 +108,8 @@
144/* Decrement the number of non-yieldable calls */ 108/* Decrement the number of non-yieldable calls */
145#define decnny(L) ((L)->nCcalls -= 0x10000) 109#define decnny(L) ((L)->nCcalls -= 0x10000)
146 110
147 111/* Non-yieldable call increment */
112#define nyci (0x10000 | 1)
148 113
149 114
150 115
@@ -290,7 +255,6 @@ typedef struct global_State {
290 TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ 255 TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
291 lua_WarnFunction warnf; /* warning function */ 256 lua_WarnFunction warnf; /* warning function */
292 void *ud_warn; /* auxiliary data to 'warnf' */ 257 void *ud_warn; /* auxiliary data to 'warnf' */
293 unsigned int Cstacklimit; /* current limit for the C stack */
294} global_State; 258} global_State;
295 259
296 260
@@ -314,7 +278,7 @@ struct lua_State {
314 CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ 278 CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
315 volatile lua_Hook hook; 279 volatile lua_Hook hook;
316 ptrdiff_t errfunc; /* current error handling function (stack index) */ 280 ptrdiff_t errfunc; /* current error handling function (stack index) */
317 l_uint32 nCcalls; /* number of allowed nested C calls - 'nci' */ 281 l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */
318 int oldpc; /* last pc traced */ 282 int oldpc; /* last pc traced */
319 int stacksize; 283 int stacksize;
320 int basehookcount; 284 int basehookcount;
@@ -383,11 +347,11 @@ LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
383LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); 347LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
384LUAI_FUNC void luaE_freeCI (lua_State *L); 348LUAI_FUNC void luaE_freeCI (lua_State *L);
385LUAI_FUNC void luaE_shrinkCI (lua_State *L); 349LUAI_FUNC void luaE_shrinkCI (lua_State *L);
350LUAI_FUNC void luaE_checkcstack (lua_State *L);
351LUAI_FUNC void luaE_incCstack (lua_State *L);
386LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); 352LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
387LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); 353LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
388 354
389 355
390#define luaE_exitCcall(L) ((L)->nCcalls++)
391
392#endif 356#endif
393 357
diff --git a/luaconf.h b/luaconf.h
index 229413d2..d9cf18ca 100644
--- a/luaconf.h
+++ b/luaconf.h
@@ -36,21 +36,6 @@
36** ===================================================================== 36** =====================================================================
37*/ 37*/
38 38
39/* >>> move back to llimits.h
40@@ LUAI_MAXCCALLS defines the maximum depth for nested calls and
41** also limits the maximum depth of other recursive algorithms in
42** the implementation, such as syntactic analysis. A value too
43** large may allow the interpreter to crash (C-stack overflow).
44** The default value seems ok for regular machines, but may be
45** too high for restricted hardware.
46** The test file 'cstack.lua' may help finding a good limit.
47** (It will crash with a limit too high.)
48*/
49#if !defined(LUAI_MAXCCALLS)
50#define LUAI_MAXCCALLS 200
51#endif
52
53
54/* 39/*
55@@ LUA_USE_C89 controls the use of non-ISO-C89 features. 40@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
56** Define it if you want Lua to avoid the use of a few C99 features 41** 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) {
1124 1124
1125 1125
1126void luaV_execute (lua_State *L, CallInfo *ci) { 1126void luaV_execute (lua_State *L, CallInfo *ci) {
1127 const CallInfo *origci = ci; 1127 CallInfo * const origci = ci;
1128 LClosure *cl; 1128 LClosure *cl;
1129 TValue *k; 1129 TValue *k;
1130 StkId base; 1130 StkId base;
@@ -1624,7 +1624,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1624 vmcase(OP_TAILCALL) { 1624 vmcase(OP_TAILCALL) {
1625 int b = GETARG_B(i); /* number of arguments + 1 (function) */ 1625 int b = GETARG_B(i); /* number of arguments + 1 (function) */
1626 int nparams1 = GETARG_C(i); 1626 int nparams1 = GETARG_C(i);
1627 /* delat is virtual 'func' - real 'func' (vararg functions) */ 1627 /* delta is virtual 'func' - real 'func' (vararg functions) */
1628 int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; 1628 int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
1629 if (b != 0) 1629 if (b != 0)
1630 L->top = ra + b; 1630 L->top = ra + b;
@@ -1648,7 +1648,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1648 updatetrap(ci); 1648 updatetrap(ci);
1649 updatestack(ci); /* stack may have been relocated */ 1649 updatestack(ci); /* stack may have been relocated */
1650 ci->func -= delta; 1650 ci->func -= delta;
1651 luaD_poscall(L, ci, cast_int(L->top - ra)); 1651 luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */
1652 goto ret; 1652 goto ret;
1653 } 1653 }
1654 ci->func -= delta; 1654 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,
2436you are responsible for ensuring consistency. 2436you are responsible for ensuring consistency.
2437In particular, 2437In particular,
2438@emph{you are responsible for controlling stack overflow}. 2438@emph{you are responsible for controlling stack overflow}.
2439You can use the function @Lid{lua_checkstack} 2439When you call any API function,
2440to ensure that the stack has enough space for pushing new elements. 2440you must ensure the stack has enough room to accommodate the results.
2441
2442There is one exception to the above rule:
2443When you call a Lua function
2444without a fixed number of results @seeF{lua_call},
2445Lua ensures that the stack has enough space for all results.
2446However, it does not ensure any extra space.
2447So, before pushing anything on the stack after such a call
2448you should use @Lid{lua_checkstack}.
2441 2449
2442Whenever Lua calls C, 2450Whenever Lua calls C,
2443it ensures that the stack has space for 2451it 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.
2446@id{LUA_MINSTACK} is defined as 20, 2454@id{LUA_MINSTACK} is defined as 20,
2447so that usually you do not have to worry about stack space 2455so that usually you do not have to worry about stack space
2448unless your code has loops pushing elements onto the stack. 2456unless your code has loops pushing elements onto the stack.
2449 2457Whenever necessary,
2450When you call a Lua function 2458you can use the function @Lid{lua_checkstack}
2451without a fixed number of results @seeF{lua_call}, 2459to ensure that the stack has enough space for pushing new elements.
2452Lua ensures that the stack has enough space for all results,
2453but it does not ensure any extra space.
2454So, before pushing anything on the stack after such a call
2455you should use @Lid{lua_checkstack}.
2456 2460
2457} 2461}
2458 2462
@@ -2695,7 +2699,7 @@ Therefore, if a @N{C function} @id{foo} calls an API function
2695and this API function yields 2699and this API function yields
2696(directly or indirectly by calling another function that yields), 2700(directly or indirectly by calling another function that yields),
2697Lua cannot return to @id{foo} any more, 2701Lua cannot return to @id{foo} any more,
2698because the @id{longjmp} removes its frame from the C stack. 2702because the @id{longjmp} removes its frame from the @N{C stack}.
2699 2703
2700To avoid this kind of problem, 2704To avoid this kind of problem,
2701Lua raises an error whenever it tries to yield across an API call, 2705Lua raises an error whenever it tries to yield across an API call,
@@ -2719,7 +2723,7 @@ After the thread resumes,
2719it eventually will finish running the callee function. 2723it eventually will finish running the callee function.
2720However, 2724However,
2721the callee function cannot return to the original function, 2725the callee function cannot return to the original function,
2722because its frame in the C stack was destroyed by the yield. 2726because its frame in the @N{C stack} was destroyed by the yield.
2723Instead, Lua calls a @def{continuation function}, 2727Instead, Lua calls a @def{continuation function},
2724which was given as an argument to the callee function. 2728which was given as an argument to the callee function.
2725As the name implies, 2729As the name implies,
@@ -2841,7 +2845,7 @@ and therefore may raise any errors.
2841 2845
2842Converts the @x{acceptable index} @id{idx} 2846Converts the @x{acceptable index} @id{idx}
2843into an equivalent @x{absolute index} 2847into an equivalent @x{absolute index}
2844(that is, one that does not depend on the stack top). 2848(that is, one that does not depend on the stack size).
2845 2849
2846} 2850}
2847 2851
@@ -4340,7 +4344,7 @@ as if it was already marked.
4340Note that, both in case of errors and of a regular return, 4344Note that, both in case of errors and of a regular return,
4341by the time the @idx{__close} metamethod runs, 4345by the time the @idx{__close} metamethod runs,
4342the @N{C stack} was already unwound, 4346the @N{C stack} was already unwound,
4343so that any automatic C variable declared in the calling function 4347so that any automatic @N{C variable} declared in the calling function
4344will be out of scope. 4348will be out of scope.
4345 4349
4346} 4350}
@@ -4955,20 +4959,6 @@ calling @Lid{lua_yield} with @id{nresults} equal to zero
4955 4959
4956} 4960}
4957 4961
4958@APIEntry{int (lua_setcstacklimit) (lua_State *L, unsigned int limit);|
4959@apii{0,0,-}
4960
4961Sets a new limit for the C stack.
4962This limit controls how deeply nested calls can go in Lua,
4963with the intent of avoiding a stack overflow.
4964Returns the old limit in case of success,
4965or zero in case of error.
4966For more details about this function,
4967see @Lid{debug.setcstacklimit},
4968its equivalent in the standard library.
4969
4970}
4971
4972@APIEntry{void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);| 4962@APIEntry{void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);|
4973@apii{0,0,-} 4963@apii{0,0,-}
4974 4964
@@ -8756,34 +8746,6 @@ to the userdata @id{u} plus a boolean,
8756 8746
8757} 8747}
8758 8748
8759@LibEntry{debug.setcstacklimit (limit)|
8760
8761Sets a new limit for the C stack.
8762This limit controls how deeply nested calls can go in Lua,
8763with the intent of avoiding a stack overflow.
8764A limit too small restricts recursive calls pointlessly;
8765a limit too large exposes the interpreter to stack-overflow crashes.
8766Unfortunately, there is no way to know a priori
8767the maximum safe limit for a platform.
8768
8769Each call made from Lua code counts one unit.
8770Other operations (e.g., calls made from C to Lua or resuming a coroutine)
8771may have a higher cost.
8772
8773This function has the following restrictions:
8774@description{
8775@item{It can only be called from the main coroutine (thread);}
8776@item{It cannot be called while handling a stack-overflow error;}
8777@item{@id{limit} must be less than 40000;}
8778@item{@id{limit} cannot be less than the amount of C stack in use.}
8779}
8780If a call does not respect some restriction,
8781it returns a false value.
8782Otherwise,
8783the call returns the old limit.
8784
8785}
8786
8787@LibEntry{debug.sethook ([thread,] hook, mask [, count])| 8749@LibEntry{debug.sethook ([thread,] hook, mask [, count])|
8788 8750
8789Sets the given function as the debug hook. 8751Sets 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 @@
1-- $Id: testes/cstack.lua $ 1-- $Id: testes/cstack.lua $
2-- See Copyright Notice in file all.lua 2-- See Copyright Notice in file all.lua
3 3
4do return end
5
6local debug = require "debug"
7 4
8print"testing C-stack overflow detection" 5print"testing C-stack overflow detection"
9print"If this test crashes, see its file ('cstack.lua')"
10 6
11-- Segmentation faults in these tests probably result from a C-stack 7-- Segmentation faults in these tests probably result from a C-stack
12-- overflow. To avoid these errors, you can use the function 8-- overflow. To avoid these errors, you should set a smaller limit for
13-- 'debug.setcstacklimit' to set a smaller limit for the use of 9-- the use of C stack by Lua, by changing the constant 'LUAI_MAXCCALLS'.
14-- C stack by Lua. After finding a reliable limit, you might want
15-- to recompile Lua with this limit as the value for
16-- the constant 'LUAI_MAXCCALLS', which defines the default limit.
17-- (The default limit is printed by this test.)
18-- Alternatively, you can ensure a larger stack for the program. 10-- Alternatively, you can ensure a larger stack for the program.
19 11
20-- For Linux, a limit up to 30_000 seems Ok. Windows cannot go much
21-- higher than 2_000.
22
23
24-- get and print original limit
25local origlimit <const> = debug.setcstacklimit(400)
26print("default stack limit: " .. origlimit)
27
28
29-- Do the tests using the original limit. Or else you may want to change
30-- 'currentlimit' to lower values to avoid a seg. fault or to higher
31-- values to check whether they are reliable.
32local currentlimit <const> = origlimit
33debug.setcstacklimit(currentlimit)
34print("current stack limit: " .. currentlimit)
35
36 12
37local function checkerror (msg, f, ...) 13local function checkerror (msg, f, ...)
38 local s, err = pcall(f, ...) 14 local s, err = pcall(f, ...)
39 assert(not s and string.find(err, msg)) 15 assert(not s and string.find(err, msg))
40end 16end
41 17
42-- auxiliary function to keep 'count' on the screen even if the program
43-- crashes.
44local count
45local back = string.rep("\b", 8)
46local function progress ()
47 count = count + 1
48 local n = string.format("%-8d", count)
49 io.stderr:write(back, n) -- erase previous value and write new one
50end
51
52
53do print("testing simple recursion:")
54 count = 0
55 local function foo ()
56 progress()
57 foo() -- do recursive calls until a stack error (or crash)
58 end
59 checkerror("stack overflow", foo)
60 print("\tfinal count: ", count)
61end
62
63
64do print("testing stack overflow in message handling") 18do print("testing stack overflow in message handling")
65 count = 0 19 local count = 0
66 local function loop (x, y, z) 20 local function loop (x, y, z)
67 progress() 21 count = count + 1
68 return 1 + loop(x, y, z) 22 return 1 + loop(x, y, z)
69 end 23 end
70 local res, msg = xpcall(loop, loop) 24 local res, msg = xpcall(loop, loop)
71 assert(msg == "error in error handling") 25 assert(msg == "error in error handling")
72 print("\tfinal count: ", count) 26 print("final count: ", count)
73end 27end
74 28
75 29
@@ -82,97 +36,66 @@ do print("testing recursion inside pattern matching")
82 end 36 end
83 local m = f(80) 37 local m = f(80)
84 assert(#m == 80) 38 assert(#m == 80)
85 checkerror("too complex", f, 200000) 39 checkerror("too complex", f, 2000)
86end 40end
87 41
88 42
89do print("testing stack-overflow in recursive 'gsub'") 43do print("testing stack-overflow in recursive 'gsub'")
90 count = 0 44 local count = 0
91 local function foo () 45 local function foo ()
92 progress() 46 count = count + 1
93 string.gsub("a", ".", foo) 47 string.gsub("a", ".", foo)
94 end 48 end
95 checkerror("stack overflow", foo) 49 checkerror("stack overflow", foo)
96 print("\tfinal count: ", count) 50 print("final count: ", count)
97 51
98 print("testing stack-overflow in recursive 'gsub' with metatables") 52 print("testing stack-overflow in recursive 'gsub' with metatables")
99 count = 0 53 local count = 0
100 local t = setmetatable({}, {__index = foo}) 54 local t = setmetatable({}, {__index = foo})
101 foo = function () 55 foo = function ()
102 count = count + 1 56 count = count + 1
103 progress(count)
104 string.gsub("a", ".", t) 57 string.gsub("a", ".", t)
105 end 58 end
106 checkerror("stack overflow", foo) 59 checkerror("stack overflow", foo)
107 print("\tfinal count: ", count) 60 print("final count: ", count)
108end 61end
109 62
63
110do -- bug in 5.4.0 64do -- bug in 5.4.0
111 print("testing limits in coroutines inside deep calls") 65 print("testing limits in coroutines inside deep calls")
112 count = 0 66 local count = 0
113 local lim = 1000 67 local lim = 1000
114 local function stack (n) 68 local function stack (n)
115 progress()
116 if n > 0 then return stack(n - 1) + 1 69 if n > 0 then return stack(n - 1) + 1
117 else coroutine.wrap(function () 70 else coroutine.wrap(function ()
71 count = count + 1
118 stack(lim) 72 stack(lim)
119 end)() 73 end)()
120 end 74 end
121 end 75 end
122 76
123 print(xpcall(stack, function () return "ok" end, lim)) 77 local st, msg = xpcall(stack, function () return "ok" end, lim)
78 assert(not st and msg == "ok")
79 print("final count: ", count)
124end 80end
125 81
126 82
127do print("testing changes in C-stack limit") 83do
84 print("nesting of resuming yielded coroutines")
85 local count = 0
128 86
129 -- Just an alternative limit, different from the current one 87 local function body ()
130 -- (smaller to avoid stack overflows) 88 coroutine.yield()
131 local alterlimit <const> = currentlimit * 8 // 10 89 local f = coroutine.wrap(body)
132 90 f(); -- start new coroutine (will stop in previous yield)
133 assert(not debug.setcstacklimit(0)) -- limit too small 91 count = count + 1
134 assert(not debug.setcstacklimit(50000)) -- limit too large 92 f() -- call it recursively
135 local co = coroutine.wrap (function ()
136 return debug.setcstacklimit(alterlimit)
137 end)
138 assert(not co()) -- cannot change C stack inside coroutine
139
140 local n
141 local function foo () n = n + 1; foo () end
142
143 local function check ()
144 n = 0
145 pcall(foo)
146 return n
147 end 93 end
148 94
149 -- set limit to 'alterlimit' 95 local f = coroutine.wrap(body)
150 assert(debug.setcstacklimit(alterlimit) == currentlimit) 96 f()
151 local limalter <const> = check() 97 assert(not pcall(f))
152 -- set a very low limit (given that there are already several active 98 print("final count: ", count)
153 -- calls to arrive here)
154 local lowlimit <const> = 38
155 assert(debug.setcstacklimit(lowlimit) == alterlimit)
156 -- usable limit is much lower, due to active calls
157 local actuallow = check()
158 assert(actuallow < lowlimit - 30)
159 -- now, add 'lowlimit' extra slots, which should all be available
160 assert(debug.setcstacklimit(lowlimit + lowlimit) == lowlimit)
161 local lim2 <const> = check()
162 assert(lim2 == actuallow + lowlimit)
163
164
165 -- 'setcstacklimit' works inside protected calls. (The new stack
166 -- limit is kept when 'pcall' returns.)
167 assert(pcall(function ()
168 assert(debug.setcstacklimit(alterlimit) == lowlimit * 2)
169 assert(check() <= limalter)
170 end))
171
172 assert(check() == limalter)
173 -- restore original limit
174 assert(debug.setcstacklimit(origlimit) == alterlimit)
175end 99end
176 100
177
178print'OK' 101print'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)
532 end 532 end
533 s = init .. string.rep(rep, 500) 533 s = init .. string.rep(rep, 500)
534 local res, msg = load(s) -- 500 levels not ok 534 local res, msg = load(s) -- 500 levels not ok
535 assert(not res and string.find(msg, "too many")) 535 assert(not res and (string.find(msg, "too many") or
536 string.find(msg, "overflow")))
536end 537end
537 538
538testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment 539testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment