diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-05-26 15:14:54 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-05-26 15:14:54 -0300 |
commit | d61b0c60287c38008d312ddd11724a15b1737f7b (patch) | |
tree | cbba214daaf712ac78547d136aa24b12d1308294 | |
parent | 196bb94d66e727e0aec053a0276c3ad701500762 (diff) | |
download | lua-d61b0c60287c38008d312ddd11724a15b1737f7b.tar.gz lua-d61b0c60287c38008d312ddd11724a15b1737f7b.tar.bz2 lua-d61b0c60287c38008d312ddd11724a15b1737f7b.zip |
More checks and documentation for uses of EXTRA_STACK
-rw-r--r-- | ldo.c | 7 | ||||
-rw-r--r-- | ldo.h | 7 | ||||
-rw-r--r-- | lobject.c | 34 | ||||
-rw-r--r-- | lobject.h | 2 | ||||
-rw-r--r-- | testes/calls.lua | 10 |
5 files changed, 47 insertions, 13 deletions
@@ -602,12 +602,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { | |||
602 | ** Call a function (C or Lua) through C. 'inc' can be 1 (increment | 602 | ** Call a function (C or Lua) through C. 'inc' can be 1 (increment |
603 | ** number of recursive invocations in the C stack) or nyci (the same | 603 | ** number of recursive invocations in the C stack) or nyci (the same |
604 | ** plus increment number of non-yieldable calls). | 604 | ** plus increment number of non-yieldable calls). |
605 | ** This function can be called with some use of EXTRA_STACK, so it should | ||
606 | ** check the stack before doing anything else. 'luaD_precall' already | ||
607 | ** does that. | ||
605 | */ | 608 | */ |
606 | l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) { | 609 | l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) { |
607 | CallInfo *ci; | 610 | CallInfo *ci; |
608 | L->nCcalls += inc; | 611 | L->nCcalls += inc; |
609 | if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) | 612 | if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) { |
613 | checkstackp(L, 0, func); /* free any use of EXTRA_STACK */ | ||
610 | luaE_checkcstack(L); | 614 | luaE_checkcstack(L); |
615 | } | ||
611 | if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ | 616 | if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ |
612 | ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ | 617 | ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ |
613 | luaV_execute(L, ci); /* call it */ | 618 | luaV_execute(L, ci); /* call it */ |
@@ -37,6 +37,13 @@ | |||
37 | 37 | ||
38 | 38 | ||
39 | /* macro to check stack size, preserving 'p' */ | 39 | /* macro to check stack size, preserving 'p' */ |
40 | #define checkstackp(L,n,p) \ | ||
41 | luaD_checkstackaux(L, n, \ | ||
42 | ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \ | ||
43 | p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ | ||
44 | |||
45 | |||
46 | /* macro to check stack size and GC, preserving 'p' */ | ||
40 | #define checkstackGCp(L,n,p) \ | 47 | #define checkstackGCp(L,n,p) \ |
41 | luaD_checkstackaux(L, n, \ | 48 | luaD_checkstackaux(L, n, \ |
42 | ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ | 49 | ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ |
@@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) { | |||
386 | ** =================================================================== | 386 | ** =================================================================== |
387 | */ | 387 | */ |
388 | 388 | ||
389 | /* size for buffer space used by 'luaO_pushvfstring' */ | 389 | /* |
390 | #define BUFVFS 200 | 390 | ** Size for buffer space used by 'luaO_pushvfstring'. It should be |
391 | ** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages, | ||
392 | ** so that 'luaG_addinfo' can work directly on the buffer. | ||
393 | */ | ||
394 | #define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95) | ||
391 | 395 | ||
392 | /* buffer used by 'luaO_pushvfstring' */ | 396 | /* buffer used by 'luaO_pushvfstring' */ |
393 | typedef struct BuffFS { | 397 | typedef struct BuffFS { |
394 | lua_State *L; | 398 | lua_State *L; |
395 | int pushed; /* number of string pieces already on the stack */ | 399 | int pushed; /* true if there is a part of the result on the stack */ |
396 | int blen; /* length of partial string in 'space' */ | 400 | int blen; /* length of partial string in 'space' */ |
397 | char space[BUFVFS]; /* holds last part of the result */ | 401 | char space[BUFVFS]; /* holds last part of the result */ |
398 | } BuffFS; | 402 | } BuffFS; |
399 | 403 | ||
400 | 404 | ||
401 | /* | 405 | /* |
402 | ** Push given string to the stack, as part of the buffer, and | 406 | ** Push given string to the stack, as part of the result, and |
403 | ** join the partial strings in the stack into one. | 407 | ** join it to previous partial result if there is one. |
408 | ** It may call 'luaV_concat' while using one slot from EXTRA_STACK. | ||
409 | ** This call cannot invoke metamethods, as both operands must be | ||
410 | ** strings. It can, however, raise an error if the result is too | ||
411 | ** long. In that case, 'luaV_concat' frees the extra slot before | ||
412 | ** raising the error. | ||
404 | */ | 413 | */ |
405 | static void pushstr (BuffFS *buff, const char *str, size_t l) { | 414 | static void pushstr (BuffFS *buff, const char *str, size_t lstr) { |
406 | lua_State *L = buff->L; | 415 | lua_State *L = buff->L; |
407 | setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); | 416 | setsvalue2s(L, L->top, luaS_newlstr(L, str, lstr)); |
408 | L->top++; /* may use one extra slot */ | 417 | L->top++; /* may use one slot from EXTRA_STACK */ |
409 | buff->pushed++; | 418 | if (!buff->pushed) /* no previous string on the stack? */ |
410 | luaV_concat(L, buff->pushed); /* join partial results into one */ | 419 | buff->pushed = 1; /* now there is one */ |
411 | buff->pushed = 1; | 420 | else /* join previous string with new one */ |
421 | luaV_concat(L, 2); | ||
412 | } | 422 | } |
413 | 423 | ||
414 | 424 | ||
@@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) { | |||
454 | 464 | ||
455 | 465 | ||
456 | /* | 466 | /* |
457 | ** Add a number to the buffer. | 467 | ** Add a numeral to the buffer. |
458 | */ | 468 | */ |
459 | static void addnum2buff (BuffFS *buff, TValue *num) { | 469 | static void addnum2buff (BuffFS *buff, TValue *num) { |
460 | char *numbuff = getbuff(buff, MAXNUMBER2STR); | 470 | char *numbuff = getbuff(buff, MAXNUMBER2STR); |
@@ -52,6 +52,8 @@ typedef union Value { | |||
52 | lua_CFunction f; /* light C functions */ | 52 | lua_CFunction f; /* light C functions */ |
53 | lua_Integer i; /* integer numbers */ | 53 | lua_Integer i; /* integer numbers */ |
54 | lua_Number n; /* float numbers */ | 54 | lua_Number n; /* float numbers */ |
55 | /* not used, but may avoid warnings for uninitialized value */ | ||
56 | lu_byte ub; | ||
55 | } Value; | 57 | } Value; |
56 | 58 | ||
57 | 59 | ||
diff --git a/testes/calls.lua b/testes/calls.lua index ff72d8f6..ee8cce73 100644 --- a/testes/calls.lua +++ b/testes/calls.lua | |||
@@ -151,6 +151,16 @@ do -- tail calls x varargs | |||
151 | end | 151 | end |
152 | 152 | ||
153 | 153 | ||
154 | do -- C-stack overflow while handling C-stack overflow | ||
155 | local function loop () | ||
156 | assert(pcall(loop)) | ||
157 | end | ||
158 | |||
159 | local err, msg = xpcall(loop, loop) | ||
160 | assert(not err and string.find(msg, "error")) | ||
161 | end | ||
162 | |||
163 | |||
154 | 164 | ||
155 | do -- tail calls x chain of __call | 165 | do -- tail calls x chain of __call |
156 | local n = 10000 -- depth | 166 | local n = 10000 -- depth |