diff --git a/backport-C-functions-can-be-tail-called-too.patch b/backport-C-functions-can-be-tail-called-too.patch new file mode 100644 index 0000000000000000000000000000000000000000..27ef9494bdd66a3c9c6948ebddf75df93629bef5 --- /dev/null +++ b/backport-C-functions-can-be-tail-called-too.patch @@ -0,0 +1,117 @@ +From 04e19712a5d48b84869f9942836ff8314fb0be8e Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Mon, 14 Jun 2021 13:28:21 -0300 +Subject: [PATCH] C functions can be tail called, too + +A tail call to a C function can have the behavior of a "real" tail +call, reusing the stack frame of the caller. + +--- + src/ldo.c | 43 +++++++++++++++++++++++++------------------ + src/lvm.c | 9 +-------- + 4 files changed, 29 insertions(+), 29 deletions(-) + +diff --git a/src/ldo.c b/src/ldo.c +index a410461b..38540561 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -478,12 +478,31 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { + ** (This is done only when no more errors can occur before entering the + ** new function, to keep debug information always consistent.) + */ +-static void moveparams (lua_State *L, StkId prevf, StkId func, int narg) { ++static void moveparams (lua_State *L, StkId prevf, StkId func) { + int i; +- narg++; /* function itself will be moved, too */ +- for (i = 0; i < narg; i++) /* move down function and arguments */ ++ for (i = 0; func + i < L->top; i++) /* move down function and arguments */ + setobjs2s(L, prevf + i, func + i); +- L->top = prevf + narg; /* correct top */ ++ L->top = prevf + i; /* correct top */ ++} ++ ++ ++static CallInfo *prepCallInfo (lua_State *L, StkId func, int nresults, ++ int delta1, int mask) { ++ CallInfo *ci; ++ if (delta1) { /* tail call? */ ++ ci = L->ci; /* reuse stack frame */ ++ ci->func -= delta1 - 1; /* correct 'func' */ ++ ++ ci->callstatus |= mask | CIST_TAIL; ++ moveparams(L, ci->func, func); ++ } ++ else { /* regular call */ ++ ci = L->ci = next_ci(L); /* new frame */ ++ ci->func = func; ++ ci->nresults = nresults; ++ ci->callstatus = mask; ++ } ++ return ci; + } + + +@@ -512,11 +531,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { + int n; /* number of returns */ + CallInfo *ci; + checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ +- L->ci = ci = next_ci(L); +- ci->nresults = nresults; +- ci->callstatus = CIST_C; ++ ci = prepCallInfo(L, func, nresults, delta1, CIST_C); + ci->top = L->top + LUA_MINSTACK; +- ci->func = func; + lua_assert(ci->top <= L->stack_last); + if (l_unlikely(L->hookmask & LUA_MASKCALL)) { + int narg = cast_int(L->top - func) - 1; +@@ -536,16 +552,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { + int nfixparams = p->numparams; + int fsize = p->maxstacksize; /* frame size */ + checkstackGCp(L, fsize, func); +- if (delta1) { /* tail call? */ +- ci = L->ci; /* reuse stack frame */ +- ci->func -= delta1 - 1; /* correct 'func' */ +- moveparams(L, ci->func, func, narg); +- } +- else { /* regular call */ +- L->ci = ci = next_ci(L); /* new frame */ +- ci->func = func; +- ci->nresults = nresults; +- } ++ ci = prepCallInfo(L, func, nresults, delta1, 0); + ci->u.l.savedpc = p->code; /* starting point */ + ci->top = func + 1 + fsize; + for (; narg < nfixparams; narg++) +diff --git a/src/lvm.c b/src/lvm.c +index 485b9caa..62ff70da 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -1636,7 +1636,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + updatetrap(ci); /* C call; nothing else to be done */ + else { /* Lua call: run function in this same C frame */ + ci = newci; +- ci->callstatus = 0; + goto startfunc; + } + vmbreak; +@@ -1655,16 +1654,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + lua_assert(L->tbclist < base); /* no pending tbc variables */ + lua_assert(base == ci->func + 1); + } +- if (luaD_precall(L, ra, LUA_MULTRET, delta + 1)) { /* Lua function? */ +- ci->callstatus |= CIST_TAIL; ++ if (luaD_precall(L, ra, LUA_MULTRET, delta + 1)) /* Lua function? */ + goto startfunc; /* execute the callee */ +- } + else { /* C function */ + updatetrap(ci); +- updatestack(ci); /* stack may have been relocated */ +- ci->func -= delta; /* restore 'func' (if vararg) */ +- luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */ +- updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; /* caller returns after the tail call */ + } + } +-- +2.33.0 + diff --git a/backport-CVE-2021-43519.patch b/backport-CVE-2021-43519.patch new file mode 100644 index 0000000000000000000000000000000000000000..b076b9b3ac53dda1f9907ee8f1819a8ce8a60d1c --- /dev/null +++ b/backport-CVE-2021-43519.patch @@ -0,0 +1,68 @@ +From 74d99057a5146755e737c479850f87fd0e3b6868 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Wed, 3 Nov 2021 15:04:18 -0300 +Subject: [PATCH] Bug: C stack overflow with coroutines + +'coroutine.resume' did not increment counter of C calls when +continuing execution after a protected error (that is, +while running 'precover'). +--- + lua-5.4.3-tests/cstack.lua | 14 ++++++++++++++ + src/ldo.c | 6 ++++-- + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/lua-5.4.3-tests/cstack.lua b/lua-5.4.3-tests/cstack.lua +index 213d15d..ca76c87 100644 +--- a/lua-5.4.3-tests/cstack.lua ++++ b/lua-5.4.3-tests/cstack.lua +@@ -103,6 +103,20 @@ do + end + + ++do -- bug in 5.4.2 ++ print("nesting coroutines running after recoverable errors") ++ local count = 0 ++ local function foo() ++ count = count + 1 ++ pcall(1) -- create an error ++ -- running now inside 'precover' ("protected recover") ++ coroutine.wrap(foo)() -- call another coroutine ++ end ++ checkerror("C stack overflow", foo) ++ print("final count: ", count) ++end ++ ++ + if T then + print("testing stack recovery") + local N = 0 -- trace number of calls +diff --git a/src/ldo.c b/src/ldo.c +index 7135079..ca558fd 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -728,11 +728,10 @@ static void resume (lua_State *L, void *ud) { + StkId firstArg = L->top - n; /* first argument */ + CallInfo *ci = L->ci; + if (L->status == LUA_OK) /* starting a coroutine? */ +- ccall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */ ++ ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */ + else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = LUA_OK; /* mark that it is running (again) */ +- luaE_incCstack(L); /* control the C stack */ + if (isLua(ci)) { /* yielded inside a hook? */ + L->top = firstArg; /* discard arguments */ + luaV_execute(L, ci); /* just continue running Lua code */ +@@ -783,6 +782,9 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, + else if (L->status != LUA_YIELD) /* ended with errors? */ + return resume_error(L, "cannot resume dead coroutine", nargs); + L->nCcalls = (from) ? getCcalls(from) : 0; ++ if (getCcalls(L) >= LUAI_MAXCCALLS) ++ return resume_error(L, "C stack overflow", nargs); ++ L->nCcalls++; + luai_userstateresume(L, nargs); + api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); + status = luaD_rawrunprotected(L, resume, &nargs); +-- +1.8.3.1 + diff --git a/backport-CVE-2021-44647.patch b/backport-CVE-2021-44647.patch new file mode 100644 index 0000000000000000000000000000000000000000..56bdfb5bdd3b1ca430af34c846fe1c95f7e58db1 --- /dev/null +++ b/backport-CVE-2021-44647.patch @@ -0,0 +1,24 @@ +From 1de95e97ef65632a88e08b6184bd9d1ceba7ec2f Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Fri, 10 Dec 2021 10:53:54 -0300 +Subject: [PATCH] Bug: Lua stack still active when closing a state + +--- + src/lstate.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/lstate.c b/src/lstate.c +index c5e3b43..38da773 100644 +--- a/src/lstate.c ++++ b/src/lstate.c +@@ -271,6 +271,7 @@ static void close_state (lua_State *L) { + if (!completestate(g)) /* closing a partially built state? */ + luaC_freeallobjects(L); /* jucst collect its objects */ + else { /* closing a fully built state */ ++ L->ci = &L->base_ci; /* unwind CallInfo list */ + luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ + luaC_freeallobjects(L); /* collect all objects */ + luai_userstateclose(L); +-- +1.8.3.1 + diff --git a/backport-CVE-2021-44964.patch b/backport-CVE-2021-44964.patch new file mode 100644 index 0000000000000000000000000000000000000000..e130b137680a6d66248e8e243ebb6194075d89c8 --- /dev/null +++ b/backport-CVE-2021-44964.patch @@ -0,0 +1,297 @@ +From 0bfc572e51d9035a615ef6e9523f736c9ffa8e57 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Mon, 13 Dec 2021 10:41:17 -0300 +Subject: [PATCH] Bug: GC is not reentrant + +As the GC is not reentrant, finalizers should not be able to invoke it. +--- + lua-5.4.3-tests/api.lua | 5 ++--- + lua-5.4.3-tests/gc.lua | 6 ++++-- + src/lapi.c | 17 +++++++++-------- + src/lbaselib.c | 19 +++++++++++++++++-- + src/lgc.c | 11 +++++++---- + src/lgc.h | 9 +++++++++ + src/lstate.c | 4 ++-- + src/lstate.h | 2 +- + 8 files changed, 51 insertions(+), 22 deletions(-) + +diff --git a/lua-5.4.3-tests/api.lua b/lua-5.4.3-tests/api.lua +index c1bcb4b..bd85a92 100644 +--- a/lua-5.4.3-tests/api.lua ++++ b/lua-5.4.3-tests/api.lua +@@ -804,15 +804,14 @@ F = function (x) + d = nil + assert(debug.getmetatable(x).__gc == F) + assert(load("table.insert({}, {})"))() -- create more garbage +- collectgarbage() -- force a GC during GC +- assert(debug.getmetatable(x).__gc == F) -- previous GC did not mess this? ++ assert(not collectgarbage()) -- GC during GC (no op) + local dummy = {} -- create more garbage during GC + if A ~= nil then + assert(type(A) == "userdata") + assert(T.udataval(A) == B) + debug.getmetatable(A) -- just access it + end +- A = x -- ressucita userdata ++ A = x -- ressurect userdata + B = udval + return 1,2,3 + end +diff --git a/lua-5.4.3-tests/gc.lua b/lua-5.4.3-tests/gc.lua +index 2332c93..d865cb2 100644 +--- a/lua-5.4.3-tests/gc.lua ++++ b/lua-5.4.3-tests/gc.lua +@@ -676,11 +676,13 @@ end + -- just to make sure + assert(collectgarbage'isrunning') + +-do -- check that the collector is reentrant in incremental mode ++do -- check that the collector is not reentrant in incremental mode ++ local res = true + setmetatable({}, {__gc = function () +- collectgarbage() ++ res = collectgarbage() + end}) + collectgarbage() ++ assert(not res) + end + + +diff --git a/src/lapi.c b/src/lapi.c +index f8f70cd..7b96979 100644 +--- a/src/lapi.c ++++ b/src/lapi.c +@@ -1126,18 +1126,19 @@ LUA_API int lua_status (lua_State *L) { + LUA_API int lua_gc (lua_State *L, int what, ...) { + va_list argp; + int res = 0; +- global_State *g; ++ global_State *g = G(L); ++ if (g->gcstp & GCSTPGC) /* internal stop? */ ++ return -1; /* all options are invalid when stopped */ + lua_lock(L); +- g = G(L); + va_start(argp, what); + switch (what) { + case LUA_GCSTOP: { +- g->gcrunning = 0; ++ g->gcstp = GCSTPUSR; /* stopeed by the user */ + break; + } + case LUA_GCRESTART: { + luaE_setdebt(g, 0); +- g->gcrunning = 1; ++ g->gcstp = 0; /* (GCSTPGC must be already zero here) */ + break; + } + case LUA_GCCOLLECT: { +@@ -1156,8 +1157,8 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { + case LUA_GCSTEP: { + int data = va_arg(argp, int); + l_mem debt = 1; /* =1 to signal that it did an actual step */ +- lu_byte oldrunning = g->gcrunning; +- g->gcrunning = 1; /* allow GC to run */ ++ lu_byte oldstp = g->gcstp; ++ g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */ + if (data == 0) { + luaE_setdebt(g, 0); /* do a basic step */ + luaC_step(L); +@@ -1167,7 +1168,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { + luaE_setdebt(g, debt); + luaC_checkGC(L); + } +- g->gcrunning = oldrunning; /* restore previous state */ ++ g->gcstp = oldstp; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; +@@ -1185,7 +1186,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { + break; + } + case LUA_GCISRUNNING: { +- res = g->gcrunning; ++ res = gcrunning(g); + break; + } + case LUA_GCGEN: { +diff --git a/src/lbaselib.c b/src/lbaselib.c +index 83ad306..82abd94 100644 +--- a/src/lbaselib.c ++++ b/src/lbaselib.c +@@ -182,12 +182,20 @@ static int luaB_rawset (lua_State *L) { + + + static int pushmode (lua_State *L, int oldmode) { +- lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" +- : "generational"); ++ if (oldmode == -1) ++ luaL_pushfail(L); /* invalid call to 'lua_gc' */ ++ else ++ lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" ++ : "generational"); + return 1; + } + + ++/* ++** check whether call to 'lua_gc' was valid (not inside a finalizer) ++*/ ++#define checkvalres(res) { if (res == -1) break; } ++ + static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", +@@ -200,12 +208,14 @@ static int luaB_collectgarbage (lua_State *L) { + case LUA_GCCOUNT: { + int k = lua_gc(L, o); + int b = lua_gc(L, LUA_GCCOUNTB); ++ checkvalres(k); + lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + int step = (int)luaL_optinteger(L, 2, 0); + int res = lua_gc(L, o, step); ++ checkvalres(res); + lua_pushboolean(L, res); + return 1; + } +@@ -213,11 +223,13 @@ static int luaB_collectgarbage (lua_State *L) { + case LUA_GCSETSTEPMUL: { + int p = (int)luaL_optinteger(L, 2, 0); + int previous = lua_gc(L, o, p); ++ checkvalres(previous); + lua_pushinteger(L, previous); + return 1; + } + case LUA_GCISRUNNING: { + int res = lua_gc(L, o); ++ checkvalres(res); + lua_pushboolean(L, res); + return 1; + } +@@ -234,10 +246,13 @@ static int luaB_collectgarbage (lua_State *L) { + } + default: { + int res = lua_gc(L, o); ++ checkvalres(res); + lua_pushinteger(L, res); + return 1; + } + } ++ luaL_pushfail(L); /* invalid call (inside a finalizer) */ ++ return 1; + } + + +diff --git a/src/lgc.c b/src/lgc.c +index b360eed..7d0b5e4 100644 +--- a/src/lgc.c ++++ b/src/lgc.c +@@ -906,16 +906,16 @@ static void GCTM (lua_State *L) { + if (!notm(tm)) { /* is there a finalizer? */ + int status; + lu_byte oldah = L->allowhook; +- int running = g->gcrunning; ++ int oldgcstp = g->gcstp; ++ g->gcstp = GCSTPGC; /* avoid GC steps */ + L->allowhook = 0; /* stop debug hooks during GC metamethod */ +- g->gcrunning = 0; /* avoid GC steps */ + setobj2s(L, L->top++, tm); /* push finalizer... */ + setobj2s(L, L->top++, &v); /* ... and its argument */ + L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); + L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ + L->allowhook = oldah; /* restore hooks */ +- g->gcrunning = running; /* restore state */ ++ g->gcstp = oldgcstp; /* restore state */ + if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ + luaE_warnerror(L, "__gc metamethod"); + L->top--; /* pops error object */ +@@ -1502,9 +1502,11 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) { + */ + void luaC_freeallobjects (lua_State *L) { + global_State *g = G(L); ++ g->gcstp = GCSTPGC; + luaC_changemode(L, KGC_INC); + separatetobefnz(g, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); ++ g->gcstp = 0; + callallpendingfinalizers(L); + deletelist(L, g->allgc, obj2gco(g->mainthread)); + deletelist(L, g->finobj, NULL); +@@ -1647,6 +1649,7 @@ void luaC_runtilstate (lua_State *L, int statesmask) { + } + + ++ + /* + ** Performs a basic incremental step. The debt and step size are + ** converted from bytes to "units of work"; then the function loops +@@ -1678,7 +1681,7 @@ static void incstep (lua_State *L, global_State *g) { + void luaC_step (lua_State *L) { + global_State *g = G(L); + lua_assert(!g->gcemergency); +- if (g->gcrunning) { /* running? */ ++ if (gcrunning(g)) { /* running? */ + if(isdecGCmodegen(g)) + genstep(L, g); + else +diff --git a/src/lgc.h b/src/lgc.h +index 073e2a4..024a432 100644 +--- a/src/lgc.h ++++ b/src/lgc.h +@@ -148,6 +148,15 @@ + */ + #define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0) + ++ ++/* ++** Control when GC is running: ++*/ ++#define GCSTPUSR 1 /* bit true when GC stopped by user */ ++#define GCSTPGC 2 /* bit true when GC stopped by itself */ ++#define gcrunning(g) ((g)->gcstp == 0) ++ ++ + /* + ** Does one step of collection when debt becomes positive. 'pre'/'pos' + ** allows some adjustments to be done only when needed. macro +diff --git a/src/lstate.c b/src/lstate.c +index 38da773..59b4f21 100644 +--- a/src/lstate.c ++++ b/src/lstate.c +@@ -236,7 +236,7 @@ static void f_luaopen (lua_State *L, void *ud) { + luaS_init(L); + luaT_init(L); + luaX_init(L); +- g->gcrunning = 1; /* allow gc */ ++ g->gcstp = 0; /* allow gc */ + setnilvalue(&g->nilvalue); /* now state is complete */ + luai_userstateopen(L); + } +@@ -373,7 +373,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + g->ud_warn = NULL; + g->mainthread = L; + g->seed = luai_makeseed(L); +- g->gcrunning = 0; /* no GC while building state */ ++ g->gcstp = GCSTPGC; /* no GC while building state */ + g->strt.size = g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(&g->l_registry); +diff --git a/src/lstate.h b/src/lstate.h +index c1283bb..0d2099f 100644 +--- a/src/lstate.h ++++ b/src/lstate.h +@@ -263,7 +263,7 @@ typedef struct global_State { + lu_byte gcstopem; /* stops emergency collections */ + lu_byte genminormul; /* control for minor generational collections */ + lu_byte genmajormul; /* control for major generational collections */ +- lu_byte gcrunning; /* true if GC is running */ ++ lu_byte gcstp; /* control whether GC is running */ + lu_byte gcemergency; /* true if this is an emergency collection */ + lu_byte gcpause; /* size of pause between successive GCs */ + lu_byte gcstepmul; /* GC "speed" */ +-- +2.33.0 + diff --git a/backport-CVE-2021-45985.patch b/backport-CVE-2021-45985.patch new file mode 100644 index 0000000000000000000000000000000000000000..bcb6a10756bfca9ab8de074e808aa9c3bdf413f9 --- /dev/null +++ b/backport-CVE-2021-45985.patch @@ -0,0 +1,34 @@ +From cf613cdc6fa367257fc61c256f63d917350858b5 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Wed, 15 Dec 2021 11:29:07 -0300 +Subject: [PATCH] Bug: finalizers can be called with an invalid stack + +The call to 'checkstackGC' can run finalizers, which will find an +inconsistent CallInfo, as 'ci' is half updated at the point of call. + +Reference:https://github.com/lua/lua/commit/cf613cdc6fa367257fc61c256f63d917350858b5 +Conflict:NA +--- + src/ldo.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/ldo.c b/src/ldo.c +index f282a773..a48e35f9 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -530,10 +530,10 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, + int fsize = p->maxstacksize; /* frame size */ + int nfixparams = p->numparams; + int i; ++ checkstackGCp(L, fsize - delta, func); + ci->func -= delta; /* restore 'func' (if vararg) */ + for (i = 0; i < narg1; i++) /* move down function and arguments */ + setobjs2s(L, ci->func + i, func + i); +- checkstackGC(L, fsize); + func = ci->func; /* moved-down function */ + for (; narg1 <= nfixparams; narg1++) + setnilvalue(s2v(func + narg1)); /* complete missing arguments */ +-- +2.33.0 + + diff --git a/backport-CVE-2022-28805.patch b/backport-CVE-2022-28805.patch new file mode 100644 index 0000000000000000000000000000000000000000..04e79c08729ffd439fd2b470da8e09b193c64571 --- /dev/null +++ b/backport-CVE-2022-28805.patch @@ -0,0 +1,46 @@ +From 1f3c6f4534c6411313361697d98d1145a1f030fa Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Tue, 15 Feb 2022 12:28:46 -0300 +Subject: [PATCH] Bug: Lua can generate wrong code when _ENV is + +--- + lua-5.4.3-tests/attrib.lua | 10 ++++++++++ + src/lparser.c | 1 + + 2 files changed, 11 insertions(+) + +diff --git a/lua-5.4.3-tests/attrib.lua b/lua-5.4.3-tests/attrib.lua +index b1076c7..83821c0 100644 +--- a/lua-5.4.3-tests/attrib.lua ++++ b/lua-5.4.3-tests/attrib.lua +@@ -434,6 +434,16 @@ a.aVeryLongName012345678901234567890123456789012345678901234567890123456789 == + 10) + + ++do ++ -- _ENV constant ++ local function foo () ++ local _ENV = 11 ++ X = "hi" ++ end ++ local st, msg = pcall(foo) ++ assert(not st and string.find(msg, "number")) ++end ++ + + -- test of large float/integer indices + +diff --git a/src/lparser.c b/src/lparser.c +index 284ef1f..0626833 100644 +--- a/src/lparser.c ++++ b/src/lparser.c +@@ -457,6 +457,7 @@ static void singlevar (LexState *ls, expdesc *var) { + expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ + lua_assert(var->k != VVOID); /* this one must exist */ ++ luaK_exp2anyregup(fs, var); /* but could be a constant */ + codestring(&key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ + } +-- +1.8.3.1 + diff --git a/backport-CVE-2022-33099.patch b/backport-CVE-2022-33099.patch new file mode 100644 index 0000000000000000000000000000000000000000..f984cab009ea25b0b354ef1b54019e02cd3b3940 --- /dev/null +++ b/backport-CVE-2022-33099.patch @@ -0,0 +1,62 @@ +From 42d40581dd919fb134c07027ca1ce0844c670daf Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Fri, 20 May 2022 13:14:33 -0300 +Subject: [PATCH] Save stack space while handling errors + +Because error handling (luaG_errormsg) uses slots from EXTRA_STACK, +and some errors can recur (e.g., string overflow while creating an +error message in 'luaG_runerror', or a C-stack overflow before calling +the message handler), the code should use stack slots with parsimony. + +This commit fixes the bug "Lua-stack overflow when C stack overflows +while handling an error". +--- + src/ldebug.c | 5 ++++- + src/lvm.c | 6 ++++-- + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/src/ldebug.c b/src/ldebug.c +index 1feaab2..5524fae 100644 +--- a/src/ldebug.c ++++ b/src/ldebug.c +@@ -783,8 +783,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); /* format message */ + va_end(argp); +- if (isLua(ci)) /* if Lua function, add source:line information */ ++ if (isLua(ci)) { /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); ++ setobjs2s(L, L->top - 2, L->top - 1); /* remove 'msg' from the stack */ ++ L->top--; ++ } + luaG_errormsg(L); + } + +diff --git a/src/lvm.c b/src/lvm.c +index c9729bc..a965087 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -656,8 +656,10 @@ void luaV_concat (lua_State *L, int total) { + /* collect total length and number of strings */ + for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { + size_t l = vslen(s2v(top - n - 1)); +- if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) ++ if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) { ++ L->top = top - total; /* pop strings to avoid wasting stack */ + luaG_runerror(L, "string length overflow"); ++ } + tl += l; + } + if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ +@@ -672,7 +674,7 @@ void luaV_concat (lua_State *L, int total) { + setsvalue2s(L, top - n, ts); /* create result */ + } + total -= n-1; /* got 'n' strings to create 1 new */ +- L->top -= n-1; /* popped 'n' strings and pushed one */ ++ L->top = top - (n - 1); /* popped 'n' strings and pushed one */ + } while (total > 1); /* repeat until only 1 result left */ + } + +-- +2.33.0 + diff --git a/backport-More-uniform-implementation-for-tail-calls.patch b/backport-More-uniform-implementation-for-tail-calls.patch new file mode 100644 index 0000000000000000000000000000000000000000..88cc4f79b792e0402ea68018d56d5ce9c9b81176 --- /dev/null +++ b/backport-More-uniform-implementation-for-tail-calls.patch @@ -0,0 +1,203 @@ +From 1fce5bea817de50e055a84c153a975f25bfcf493 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Fri, 29 Oct 2021 13:41:24 -0300 +Subject: [PATCH] More uniform implementation for tail calls + +'luaD_pretailcall' mimics 'luaD_precall', handling call metamethods +and calling C functions directly. That makes the code in the +interpreter loop simpler. + +This commit also goes back to emulating the tail call in 'luaD_precall' +with a goto, as C compilers may not do proper tail calls and the C +stack can overflow much sooner than the Lua stack (which grows as the +metamethod is added to it). + +Reference:https://github.com/lua/lua/commit/1fce5bea817de50e055a84c153a975f25bfcf493 +Conflict:NA +--- + src/ldo.c | 81 ++++++++++++++++++++++++++++++++++++++--------------------- + src/ldo.h | 2 +- + src/lvm.c | 19 ++++---------- + 3 files changed, 58 insertions(+), 44 deletions(-) + +diff --git a/src/ldo.c b/src/ldo.c +index 0ac12e74..d0edc8b4 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -475,30 +475,6 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { + #define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) + + +-/* +-** Prepare a function for a tail call, building its call info on top +-** of the current call info. 'narg1' is the number of arguments plus 1 +-** (so that it includes the function itself). +-*/ +-void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { +- Proto *p = clLvalue(s2v(func))->p; +- int fsize = p->maxstacksize; /* frame size */ +- int nfixparams = p->numparams; +- int i; +- for (i = 0; i < narg1; i++) /* move down function and arguments */ +- setobjs2s(L, ci->func + i, func + i); +- checkstackGC(L, fsize); +- func = ci->func; /* moved-down function */ +- for (; narg1 <= nfixparams; narg1++) +- setnilvalue(s2v(func + narg1)); /* complete missing arguments */ +- ci->top = func + 1 + fsize; /* top for new function */ +- lua_assert(ci->top <= L->stack_last); +- ci->u.l.savedpc = p->code; /* starting point */ +- ci->callstatus |= CIST_TAIL; +- L->top = func + narg1; /* set top */ +-} +- +- + l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, + int mask, StkId top) { + CallInfo *ci = L->ci = next_ci(L); /* new frame */ +@@ -513,7 +489,7 @@ l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, + /* + ** precall for C functions + */ +-l_sinline CallInfo *precallC (lua_State *L, StkId func, int nresults, ++l_sinline int precallC (lua_State *L, StkId func, int nresults, + lua_CFunction f) { + int n; /* number of returns */ + CallInfo *ci; +@@ -530,7 +506,50 @@ l_sinline CallInfo *precallC (lua_State *L, StkId func, int nresults, + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, n); +- return NULL; ++ return n; ++} ++ ++ ++/* ++** Prepare a function for a tail call, building its call info on top ++** of the current call info. 'narg1' is the number of arguments plus 1 ++** (so that it includes the function itself). Return the number of ++** results, if it was a C function, or -1 for a Lua function. ++*/ ++int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, ++ int narg1, int delta) { ++ retry: ++ switch (ttypetag(s2v(func))) { ++ case LUA_VCCL: /* C closure */ ++ return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f); ++ case LUA_VLCF: /* light C function */ ++ return precallC(L, func, LUA_MULTRET, fvalue(s2v(func))); ++ case LUA_VLCL: { /* Lua function */ ++ Proto *p = clLvalue(s2v(func))->p; ++ int fsize = p->maxstacksize; /* frame size */ ++ int nfixparams = p->numparams; ++ int i; ++ ci->func -= delta; /* restore 'func' (if vararg) */ ++ for (i = 0; i < narg1; i++) /* move down function and arguments */ ++ setobjs2s(L, ci->func + i, func + i); ++ checkstackGC(L, fsize); ++ func = ci->func; /* moved-down function */ ++ for (; narg1 <= nfixparams; narg1++) ++ setnilvalue(s2v(func + narg1)); /* complete missing arguments */ ++ ci->top = func + 1 + fsize; /* top for new function */ ++ lua_assert(ci->top <= L->stack_last); ++ ci->u.l.savedpc = p->code; /* starting point */ ++ ci->callstatus |= CIST_TAIL; ++ L->top = func + narg1; /* set top */ ++ return -1; ++ } ++ default: { /* not a function */ ++ func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ ++ /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */ ++ narg1++; ++ goto retry; /* try again */ ++ } ++ } + } + + +@@ -543,11 +562,14 @@ l_sinline CallInfo *precallC (lua_State *L, StkId func, int nresults, + ** original function position. + */ + CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { ++ retry: + switch (ttypetag(s2v(func))) { + case LUA_VCCL: /* C closure */ +- return precallC(L, func, nresults, clCvalue(s2v(func))->f); ++ precallC(L, func, nresults, clCvalue(s2v(func))->f); ++ return NULL; + case LUA_VLCF: /* light C function */ +- return precallC(L, func, nresults, fvalue(s2v(func))); ++ precallC(L, func, nresults, fvalue(s2v(func))); ++ return NULL; + case LUA_VLCL: { /* Lua function */ + CallInfo *ci; + Proto *p = clLvalue(s2v(func))->p; +@@ -564,7 +586,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { + } + default: { /* not a function */ + func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ +- return luaD_precall(L, func, nresults); /* try again with metamethod */ ++ /* return luaD_precall(L, func, nresults); */ ++ goto retry; /* try again with metamethod */ + } + } + } +diff --git a/src/ldo.h b/src/ldo.h +index 9fb772fe..911e67f6 100644 +--- a/src/ldo.h ++++ b/src/ldo.h +@@ -58,7 +58,7 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, + int fTransfer, int nTransfer); + LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); +-LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); ++LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta); + LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); +diff --git a/src/lvm.c b/src/lvm.c +index 49ed3ddf..2ec34400 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -1643,6 +1643,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + } + vmcase(OP_TAILCALL) { + int b = GETARG_B(i); /* number of arguments + 1 (function) */ ++ int n; /* number of results when calling a C function */ + int nparams1 = GETARG_C(i); + /* delta is virtual 'func' - real 'func' (vararg functions) */ + int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; +@@ -1656,24 +1657,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + lua_assert(L->tbclist < base); /* no pending tbc variables */ + lua_assert(base == ci->func + 1); + } +- while (!ttisfunction(s2v(ra))) { /* not a function? */ +- ra = luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ +- b++; /* there is now one extra argument */ +- } +- if (!ttisLclosure(s2v(ra))) { /* C function? */ +- luaD_precall(L, ra, LUA_MULTRET); /* call it */ +- updatetrap(ci); +- updatestack(ci); /* stack may have been relocated */ ++ if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */ ++ goto startfunc; /* execute the callee */ ++ else { /* C function? */ + ci->func -= delta; /* restore 'func' (if vararg) */ +- luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */ ++ luaD_poscall(L, ci, n); /* finish caller */ + updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; /* caller returns after the tail call */ + } +- else { /* Lua function */ +- ci->func -= delta; /* restore 'func' (if vararg) */ +- luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ +- goto startfunc; /* execute the callee */ +- } + } + vmcase(OP_RETURN) { + int n = GETARG_B(i) - 1; /* number of results */ +-- +2.33.0 + + diff --git a/backport-Removed-goto-s-in-luaD_precall.patch b/backport-Removed-goto-s-in-luaD_precall.patch new file mode 100644 index 0000000000000000000000000000000000000000..bbb5d43e9b72d881befca54386338f649b55229e --- /dev/null +++ b/backport-Removed-goto-s-in-luaD_precall.patch @@ -0,0 +1,107 @@ +From 3699446aaf5c7a07af028b1ae43cf52d2d4dda59 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Mon, 18 Oct 2021 11:58:40 -0300 +Subject: [PATCH] Removed goto's in 'luaD_precall' + +(plus a detail in src/lauxlib.h.) +--- + src/lauxlib.h | 2 +- + src/ldo.c | 51 +++++++++++++++++++++++++++------------------------ + 2 files changed, 28 insertions(+), 25 deletions(-) + +diff --git a/src/lauxlib.h b/src/lauxlib.h +index 6f9695e8..5b977e2a 100644 +--- a/src/lauxlib.h ++++ b/src/lauxlib.h +@@ -102,7 +102,7 @@ LUALIB_API lua_State *(luaL_newstate) (void); + + LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); + +-LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s, ++LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, + const char *p, const char *r); + LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, + const char *p, const char *r); +diff --git a/src/ldo.c b/src/ldo.c +index 88b20f95..0ac12e74 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -510,6 +510,30 @@ l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, + } + + ++/* ++** precall for C functions ++*/ ++l_sinline CallInfo *precallC (lua_State *L, StkId func, int nresults, ++ lua_CFunction f) { ++ int n; /* number of returns */ ++ CallInfo *ci; ++ checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ ++ L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, ++ L->top + LUA_MINSTACK); ++ lua_assert(ci->top <= L->stack_last); ++ if (l_unlikely(L->hookmask & LUA_MASKCALL)) { ++ int narg = cast_int(L->top - func) - 1; ++ luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); ++ } ++ lua_unlock(L); ++ n = (*f)(L); /* do the actual call */ ++ lua_lock(L); ++ api_checknelems(L, n); ++ luaD_poscall(L, ci, n); ++ return NULL; ++} ++ ++ + /* + ** Prepares the call to a function (C or Lua). For C functions, also do + ** the call. The function to be called is at '*func'. The arguments +@@ -519,32 +543,11 @@ l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, + ** original function position. + */ + CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { +- lua_CFunction f; +- retry: + switch (ttypetag(s2v(func))) { + case LUA_VCCL: /* C closure */ +- f = clCvalue(s2v(func))->f; +- goto Cfunc; ++ return precallC(L, func, nresults, clCvalue(s2v(func))->f); + case LUA_VLCF: /* light C function */ +- f = fvalue(s2v(func)); +- Cfunc: { +- int n; /* number of returns */ +- CallInfo *ci; +- checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ +- L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, +- L->top + LUA_MINSTACK); +- lua_assert(ci->top <= L->stack_last); +- if (l_unlikely(L->hookmask & LUA_MASKCALL)) { +- int narg = cast_int(L->top - func) - 1; +- luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); +- } +- lua_unlock(L); +- n = (*f)(L); /* do the actual call */ +- lua_lock(L); +- api_checknelems(L, n); +- luaD_poscall(L, ci, n); +- return NULL; +- } ++ return precallC(L, func, nresults, fvalue(s2v(func))); + case LUA_VLCL: { /* Lua function */ + CallInfo *ci; + Proto *p = clLvalue(s2v(func))->p; +@@ -561,7 +564,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { + } + default: { /* not a function */ + func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ +- goto retry; /* try again with metamethod */ ++ return luaD_precall(L, func, nresults); /* try again with metamethod */ + } + } + } +-- +2.33.0 + + diff --git a/backport-Simpler-implementation-for-tail-calls.patch b/backport-Simpler-implementation-for-tail-calls.patch new file mode 100644 index 0000000000000000000000000000000000000000..7efe8c876a16946a0114c02c565200cb48682ac8 --- /dev/null +++ b/backport-Simpler-implementation-for-tail-calls.patch @@ -0,0 +1,172 @@ +From 901d76009346d76996679c02deee708bf225e91e Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Fri, 11 Jun 2021 13:41:07 -0300 +Subject: [PATCH] Simpler implementation for tail calls + +Tail calls handled by 'luaD_precall', like regular calls, to avoid +code duplication. +--- + src/ldo.c | 48 ++++++++++++++++++++++++------------------------ + src/ldo.h | 4 ++-- + src/lvm.c | 20 +++++++------------- + 3 files changed, 33 insertions(+), 39 deletions(-) + +diff --git a/src/ldo.c b/src/ldo.c +index 7135079b..a410461b 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -474,26 +474,16 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { + + + /* +-** Prepare a function for a tail call, building its call info on top +-** of the current call info. 'narg1' is the number of arguments plus 1 +-** (so that it includes the function itself). ++** In a tail call, move function and parameters to previous call frame. ++** (This is done only when no more errors can occur before entering the ++** new function, to keep debug information always consistent.) + */ +-void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { +- Proto *p = clLvalue(s2v(func))->p; +- int fsize = p->maxstacksize; /* frame size */ +- int nfixparams = p->numparams; ++static void moveparams (lua_State *L, StkId prevf, StkId func, int narg) { + int i; +- for (i = 0; i < narg1; i++) /* move down function and arguments */ +- setobjs2s(L, ci->func + i, func + i); +- checkstackGC(L, fsize); +- func = ci->func; /* moved-down function */ +- for (; narg1 <= nfixparams; narg1++) +- setnilvalue(s2v(func + narg1)); /* complete missing arguments */ +- ci->top = func + 1 + fsize; /* top for new function */ +- lua_assert(ci->top <= L->stack_last); +- ci->u.l.savedpc = p->code; /* starting point */ +- ci->callstatus |= CIST_TAIL; +- L->top = func + narg1; /* set top */ ++ narg++; /* function itself will be moved, too */ ++ for (i = 0; i < narg; i++) /* move down function and arguments */ ++ setobjs2s(L, prevf + i, func + i); ++ L->top = prevf + narg; /* correct top */ + } + + +@@ -504,8 +494,12 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { + ** to be executed, if it was a Lua function. Otherwise (a C function) + ** returns NULL, with all the results on the stack, starting at the + ** original function position. ++** For regular calls, 'delta1' is 0. For tail calls, 'delta1' is the ++** 'delta' (correction of base for vararg functions) plus 1, so that it ++** cannot be zero. Like 'moveparams', this correction can only be done ++** when no more errors can occur in the call. + */ +-CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { ++CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { + lua_CFunction f; + retry: + switch (ttypetag(s2v(func))) { +@@ -542,12 +536,18 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { + int nfixparams = p->numparams; + int fsize = p->maxstacksize; /* frame size */ + checkstackGCp(L, fsize, func); +- L->ci = ci = next_ci(L); +- ci->nresults = nresults; ++ if (delta1) { /* tail call? */ ++ ci = L->ci; /* reuse stack frame */ ++ ci->func -= delta1 - 1; /* correct 'func' */ ++ moveparams(L, ci->func, func, narg); ++ } ++ else { /* regular call */ ++ L->ci = ci = next_ci(L); /* new frame */ ++ ci->func = func; ++ ci->nresults = nresults; ++ } + ci->u.l.savedpc = p->code; /* starting point */ + ci->top = func + 1 + fsize; +- ci->func = func; +- L->ci = ci; + for (; narg < nfixparams; narg++) + setnilvalue(s2v(L->top++)); /* complete missing arguments */ + lua_assert(ci->top <= L->stack_last); +@@ -572,7 +572,7 @@ static void ccall (lua_State *L, StkId func, int nResults, int inc) { + L->nCcalls += inc; + if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) + luaE_checkcstack(L); +- if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ ++ if ((ci = luaD_precall(L, func, nResults, 0)) != NULL) { /* Lua function? */ + ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ + luaV_execute(L, ci); /* call it */ + } +diff --git a/src/ldo.h b/src/ldo.h +index 6bf0ed86..6edc4450 100644 +--- a/src/ldo.h ++++ b/src/ldo.h +@@ -58,8 +58,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, + int fTransfer, int nTransfer); + LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); +-LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); +-LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); ++LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, ++ int delta1); + LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); +diff --git a/src/lvm.c b/src/lvm.c +index e4b1903e..485b9caa 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -1632,11 +1632,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + L->top = ra + b; /* top signals number of arguments */ + /* else previous instruction set top */ + savepc(L); /* in case of errors */ +- if ((newci = luaD_precall(L, ra, nresults)) == NULL) ++ if ((newci = luaD_precall(L, ra, nresults, 0)) == NULL) + updatetrap(ci); /* C call; nothing else to be done */ + else { /* Lua call: run function in this same C frame */ + ci = newci; +- ci->callstatus = 0; /* call re-uses 'luaV_execute' */ ++ ci->callstatus = 0; + goto startfunc; + } + vmbreak; +@@ -1648,21 +1648,18 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; + if (b != 0) + L->top = ra + b; +- else /* previous instruction set top */ +- b = cast_int(L->top - ra); ++ /* else previous instruction set top */ + savepc(ci); /* several calls here can raise errors */ + if (TESTARG_k(i)) { + luaF_closeupval(L, base); /* close upvalues from current call */ + lua_assert(L->tbclist < base); /* no pending tbc variables */ + lua_assert(base == ci->func + 1); + } +- while (!ttisfunction(s2v(ra))) { /* not a function? */ +- luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ +- b++; /* there is now one extra argument */ +- checkstackGCp(L, 1, ra); ++ if (luaD_precall(L, ra, LUA_MULTRET, delta + 1)) { /* Lua function? */ ++ ci->callstatus |= CIST_TAIL; ++ goto startfunc; /* execute the callee */ + } +- if (!ttisLclosure(s2v(ra))) { /* C function? */ +- luaD_precall(L, ra, LUA_MULTRET); /* call it */ ++ else { /* C function */ + updatetrap(ci); + updatestack(ci); /* stack may have been relocated */ + ci->func -= delta; /* restore 'func' (if vararg) */ +@@ -1670,9 +1667,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; /* caller returns after the tail call */ + } +- ci->func -= delta; /* restore 'func' (if vararg) */ +- luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ +- goto startfunc; /* execute the callee */ + } + vmcase(OP_RETURN) { + int n = GETARG_B(i) - 1; /* number of results */ +-- +2.33.0 + + diff --git a/backport-Simplification-in-the-parameters-of-luaD_precall.patch b/backport-Simplification-in-the-parameters-of-luaD_precall.patch new file mode 100644 index 0000000000000000000000000000000000000000..84db717665efd64cdd1cdfeae0744283e41126f8 --- /dev/null +++ b/backport-Simplification-in-the-parameters-of-luaD_precall.patch @@ -0,0 +1,139 @@ +From dbdc74dc5502c2e05e1c1e2ac894943f418c8431 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Wed, 30 Jun 2021 12:53:21 -0300 +Subject: [PATCH] Simplification in the parameters of 'luaD_precall' + +The parameters 'nresults' and 'delta1', in 'luaD_precall', were never +meaningful simultaneously. So, they were combined in a single parameter +'retdel'. +--- + src/ldo.c | 19 +++++++++---------- + src/ldo.h | 15 +++++++++++++-- + src/lvm.c | 4 ++-- + 3 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/src/ldo.c b/src/ldo.c +index 38540561..93fcbb1a 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -486,20 +486,19 @@ static void moveparams (lua_State *L, StkId prevf, StkId func) { + } + + +-static CallInfo *prepCallInfo (lua_State *L, StkId func, int nresults, +- int delta1, int mask) { ++static CallInfo *prepCallInfo (lua_State *L, StkId func, int retdel, ++ int mask) { + CallInfo *ci; +- if (delta1) { /* tail call? */ ++ if (isdelta(retdel)) { /* tail call? */ + ci = L->ci; /* reuse stack frame */ +- ci->func -= delta1 - 1; /* correct 'func' */ +- ++ ci->func -= retdel2delta(retdel); /* correct 'func' */ + ci->callstatus |= mask | CIST_TAIL; + moveparams(L, ci->func, func); + } + else { /* regular call */ + ci = L->ci = next_ci(L); /* new frame */ + ci->func = func; +- ci->nresults = nresults; ++ ci->nresults = retdel; + ci->callstatus = mask; + } + return ci; +@@ -518,7 +517,7 @@ static CallInfo *prepCallInfo (lua_State *L, StkId func, int nresults, + ** cannot be zero. Like 'moveparams', this correction can only be done + ** when no more errors can occur in the call. + */ +-CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { ++CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { + lua_CFunction f; + retry: + switch (ttypetag(s2v(func))) { +@@ -531,7 +530,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { + int n; /* number of returns */ + CallInfo *ci; + checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ +- ci = prepCallInfo(L, func, nresults, delta1, CIST_C); ++ ci = prepCallInfo(L, func, retdel, CIST_C); + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + if (l_unlikely(L->hookmask & LUA_MASKCALL)) { +@@ -552,7 +551,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { + int nfixparams = p->numparams; + int fsize = p->maxstacksize; /* frame size */ + checkstackGCp(L, fsize, func); +- ci = prepCallInfo(L, func, nresults, delta1, 0); ++ ci = prepCallInfo(L, func, retdel, 0); + ci->u.l.savedpc = p->code; /* starting point */ + ci->top = func + 1 + fsize; + for (; narg < nfixparams; narg++) +@@ -579,7 +578,7 @@ static void ccall (lua_State *L, StkId func, int nResults, int inc) { + L->nCcalls += inc; + if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) + luaE_checkcstack(L); +- if ((ci = luaD_precall(L, func, nResults, 0)) != NULL) { /* Lua function? */ ++ 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/src/ldo.h b/src/ldo.h +index 6edc4450..49fbb492 100644 +--- a/src/ldo.h ++++ b/src/ldo.h +@@ -49,6 +49,18 @@ + luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) + + ++/* ++** 'luaD_precall' is used for regular calls, when it needs the ++** number of results, and in tail calls, when it needs the 'delta' ++** (correction of base for vararg functions). The argument 'retdel' ++** codes these two options. A number of results is represented by ++** itself, while a delta is represented by 'delta2retdel(delta)' ++*/ ++#define delta2retdel(d) (-(d) + LUA_MULTRET - 1) ++#define retdel2delta(d) (-(d) + LUA_MULTRET - 1) ++#define isdelta(rd) ((rd) < LUA_MULTRET) ++ ++ + /* type of protected functions, to be ran by 'runprotected' */ + typedef void (*Pfunc) (lua_State *L, void *ud); + +@@ -58,8 +70,7 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, + int fTransfer, int nTransfer); + LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); +-LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, +- int delta1); ++LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int retdel); + LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); +diff --git a/src/lvm.c b/src/lvm.c +index 62ff70da..ec83f415 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -1632,7 +1632,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + L->top = ra + b; /* top signals number of arguments */ + /* else previous instruction set top */ + savepc(L); /* in case of errors */ +- if ((newci = luaD_precall(L, ra, nresults, 0)) == NULL) ++ if ((newci = luaD_precall(L, ra, nresults)) == NULL) + updatetrap(ci); /* C call; nothing else to be done */ + else { /* Lua call: run function in this same C frame */ + ci = newci; +@@ -1654,7 +1654,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + lua_assert(L->tbclist < base); /* no pending tbc variables */ + lua_assert(base == ci->func + 1); + } +- if (luaD_precall(L, ra, LUA_MULTRET, delta + 1)) /* Lua function? */ ++ if (luaD_precall(L, ra, delta2retdel(delta))) /* Lua function? */ + goto startfunc; /* execute the callee */ + else { /* C function */ + updatetrap(ci); +-- +2.33.0 + + diff --git a/backport-Undo-simplification-of-tail-calls-commit-901d760.patch b/backport-Undo-simplification-of-tail-calls-commit-901d760.patch new file mode 100644 index 0000000000000000000000000000000000000000..2e3dae1d226f814f0cf8fb4ff7bd2103892684d4 --- /dev/null +++ b/backport-Undo-simplification-of-tail-calls-commit-901d760.patch @@ -0,0 +1,189 @@ +From dbdc74dc5502c2e05e1c1e2ac894943f418c8431 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Wed, 30 Jun 2021 12:53:21 -0300 +Subject: [PATCH] Simplification in the parameters of 'luaD_precall' +--- + src/ldo.c | 66 +++++++++++++++++++++++++++---------------------------- + src/ldo.h | 15 ++----------- + src/lvm.c | 20 +++++++++++++---- + 3 files changed, 50 insertions(+), 51 deletions(-) + +diff --git a/src/ldo.c b/src/ldo.c +index 17fb398..e2af6dc 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -474,33 +474,36 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { + + + /* +-** In a tail call, move function and parameters to previous call frame. +-** (This is done only when no more errors can occur before entering the +-** new function, to keep debug information always consistent.) ++** Prepare a function for a tail call, building its call info on top ++** of the current call info. 'narg1' is the number of arguments plus 1 ++** (so that it includes the function itself). + */ +-static void moveparams (lua_State *L, StkId prevf, StkId func) { ++void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { ++ Proto *p = clLvalue(s2v(func))->p; ++ int fsize = p->maxstacksize; /* frame size */ ++ int nfixparams = p->numparams; + int i; +- for (i = 0; func + i < L->top; i++) /* move down function and arguments */ +- setobjs2s(L, prevf + i, func + i); +- L->top = prevf + i; /* correct top */ +-} +- +- +-static CallInfo *prepCallInfo (lua_State *L, StkId func, int retdel, +- int mask) { +- CallInfo *ci; +- if (isdelta(retdel)) { /* tail call? */ +- ci = L->ci; /* reuse stack frame */ +- ci->func -= retdel2delta(retdel); /* correct 'func' */ +- ci->callstatus |= mask | CIST_TAIL; +- moveparams(L, ci->func, func); +- } +- else { /* regular call */ +- ci = L->ci = next_ci(L); /* new frame */ +- ci->func = func; +- ci->nresults = retdel; +- ci->callstatus = mask; +- } ++ for (i = 0; i < narg1; i++) /* move down function and arguments */ ++ setobjs2s(L, ci->func + i, func + i); ++ checkstackGC(L, fsize); ++ func = ci->func; /* moved-down function */ ++ for (; narg1 <= nfixparams; narg1++) ++ setnilvalue(s2v(func + narg1)); /* complete missing arguments */ ++ ci->top = func + 1 + fsize; /* top for new function */ ++ lua_assert(ci->top <= L->stack_last); ++ ci->u.l.savedpc = p->code; /* starting point */ ++ ci->callstatus |= CIST_TAIL; ++ L->top = func + narg1; /* set top */ ++} ++ ++ ++static CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, ++ int mask, StkId top) { ++ CallInfo *ci = L->ci = next_ci(L); /* new frame */ ++ ci->func = func; ++ ci->nresults = nret; ++ ci->callstatus = mask; ++ ci->top = top; + return ci; + } + +@@ -512,12 +515,8 @@ static CallInfo *prepCallInfo (lua_State *L, StkId func, int retdel, + ** to be executed, if it was a Lua function. Otherwise (a C function) + ** returns NULL, with all the results on the stack, starting at the + ** original function position. +-** For regular calls, 'delta1' is 0. For tail calls, 'delta1' is the +-** 'delta' (correction of base for vararg functions) plus 1, so that it +-** cannot be zero. Like 'moveparams', this correction can only be done +-** when no more errors can occur in the call. + */ +-CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { ++CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { + lua_CFunction f; + retry: + switch (ttypetag(s2v(func))) { +@@ -530,8 +529,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { + int n; /* number of returns */ + CallInfo *ci; + checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ +- ci = prepCallInfo(L, func, retdel, CIST_C); +- ci->top = L->top + LUA_MINSTACK; ++ L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, ++ L->top + LUA_MINSTACK); + lua_assert(ci->top <= L->stack_last); + if (l_unlikely(L->hookmask & LUA_MASKCALL)) { + int narg = cast_int(L->top - func) - 1; +@@ -551,9 +550,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { + int nfixparams = p->numparams; + int fsize = p->maxstacksize; /* frame size */ + checkstackGCp(L, fsize, func); +- ci = prepCallInfo(L, func, retdel, 0); ++ L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); + ci->u.l.savedpc = p->code; /* starting point */ +- ci->top = func + 1 + fsize; + for (; narg < nfixparams; narg++) + setnilvalue(s2v(L->top++)); /* complete missing arguments */ + lua_assert(ci->top <= L->stack_last); +diff --git a/src/ldo.h b/src/ldo.h +index 49fbb49..6bf0ed8 100644 +--- a/src/ldo.h ++++ b/src/ldo.h +@@ -49,18 +49,6 @@ + luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) + + +-/* +-** 'luaD_precall' is used for regular calls, when it needs the +-** number of results, and in tail calls, when it needs the 'delta' +-** (correction of base for vararg functions). The argument 'retdel' +-** codes these two options. A number of results is represented by +-** itself, while a delta is represented by 'delta2retdel(delta)' +-*/ +-#define delta2retdel(d) (-(d) + LUA_MULTRET - 1) +-#define retdel2delta(d) (-(d) + LUA_MULTRET - 1) +-#define isdelta(rd) ((rd) < LUA_MULTRET) +- +- + /* type of protected functions, to be ran by 'runprotected' */ + typedef void (*Pfunc) (lua_State *L, void *ud); + +@@ -70,7 +58,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, + int fTransfer, int nTransfer); + LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); +-LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int retdel); ++LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); ++LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); +diff --git a/src/lvm.c b/src/lvm.c +index 4fb426c..1541c63 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -1638,19 +1638,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; + if (b != 0) + L->top = ra + b; +- /* else previous instruction set top */ ++ else /* previous instruction set top */ ++ b = cast_int(L->top - ra); + savepc(ci); /* several calls here can raise errors */ + if (TESTARG_k(i)) { + luaF_closeupval(L, base); /* close upvalues from current call */ + lua_assert(L->tbclist < base); /* no pending tbc variables */ + lua_assert(base == ci->func + 1); + } +- if (luaD_precall(L, ra, delta2retdel(delta))) /* Lua function? */ +- goto startfunc; /* execute the callee */ +- else { /* C function */ ++ while (!ttisfunction(s2v(ra))) { /* not a function? */ ++ luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ ++ b++; /* there is now one extra argument */ ++ checkstackGCp(L, 1, ra); ++ } ++ if (!ttisLclosure(s2v(ra))) { /* C function? */ ++ luaD_precall(L, ra, LUA_MULTRET); /* call it */ + updatetrap(ci); ++ updatestack(ci); /* stack may have been relocated */ ++ ci->func -= delta; /* restore 'func' (if vararg) */ ++ luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */ ++ updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; /* caller returns after the tail call */ + } ++ ci->func -= delta; /* restore 'func' (if vararg) */ ++ luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ ++ goto startfunc; /* execute the callee */ + } + vmcase(OP_RETURN) { + int n = GETARG_B(i) - 1; /* number of results */ +-- +2.33.0 + + diff --git a/backport-Using-inline-in-some-functions.patch b/backport-Using-inline-in-some-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..4b1785157ef64955bd5d04751144eabe115cf903 --- /dev/null +++ b/backport-Using-inline-in-some-functions.patch @@ -0,0 +1,183 @@ +From 2ff34717227b8046b0fdcb96206f11f5e888664e Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Wed, 15 Sep 2021 11:18:41 -0300 +Subject: [PATCH] Using 'inline' in some functions + +According to ISO C, "making a function an inline function suggests that +calls to the function be as fast as possible." (Not available in C89.) +--- + src/lapi.c | 10 +++++----- + src/ldo.c | 8 ++++---- + src/llimits.h | 14 ++++++++++++++ + src/lvm.c | 12 ++++++------ + 4 files changed, 29 insertions(+), 15 deletions(-) + +diff --git a/src/lapi.c b/src/lapi.c +index 7b96979..2f59d3c 100644 +--- a/src/lapi.c ++++ b/src/lapi.c +@@ -81,7 +81,7 @@ static TValue *index2value (lua_State *L, int idx) { + } + + +-static StkId index2stack (lua_State *L, int idx) { ++l_sinline StkId index2stack (lua_State *L, int idx) { + CallInfo *ci = L->ci; + if (idx > 0) { + StkId o = ci->func + idx; +@@ -218,7 +218,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) { + ** Note that we move(copy) only the value inside the stack. + ** (We do not move additional fields that may exist.) + */ +-static void reverse (lua_State *L, StkId from, StkId to) { ++l_sinline void reverse (lua_State *L, StkId from, StkId to) { + for (; from < to; from++, to--) { + TValue temp; + setobj(L, &temp, s2v(from)); +@@ -438,7 +438,7 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + } + + +-static void *touserdata (const TValue *o) { ++l_sinline void *touserdata (const TValue *o) { + switch (ttype(o)) { + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); +@@ -630,7 +630,7 @@ LUA_API int lua_pushthread (lua_State *L) { + */ + + +-static int auxgetstr (lua_State *L, const TValue *t, const char *k) { ++l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { +@@ -705,7 +705,7 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { + } + + +-static int finishrawget (lua_State *L, const TValue *val) { ++l_sinline int finishrawget (lua_State *L, const TValue *val) { + if (isempty(val)) /* avoid copying empty items to the stack */ + setnilvalue(s2v(L->top)); + else +diff --git a/src/ldo.c b/src/ldo.c +index 673b975..bf2d041 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -407,7 +407,7 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) { + ** expressions, multiple results for tail calls/single parameters) + ** separated. + */ +-static void moveresults (lua_State *L, StkId res, int nres, int wanted) { ++l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) { + StkId firstresult; + int i; + switch (wanted) { /* handle typical cases separately */ +@@ -499,8 +499,8 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { + } + + +-static CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, +- int mask, StkId top) { ++l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, ++ int mask, StkId top) { + CallInfo *ci = L->ci = next_ci(L); /* new frame */ + ci->func = func; + ci->nresults = nret; +@@ -572,7 +572,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { + ** number of recursive invocations in the C stack) or nyci (the same + ** plus increment number of non-yieldable calls). + */ +-static void ccall (lua_State *L, StkId func, int nResults, int inc) { ++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)) +diff --git a/src/llimits.h b/src/llimits.h +index 025f1c8..6c56ba5 100644 +--- a/src/llimits.h ++++ b/src/llimits.h +@@ -165,6 +165,20 @@ typedef LUAI_UACINT l_uacInt; + #endif + + ++/* ++** Inline functions ++*/ ++#if !defined(LUA_USE_C89) ++#define l_inline inline ++#elif defined(__GNUC__) ++#define l_inline __inline__ ++#else ++#define l_inline /* empty */ ++#endif ++ ++#define l_sinline static l_inline ++ ++ + /* + ** type for virtual-machine instructions; + ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +diff --git a/src/lvm.c b/src/lvm.c +index c16c2c6..14af102 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -406,7 +406,7 @@ static int l_strcmp (const TString *ls, const TString *rs) { + ** from float to int.) + ** When 'f' is NaN, comparisons must result in false. + */ +-static int LTintfloat (lua_Integer i, lua_Number f) { ++l_sinline int LTintfloat (lua_Integer i, lua_Number f) { + if (l_intfitsf(i)) + return luai_numlt(cast_num(i), f); /* compare them as floats */ + else { /* i < f <=> i < ceil(f) */ +@@ -423,7 +423,7 @@ static int LTintfloat (lua_Integer i, lua_Number f) { + ** Check whether integer 'i' is less than or equal to float 'f'. + ** See comments on previous function. + */ +-static int LEintfloat (lua_Integer i, lua_Number f) { ++l_sinline int LEintfloat (lua_Integer i, lua_Number f) { + if (l_intfitsf(i)) + return luai_numle(cast_num(i), f); /* compare them as floats */ + else { /* i <= f <=> i <= floor(f) */ +@@ -440,7 +440,7 @@ static int LEintfloat (lua_Integer i, lua_Number f) { + ** Check whether float 'f' is less than integer 'i'. + ** See comments on previous function. + */ +-static int LTfloatint (lua_Number f, lua_Integer i) { ++l_sinline int LTfloatint (lua_Number f, lua_Integer i) { + if (l_intfitsf(i)) + return luai_numlt(f, cast_num(i)); /* compare them as floats */ + else { /* f < i <=> floor(f) < i */ +@@ -457,7 +457,7 @@ static int LTfloatint (lua_Number f, lua_Integer i) { + ** Check whether float 'f' is less than or equal to integer 'i'. + ** See comments on previous function. + */ +-static int LEfloatint (lua_Number f, lua_Integer i) { ++l_sinline int LEfloatint (lua_Number f, lua_Integer i) { + if (l_intfitsf(i)) + return luai_numle(f, cast_num(i)); /* compare them as floats */ + else { /* f <= i <=> ceil(f) <= i */ +@@ -473,7 +473,7 @@ static int LEfloatint (lua_Number f, lua_Integer i) { + /* + ** Return 'l < r', for numbers. + */ +-static int LTnum (const TValue *l, const TValue *r) { ++l_sinline int LTnum (const TValue *l, const TValue *r) { + lua_assert(ttisnumber(l) && ttisnumber(r)); + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); +@@ -495,7 +495,7 @@ static int LTnum (const TValue *l, const TValue *r) { + /* + ** Return 'l <= r', for numbers. + */ +-static int LEnum (const TValue *l, const TValue *r) { ++l_sinline int LEnum (const TValue *l, const TValue *r) { + lua_assert(ttisnumber(l) && ttisnumber(r)); + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); +-- +2.33.0 + + diff --git a/backport-luaD_tryfuncTM-checks-stack-space-by-itself.patch b/backport-luaD_tryfuncTM-checks-stack-space-by-itself.patch new file mode 100644 index 0000000000000000000000000000000000000000..db36e6033786bdfa2917a1d89ee6c808924829c8 --- /dev/null +++ b/backport-luaD_tryfuncTM-checks-stack-space-by-itself.patch @@ -0,0 +1,90 @@ +From 91673a8ec0ae55e188a790bd2dfdc99246adf20e Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Wed, 18 Aug 2021 12:05:06 -0300 +Subject: [PATCH] 'luaD_tryfuncTM' checks stack space by itself +--- + src/ldo.c | 7 ++++--- + src/ldo.h | 2 +- + src/lvm.c | 11 ++++++----- + 3 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/src/ldo.c b/src/ldo.c +index fa8d98b2..889cb34b 100644 +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -387,15 +387,17 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) { + ** stack, below original 'func', so that 'luaD_precall' can call it. Raise + ** an error if there is no '__call' metafield. + */ +-void luaD_tryfuncTM (lua_State *L, StkId func) { ++StkId luaD_tryfuncTM (lua_State *L, StkId func) { + const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); + StkId p; ++ checkstackGCp(L, 1, func); /* space for metamethod */ + if (l_unlikely(ttisnil(tm))) + luaG_callerror(L, s2v(func)); /* nothing to call */ + for (p = L->top; p > func; p--) /* open space for metamethod */ + setobjs2s(L, p, p-1); + L->top++; /* stack space pre-allocated by the caller */ + setobj2s(L, func, tm); /* metamethod is the new function to be called */ ++ return func; + } + + +@@ -558,8 +560,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { + return ci; + } + default: { /* not a function */ +- checkstackGCp(L, 1, func); /* space for metamethod */ +- luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ ++ func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + goto retry; /* try again with metamethod */ + } + } +diff --git a/src/ldo.h b/src/ldo.h +index 6bf0ed86..9fb772fe 100644 +--- a/src/ldo.h ++++ b/src/ldo.h +@@ -62,7 +62,7 @@ LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); + LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); + LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); +-LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); ++LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func); + LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); + LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +diff --git a/src/lvm.c b/src/lvm.c +index df1dec83..29a211c6 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -1657,9 +1657,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + lua_assert(base == ci->func + 1); + } + while (!ttisfunction(s2v(ra))) { /* not a function? */ +- luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ ++ ra = luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ + b++; /* there is now one extra argument */ +- checkstackGCp(L, 1, ra); + } + if (!ttisLclosure(s2v(ra))) { /* C function? */ + luaD_precall(L, ra, LUA_MULTRET); /* call it */ +@@ -1670,9 +1669,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { + updatetrap(ci); /* 'luaD_poscall' can change hooks */ + goto ret; /* caller returns after the tail call */ + } +- ci->func -= delta; /* restore 'func' (if vararg) */ +- luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ +- goto startfunc; /* execute the callee */ ++ else { /* Lua function */ ++ ci->func -= delta; /* restore 'func' (if vararg) */ ++ luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ ++ goto startfunc; /* execute the callee */ ++ } + } + vmcase(OP_RETURN) { + int n = GETARG_B(i) - 1; /* number of results */ +-- +2.33.0 + + diff --git a/backport-luaV_concat-can-use-invalidated-pointer-to-stack.patch b/backport-luaV_concat-can-use-invalidated-pointer-to-stack.patch new file mode 100644 index 0000000000000000000000000000000000000000..beef7e6b27016e7f4f56cfd4a240a345315ae233 --- /dev/null +++ b/backport-luaV_concat-can-use-invalidated-pointer-to-stack.patch @@ -0,0 +1,37 @@ +From 603b2c64add5fbf4b7343525cf109af0c7077695 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Mon, 23 May 2022 17:50:47 -0300 +Subject: [PATCH] 'luaV_concat' can use invalidated pointer to stack + +Bug introduced in commit 42d40581. +--- + src/lvm.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/lvm.c b/src/lvm.c +index cd992aa..614df05 100644 +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -643,7 +643,7 @@ void luaV_concat (lua_State *L, int total) { + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) || + !tostring(L, s2v(top - 1))) +- luaT_tryconcatTM(L); ++ luaT_tryconcatTM(L); /* may invalidate 'top' */ + else if (isemptystr(s2v(top - 1))) /* second operand is empty? */ + cast_void(tostring(L, s2v(top - 2))); /* result is first operand */ + else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */ +@@ -673,8 +673,8 @@ void luaV_concat (lua_State *L, int total) { + } + setsvalue2s(L, top - n, ts); /* create result */ + } +- total -= n-1; /* got 'n' strings to create 1 new */ +- L->top = top - (n - 1); /* popped 'n' strings and pushed one */ ++ total -= n - 1; /* got 'n' strings to create one new */ ++ L->top -= n - 1; /* popped 'n' strings and pushed one */ + } while (total > 1); /* repeat until only 1 result left */ + } + +-- +1.8.3.1 + diff --git a/lua-5.3.0-idsize.patch b/lua-5.3.0-idsize.patch new file mode 100644 index 0000000000000000000000000000000000000000..16107fe2f747c02cdd1055da7907e2ea5d7a5d08 --- /dev/null +++ b/lua-5.3.0-idsize.patch @@ -0,0 +1,12 @@ +diff -up lua-5.3.0/src/luaconf.h.template.in.idsize lua-5.3.0/src/luaconf.h.template.in +--- lua-5.3.0/src/luaconf.h.template.in.idsize 2015-01-15 10:23:20.515801344 -0500 ++++ lua-5.3.0/src/luaconf.h.template.in 2015-01-15 10:23:48.955651916 -0500 +@@ -693,7 +693,7 @@ + @@ of a function in debug information. + ** CHANGE it if you want a different size. + */ +-#define LUA_IDSIZE 60 ++#define LUA_IDSIZE 512 + + + /* diff --git a/lua-5.4.3-tests.tar.gz b/lua-5.4.3-tests.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..d7817dc9a2e963679bf3202b4816f7887c80da32 Binary files /dev/null and b/lua-5.4.3-tests.tar.gz differ diff --git a/lua-5.4.3.tar.gz b/lua-5.4.3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1e7b11aa77b2cd92c66b1a185a2e844dc5da7c31 Binary files /dev/null and b/lua-5.4.3.tar.gz differ diff --git a/lua-5.4.6-idsize.patch b/lua-5.4.6-idsize.patch deleted file mode 100644 index a97688dd92dd612a63b972b39d3cbe480451a58d..0000000000000000000000000000000000000000 --- a/lua-5.4.6-idsize.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/src/luaconf.h.template.in b/src/luaconf.h.template.in -index 1e32333..601d10e 100644 ---- a/src/luaconf.h.template.in -+++ b/src/luaconf.h.template.in -@@ -762,7 +762,7 @@ - ** of a function in debug information. - ** CHANGE it if you want a different size. - */ --#define LUA_IDSIZE 60 -+#define LUA_IDSIZE 512 - - - /* - diff --git a/lua-5.4.6-tests.tar.gz b/lua-5.4.6-tests.tar.gz deleted file mode 100644 index 8ab62648408326cd91b0d37b74484f3dfd1923fd..0000000000000000000000000000000000000000 Binary files a/lua-5.4.6-tests.tar.gz and /dev/null differ diff --git a/lua-5.4.6.tar.gz b/lua-5.4.6.tar.gz deleted file mode 100644 index 5677b16bc0a4df093b6b57d51538108df2329ff7..0000000000000000000000000000000000000000 Binary files a/lua-5.4.6.tar.gz and /dev/null differ diff --git a/lua.spec b/lua.spec index 25b2723ab8db14a9707b2c5a83f94d227760bb75..c943b9187b4a61ebe44a01c7c82b061037619f2c 100644 --- a/lua.spec +++ b/lua.spec @@ -1,12 +1,12 @@ %global major_version 5.4 -# test version is still 5.4.6 -%global test_version 5.4.6 +# test version is still 5.4.3 +%global test_version 5.4.3 # Place rpm-macros into proper location. %global macrosdir %(d=%{_rpmconfigdir}/macros.d; [ -d $d ] || d=%{_sysconfdir}/rpm; echo $d) Name: lua -Version: 5.4.6 -Release: 1 +Version: 5.4.3 +Release: 11 Summary: A powerful, efficient, lightweight, embeddable scripting language License: MIT URL: http://www.lua.org/ @@ -20,9 +20,24 @@ Source3: mit.txt # rpm-macro Source1000: macros.lua Patch0: lua-5.4.0-beta-autotoolize.patch -Patch1: lua-5.4.6-idsize.patch +Patch1: lua-5.3.0-idsize.patch Patch2: lua-5.2.2-configure-linux.patch Patch3: lua-5.3.0-configure-compat-module.patch +Patch6000: backport-CVE-2021-43519.patch +Patch6001: backport-CVE-2021-44647.patch +Patch6002: backport-CVE-2022-28805.patch +Patch6003: backport-CVE-2022-33099.patch +Patch6004: backport-CVE-2021-44964.patch +Patch6005: backport-luaV_concat-can-use-invalidated-pointer-to-stack.patch +Patch6006: backport-Simpler-implementation-for-tail-calls.patch +Patch6007: backport-C-functions-can-be-tail-called-too.patch +Patch6008: backport-Simplification-in-the-parameters-of-luaD_precall.patch +Patch6009: backport-Undo-simplification-of-tail-calls-commit-901d760.patch +Patch6010: backport-luaD_tryfuncTM-checks-stack-space-by-itself.patch +Patch6011: backport-Using-inline-in-some-functions.patch +Patch6012: backport-Removed-goto-s-in-luaD_precall.patch +Patch6013: backport-More-uniform-implementation-for-tail-calls.patch +Patch6014: backport-CVE-2021-45985.patch BuildRequires: automake autoconf libtool readline-devel ncurses-devel @@ -55,6 +70,21 @@ mv src/luaconf.h src/luaconf.h.template.in %patch1 -p1 -z .idsize %patch2 -p1 -z .configure-linux %patch3 -p1 -z .configure-compat-all +%patch6000 -p1 +%patch6001 -p1 +%patch6002 -p1 +%patch6003 -p1 +%patch6004 -p1 +%patch6005 -p1 +%patch6006 -p1 +%patch6007 -p1 +%patch6008 -p1 +%patch6009 -p1 +%patch6010 -p1 +%patch6011 -p1 +%patch6012 -p1 +%patch6013 -p1 +%patch6014 -p1 # Put proper version in configure.ac, patch0 hardcodes 5.3.0 sed -i 's|5.3.0|%{version}|g' configure.ac @@ -129,9 +159,6 @@ LD_LIBRARY_PATH=$RPM_BUILD_ROOT/%{_libdir} $RPM_BUILD_ROOT/%{_bindir}/lua -e"_U= %{_mandir}/man1/lua*.1* %changelog -* Mon Oct 30 2023 chenziyang - 5.4.6-1 -- upgrade to version 5.4.6 for 22.03-LTS-Next version because 5.4.3 released 2 years ago - * Tue Apr 18 2023 chenziyang - 5.4.3-11 - fix CVE-2021-45985 and other commits because CVE change heavily rely on these commits