diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-09-23 10:18:01 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-10-12 12:29:09 -0300 |
commit | 287b302acb8d925178e9edb800f0a8d18c7d35f6 (patch) | |
tree | bd662481ea995dc8c050324d553146e870434d93 | |
parent | 5d8ce05b3f6fad79e37ed21c1076e47a322472c6 (diff) | |
download | lua-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-x | all | 2 | ||||
-rw-r--r-- | ldblib.c | 5 | ||||
-rw-r--r-- | ldo.c | 52 | ||||
-rw-r--r-- | llimits.h | 11 | ||||
-rw-r--r-- | lparser.c | 6 | ||||
-rw-r--r-- | lstate.c | 45 | ||||
-rw-r--r-- | lstate.h | 56 | ||||
-rw-r--r-- | luaconf.h | 15 | ||||
-rw-r--r-- | lvm.c | 6 | ||||
-rw-r--r-- | manual/manual.of | 72 | ||||
-rw-r--r-- | testes/cstack.lua | 137 | ||||
-rw-r--r-- | testes/errors.lua | 3 |
12 files changed, 127 insertions, 283 deletions
@@ -1,7 +1,7 @@ | |||
1 | make -s -j | 1 | make -s -j |
2 | cd testes/libs; make -s | 2 | cd testes/libs; make -s |
3 | cd .. # back to directory 'testes' | 3 | cd .. # back to directory 'testes' |
4 | ulimit -S -s 2000 | 4 | ulimit -S -s 1000 |
5 | if { ../lua -W all.lua; } then | 5 | if { ../lua -W all.lua; } then |
6 | echo -e "\n\n final OK!!!!\n\n" | 6 | echo -e "\n\n final OK!!!!\n\n" |
7 | else | 7 | else |
@@ -440,10 +440,7 @@ static int db_traceback (lua_State *L) { | |||
440 | static int db_setcstacklimit (lua_State *L) { | 440 | static 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 | ||
@@ -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 | */ |
456 | int luaD_precall (lua_State *L, StkId func, int nresults) { | 457 | int 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 | ||
514 | static 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 | } | 520 | static void docall (lua_State *L, StkId func, int nResults, int inc) { |
520 | 521 | L->nCcalls += inc; | |
521 | |||
522 | void 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 | */ | ||
533 | void 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 | */ |
536 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { | 541 | void 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); |
@@ -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 | */ |
@@ -489,11 +489,7 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { | |||
489 | } | 489 | } |
490 | 490 | ||
491 | 491 | ||
492 | static 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--) |
@@ -97,25 +97,8 @@ void luaE_setdebt (global_State *g, l_mem debt) { | |||
97 | 97 | ||
98 | 98 | ||
99 | LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) { | 99 | LUA_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 | */ | ||
165 | void 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 | |||
173 | LUAI_FUNC void luaE_incCstack (lua_State *L) { | ||
174 | L->nCcalls++; | ||
175 | if (getCcalls(L) >= LUAI_MAXCCALLS) | ||
176 | luaE_checkcstack(L); | ||
177 | } | ||
178 | |||
179 | |||
175 | static void stack_init (lua_State *L1, lua_State *L) { | 180 | static 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; |
@@ -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); | |||
383 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); | 347 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); |
384 | LUAI_FUNC void luaE_freeCI (lua_State *L); | 348 | LUAI_FUNC void luaE_freeCI (lua_State *L); |
385 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); | 349 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); |
350 | LUAI_FUNC void luaE_checkcstack (lua_State *L); | ||
351 | LUAI_FUNC void luaE_incCstack (lua_State *L); | ||
386 | LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); | 352 | LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); |
387 | LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); | 353 | LUAI_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 | ||
@@ -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 |
@@ -1124,7 +1124,7 @@ void luaV_finishOp (lua_State *L) { | |||
1124 | 1124 | ||
1125 | 1125 | ||
1126 | void luaV_execute (lua_State *L, CallInfo *ci) { | 1126 | void 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, | |||
2436 | you are responsible for ensuring consistency. | 2436 | you are responsible for ensuring consistency. |
2437 | In particular, | 2437 | In particular, |
2438 | @emph{you are responsible for controlling stack overflow}. | 2438 | @emph{you are responsible for controlling stack overflow}. |
2439 | You can use the function @Lid{lua_checkstack} | 2439 | When you call any API function, |
2440 | to ensure that the stack has enough space for pushing new elements. | 2440 | you must ensure the stack has enough room to accommodate the results. |
2441 | |||
2442 | There is one exception to the above rule: | ||
2443 | When you call a Lua function | ||
2444 | without a fixed number of results @seeF{lua_call}, | ||
2445 | Lua ensures that the stack has enough space for all results. | ||
2446 | However, it does not ensure any extra space. | ||
2447 | So, before pushing anything on the stack after such a call | ||
2448 | you should use @Lid{lua_checkstack}. | ||
2441 | 2449 | ||
2442 | Whenever Lua calls C, | 2450 | Whenever Lua calls C, |
2443 | it ensures that the stack has space for | 2451 | 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. | |||
2446 | @id{LUA_MINSTACK} is defined as 20, | 2454 | @id{LUA_MINSTACK} is defined as 20, |
2447 | so that usually you do not have to worry about stack space | 2455 | so that usually you do not have to worry about stack space |
2448 | unless your code has loops pushing elements onto the stack. | 2456 | unless your code has loops pushing elements onto the stack. |
2449 | 2457 | Whenever necessary, | |
2450 | When you call a Lua function | 2458 | you can use the function @Lid{lua_checkstack} |
2451 | without a fixed number of results @seeF{lua_call}, | 2459 | to ensure that the stack has enough space for pushing new elements. |
2452 | Lua ensures that the stack has enough space for all results, | ||
2453 | but it does not ensure any extra space. | ||
2454 | So, before pushing anything on the stack after such a call | ||
2455 | you 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 | |||
2695 | and this API function yields | 2699 | and this API function yields |
2696 | (directly or indirectly by calling another function that yields), | 2700 | (directly or indirectly by calling another function that yields), |
2697 | Lua cannot return to @id{foo} any more, | 2701 | Lua cannot return to @id{foo} any more, |
2698 | because the @id{longjmp} removes its frame from the C stack. | 2702 | because the @id{longjmp} removes its frame from the @N{C stack}. |
2699 | 2703 | ||
2700 | To avoid this kind of problem, | 2704 | To avoid this kind of problem, |
2701 | Lua raises an error whenever it tries to yield across an API call, | 2705 | Lua raises an error whenever it tries to yield across an API call, |
@@ -2719,7 +2723,7 @@ After the thread resumes, | |||
2719 | it eventually will finish running the callee function. | 2723 | it eventually will finish running the callee function. |
2720 | However, | 2724 | However, |
2721 | the callee function cannot return to the original function, | 2725 | the callee function cannot return to the original function, |
2722 | because its frame in the C stack was destroyed by the yield. | 2726 | because its frame in the @N{C stack} was destroyed by the yield. |
2723 | Instead, Lua calls a @def{continuation function}, | 2727 | Instead, Lua calls a @def{continuation function}, |
2724 | which was given as an argument to the callee function. | 2728 | which was given as an argument to the callee function. |
2725 | As the name implies, | 2729 | As the name implies, |
@@ -2841,7 +2845,7 @@ and therefore may raise any errors. | |||
2841 | 2845 | ||
2842 | Converts the @x{acceptable index} @id{idx} | 2846 | Converts the @x{acceptable index} @id{idx} |
2843 | into an equivalent @x{absolute index} | 2847 | into 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. | |||
4340 | Note that, both in case of errors and of a regular return, | 4344 | Note that, both in case of errors and of a regular return, |
4341 | by the time the @idx{__close} metamethod runs, | 4345 | by the time the @idx{__close} metamethod runs, |
4342 | the @N{C stack} was already unwound, | 4346 | the @N{C stack} was already unwound, |
4343 | so that any automatic C variable declared in the calling function | 4347 | so that any automatic @N{C variable} declared in the calling function |
4344 | will be out of scope. | 4348 | will 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 | |||
4961 | Sets a new limit for the C stack. | ||
4962 | This limit controls how deeply nested calls can go in Lua, | ||
4963 | with the intent of avoiding a stack overflow. | ||
4964 | Returns the old limit in case of success, | ||
4965 | or zero in case of error. | ||
4966 | For more details about this function, | ||
4967 | see @Lid{debug.setcstacklimit}, | ||
4968 | its 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 | |||
8761 | Sets a new limit for the C stack. | ||
8762 | This limit controls how deeply nested calls can go in Lua, | ||
8763 | with the intent of avoiding a stack overflow. | ||
8764 | A limit too small restricts recursive calls pointlessly; | ||
8765 | a limit too large exposes the interpreter to stack-overflow crashes. | ||
8766 | Unfortunately, there is no way to know a priori | ||
8767 | the maximum safe limit for a platform. | ||
8768 | |||
8769 | Each call made from Lua code counts one unit. | ||
8770 | Other operations (e.g., calls made from C to Lua or resuming a coroutine) | ||
8771 | may have a higher cost. | ||
8772 | |||
8773 | This 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 | } | ||
8780 | If a call does not respect some restriction, | ||
8781 | it returns a false value. | ||
8782 | Otherwise, | ||
8783 | the 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 | ||
8789 | Sets the given function as the debug hook. | 8751 | 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 @@ | |||
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 | ||
4 | do return end | ||
5 | |||
6 | local debug = require "debug" | ||
7 | 4 | ||
8 | print"testing C-stack overflow detection" | 5 | print"testing C-stack overflow detection" |
9 | print"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 | ||
25 | local origlimit <const> = debug.setcstacklimit(400) | ||
26 | print("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. | ||
32 | local currentlimit <const> = origlimit | ||
33 | debug.setcstacklimit(currentlimit) | ||
34 | print("current stack limit: " .. currentlimit) | ||
35 | |||
36 | 12 | ||
37 | local function checkerror (msg, f, ...) | 13 | local 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)) |
40 | end | 16 | end |
41 | 17 | ||
42 | -- auxiliary function to keep 'count' on the screen even if the program | ||
43 | -- crashes. | ||
44 | local count | ||
45 | local back = string.rep("\b", 8) | ||
46 | local 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 | ||
50 | end | ||
51 | |||
52 | |||
53 | do 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) | ||
61 | end | ||
62 | |||
63 | |||
64 | do print("testing stack overflow in message handling") | 18 | do 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) |
73 | end | 27 | end |
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) |
86 | end | 40 | end |
87 | 41 | ||
88 | 42 | ||
89 | do print("testing stack-overflow in recursive 'gsub'") | 43 | do 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) |
108 | end | 61 | end |
109 | 62 | ||
63 | |||
110 | do -- bug in 5.4.0 | 64 | do -- 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) | ||
124 | end | 80 | end |
125 | 81 | ||
126 | 82 | ||
127 | do print("testing changes in C-stack limit") | 83 | do |
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) | ||
175 | end | 99 | end |
176 | 100 | ||
177 | |||
178 | print'OK' | 101 | 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) | |||
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"))) | ||
536 | end | 537 | end |
537 | 538 | ||
538 | testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment | 539 | testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment |