From 89c61e7fa4b57456285e2cde7143c2cdf053d79e Mon Sep 17 00:00:00 2001 From: Chen Ziyang Date: Tue, 18 Apr 2023 21:48:32 +0800 Subject: [PATCH] fix CVE-2021-45985 --- ...t-C-functions-can-be-tail-called-too.patch | 117 ++++++++++ backport-CVE-2021-45985.patch | 34 +++ ...niform-implementation-for-tail-calls.patch | 203 ++++++++++++++++++ backport-Removed-goto-s-in-luaD_precall.patch | 107 +++++++++ ...impler-implementation-for-tail-calls.patch | 172 +++++++++++++++ ...on-in-the-parameters-of-luaD_precall.patch | 139 ++++++++++++ ...ication-of-tail-calls-commit-901d760.patch | 189 ++++++++++++++++ backport-Using-inline-in-some-functions.patch | 183 ++++++++++++++++ ...yfuncTM-checks-stack-space-by-itself.patch | 90 ++++++++ lua.spec | 24 ++- 10 files changed, 1257 insertions(+), 1 deletion(-) create mode 100644 backport-C-functions-can-be-tail-called-too.patch create mode 100644 backport-CVE-2021-45985.patch create mode 100644 backport-More-uniform-implementation-for-tail-calls.patch create mode 100644 backport-Removed-goto-s-in-luaD_precall.patch create mode 100644 backport-Simpler-implementation-for-tail-calls.patch create mode 100644 backport-Simplification-in-the-parameters-of-luaD_precall.patch create mode 100644 backport-Undo-simplification-of-tail-calls-commit-901d760.patch create mode 100644 backport-Using-inline-in-some-functions.patch create mode 100644 backport-luaD_tryfuncTM-checks-stack-space-by-itself.patch 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 0000000..27ef949 --- /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-45985.patch b/backport-CVE-2021-45985.patch new file mode 100644 index 0000000..bcb6a10 --- /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-More-uniform-implementation-for-tail-calls.patch b/backport-More-uniform-implementation-for-tail-calls.patch new file mode 100644 index 0000000..88cc4f7 --- /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 0000000..bbb5d43 --- /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 0000000..7efe8c8 --- /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 0000000..84db717 --- /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 0000000..2e3dae1 --- /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 0000000..4b17851 --- /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 0000000..db36e60 --- /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/lua.spec b/lua.spec index 3a22709..c943b91 100644 --- a/lua.spec +++ b/lua.spec @@ -6,7 +6,7 @@ Name: lua Version: 5.4.3 -Release: 10 +Release: 11 Summary: A powerful, efficient, lightweight, embeddable scripting language License: MIT URL: http://www.lua.org/ @@ -29,6 +29,15 @@ 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 @@ -67,6 +76,15 @@ mv src/luaconf.h src/luaconf.h.template.in %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 @@ -141,6 +159,9 @@ LD_LIBRARY_PATH=$RPM_BUILD_ROOT/%{_libdir} $RPM_BUILD_ROOT/%{_bindir}/lua -e"_U= %{_mandir}/man1/lua*.1* %changelog +* Tue Apr 18 2023 chenziyang - 5.4.3-11 +- fix CVE-2021-45985 and other commits because CVE change heavily rely on these commits + * Mon Dec 26 2022 liyanan - 5.4.3-10 - add support for LoongArch @@ -185,3 +206,4 @@ LD_LIBRARY_PATH=$RPM_BUILD_ROOT/%{_libdir} $RPM_BUILD_ROOT/%{_bindir}/lua -e"_U= * Tue Sep 10 2019 openEuler Buildteam - 5.3.5-3 - Package init + -- Gitee