From f9e35627ed26dff4114a1d01ff113d8b4cc91ab5 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 26 Feb 2025 11:31:10 -0300 Subject: [PATCH] 'lua_State.nci' must be an integer Lua can easily overflow an unsigned short counting nested calls. (The limit to this value is the maximum stack size, LUAI_MAXSTACK, which is currently 1e6.) --- lstate.h | 2 +- ltests.h | 7 +++++-- testes/coroutine.lua | 12 ++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lstate.h b/lstate.h index 050fc35f..f841c232 100644 --- a/lstate.h +++ b/lstate.h @@ -290,7 +290,6 @@ struct lua_State { CommonHeader; lu_byte allowhook; TStatus status; - unsigned short nci; /* number of items in 'ci' list */ StkIdRel top; /* first free slot in the stack */ struct global_State *l_G; CallInfo *ci; /* call info for current function */ @@ -306,6 +305,7 @@ struct lua_State { ptrdiff_t errfunc; /* current error handling function (stack index) */ l_uint32 nCcalls; /* number of nested non-yieldable or C calls */ int oldpc; /* last pc traced */ + int nci; /* number of items in 'ci' list */ int basehookcount; int hookcount; volatile l_signalT hookmask; diff --git a/ltests.h b/ltests.h index df72307a..cc372b8f 100644 --- a/ltests.h +++ b/ltests.h @@ -152,9 +152,12 @@ LUA_API void *debug_realloc (void *ud, void *block, */ -/* make stack-overflow tests run faster */ +/* +** Reduce maximum stack size to make stack-overflow tests run faster. +** (But value is still large enough to overflow smaller integers.) +*/ #undef LUAI_MAXSTACK -#define LUAI_MAXSTACK 50000 +#define LUAI_MAXSTACK 68000 /* test mode uses more stack space */ diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 78b9bdca..abc08039 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua @@ -127,6 +127,18 @@ assert(#a == 22 and a[#a] == 79) x, a = nil +do -- "bug" in 5.4.2 + local function foo () foo () end -- just create a stack overflow + local co = coroutine.create(foo) + -- running this coroutine would overflow the unsigned short 'nci', the + -- counter of CallInfo structures available to the thread. + -- (The issue only manifests in an 'assert'.) + local st, msg = coroutine.resume(co) + assert(string.find(msg, "stack overflow")) + assert(coroutine.status(co) == "dead") +end + + print("to-be-closed variables in coroutines") local function func2close (f)