summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2022-05-26 15:14:54 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2022-05-26 15:14:54 -0300
commitd61b0c60287c38008d312ddd11724a15b1737f7b (patch)
treecbba214daaf712ac78547d136aa24b12d1308294
parent196bb94d66e727e0aec053a0276c3ad701500762 (diff)
downloadlua-github-d61b0c60287c38008d312ddd11724a15b1737f7b.tar.gz
More checks and documentation for uses of EXTRA_STACK
-rw-r--r--ldo.c7
-rw-r--r--ldo.h7
-rw-r--r--lobject.c34
-rw-r--r--lobject.h2
-rw-r--r--testes/calls.lua10
5 files changed, 47 insertions, 13 deletions
diff --git a/ldo.c b/ldo.c
index 13498905..419b3db9 100644
--- a/ldo.c
+++ b/ldo.c
@@ -602,12 +602,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls).
+** This function can be called with some use of EXTRA_STACK, so it should
+** check the stack before doing anything else. 'luaD_precall' already
+** does that.
*/
l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) {
CallInfo *ci;
L->nCcalls += inc;
- if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
+ if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
+ checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L);
+ }
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */
diff --git a/ldo.h b/ldo.h
index 4cbdb847..4661aa00 100644
--- a/ldo.h
+++ b/ldo.h
@@ -37,6 +37,13 @@
/* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p) \
+ luaD_checkstackaux(L, n, \
+ ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
+ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
+
+
+/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
diff --git a/lobject.c b/lobject.c
index 301aa900..a2c00609 100644
--- a/lobject.c
+++ b/lobject.c
@@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** ===================================================================
*/
-/* size for buffer space used by 'luaO_pushvfstring' */
-#define BUFVFS 200
+/*
+** Size for buffer space used by 'luaO_pushvfstring'. It should be
+** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
+** so that 'luaG_addinfo' can work directly on the buffer.
+*/
+#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS {
lua_State *L;
- int pushed; /* number of string pieces already on the stack */
+ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */
} BuffFS;
/*
-** Push given string to the stack, as part of the buffer, and
-** join the partial strings in the stack into one.
+** Push given string to the stack, as part of the result, and
+** join it to previous partial result if there is one.
+** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
+** This call cannot invoke metamethods, as both operands must be
+** strings. It can, however, raise an error if the result is too
+** long. In that case, 'luaV_concat' frees the extra slot before
+** raising the error.
*/
-static void pushstr (BuffFS *buff, const char *str, size_t l) {
+static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L;
- setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
- L->top++; /* may use one extra slot */
- buff->pushed++;
- luaV_concat(L, buff->pushed); /* join partial results into one */
- buff->pushed = 1;
+ setsvalue2s(L, L->top, luaS_newlstr(L, str, lstr));
+ L->top++; /* may use one slot from EXTRA_STACK */
+ if (!buff->pushed) /* no previous string on the stack? */
+ buff->pushed = 1; /* now there is one */
+ else /* join previous string with new one */
+ luaV_concat(L, 2);
}
@@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/*
-** Add a number to the buffer.
+** Add a numeral to the buffer.
*/
static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR);
diff --git a/lobject.h b/lobject.h
index 0e05b3e4..77cc606f 100644
--- a/lobject.h
+++ b/lobject.h
@@ -52,6 +52,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
+ /* not used, but may avoid warnings for uninitialized value */
+ lu_byte ub;
} Value;
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
end
+do -- C-stack overflow while handling C-stack overflow
+ local function loop ()
+ assert(pcall(loop))
+ end
+
+ local err, msg = xpcall(loop, loop)
+ assert(not err and string.find(msg, "error"))
+end
+
+
do -- tail calls x chain of __call
local n = 10000 -- depth