From f6d65c026380eca6f142db227a4d534473bd351b Mon Sep 17 00:00:00 2001 From: Michael Lenaghan Date: Fri, 28 Jul 2023 15:04:04 -0400 Subject: [PATCH] Bring Lua to 5.4.4. --- third_party/lua/README.cosmo | 8 +- third_party/lua/lapi.c | 49 ++++++----- third_party/lua/lauxlib.c | 5 +- third_party/lua/lauxlib.h | 10 ++- third_party/lua/lbaselib.c | 29 ++++++- third_party/lua/lcode.c | 35 ++++++-- third_party/lua/lcorolib.c | 8 +- third_party/lua/ldblib.c | 4 +- third_party/lua/ldebug.c | 107 ++++++++++++++++------- third_party/lua/ldo.c | 120 ++++++++++++++++---------- third_party/lua/ldo.h | 4 +- third_party/lua/ldump.c | 4 +- third_party/lua/lfunc.c | 4 +- third_party/lua/lgc.c | 21 +++-- third_party/lua/lgc.h | 10 +++ third_party/lua/linit.c | 4 +- third_party/lua/liolib.c | 4 +- third_party/lua/llex.c | 4 +- third_party/lua/llimits.h | 16 +++- third_party/lua/lmathlib.c | 8 +- third_party/lua/lmem.c | 4 +- third_party/lua/loadlib.c | 4 +- third_party/lua/lobject.c | 14 +-- third_party/lua/lobject.h | 7 +- third_party/lua/lopcodes.c | 4 +- third_party/lua/lopcodes.h | 21 ++++- third_party/lua/loslib.c | 4 +- third_party/lua/lparser.c | 26 ++++-- third_party/lua/lprefix.h | 1 + third_party/lua/lrepl.c | 4 +- third_party/lua/lstate.c | 15 ++-- third_party/lua/lstate.h | 6 +- third_party/lua/lstring.c | 4 +- third_party/lua/lstrlib.c | 133 ++++++++++++++++++++--------- third_party/lua/ltable.c | 55 +++++++----- third_party/lua/ltablib.c | 9 +- third_party/lua/ltests.c | 7 +- third_party/lua/ltm.c | 4 +- third_party/lua/lua.h | 6 +- third_party/lua/lua.main.c | 29 ++++--- third_party/lua/luac.main.c | 11 +-- third_party/lua/luaconf.h | 4 - third_party/lua/lundump.c | 4 +- third_party/lua/lutf8lib.c | 15 ++-- third_party/lua/lvm.c | 56 ++++++------ third_party/lua/lzio.c | 4 +- third_party/lua/test/api.lua | 5 +- third_party/lua/test/bitwise.lua | 5 ++ third_party/lua/test/code.lua | 14 +++ third_party/lua/test/coroutine.lua | 46 +++++++++- third_party/lua/test/cstack.lua | 14 +++ third_party/lua/test/db.lua | 45 +++++++++- third_party/lua/test/errors.lua | 20 ++++- third_party/lua/test/files.lua | 3 +- third_party/lua/test/gc.lua | 8 +- third_party/lua/test/literals.lua | 24 ++++++ third_party/lua/test/locals.lua | 84 ++++++++++++++++++ third_party/lua/test/main.lua | 33 +++++++ third_party/lua/test/math.lua | 1 + third_party/lua/test/nextvar.lua | 38 +++++++++ third_party/lua/test/strings.lua | 36 ++++++-- third_party/lua/test/utf8.lua | 6 ++ 62 files changed, 946 insertions(+), 341 deletions(-) diff --git a/third_party/lua/README.cosmo b/third_party/lua/README.cosmo index 1d418f797..bd5de7295 100644 --- a/third_party/lua/README.cosmo +++ b/third_party/lua/README.cosmo @@ -9,14 +9,14 @@ PROVENANCE https://github.com/lua/lua/ - commit e7803f7dbcdc966ab1f9db143424ee811ab1a398 + commit 5d708c3f9cae12820e415d4f89c9eacbe2ab964b Author: Roberto Ierusalimschy - Date: Wed Mar 3 09:44:20 2021 -0300 + Date: Jan 13, 2022 at 6:15 AM EST - New release number (5.4.3) + New release number (5.4.4) luac.c needed to be sourced from: - https://www.lua.org/ftp/lua-5.4.3.tar.gz + https://www.lua.org/ftp/lua-5.4.4.tar.gz LOCAL MODIFICATIONS diff --git a/third_party/lua/lapi.c b/third_party/lua/lapi.c index b6916019a..36bc2f32c 100644 --- a/third_party/lua/lapi.c +++ b/third_party/lua/lapi.c @@ -47,8 +47,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -73,6 +73,10 @@ const char lua_ident[] = #define isupvalue(i) ((i) < LUA_REGISTRYINDEX) +/* +** Convert an acceptable index to a pointer to its respective value. +** Non-valid indices return the special nil value 'G(L)->nilvalue'. +*/ static TValue *index2value (lua_State *L, int idx) { CallInfo *ci = L->ci; if (idx > 0) { @@ -90,22 +94,28 @@ static TValue *index2value (lua_State *L, int idx) { else { /* upvalues */ idx = LUA_REGISTRYINDEX - idx; api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); - if (ttislcf(s2v(ci->func))) /* light C function? */ - return &G(L)->nilvalue; /* it has no upvalues */ - else { + if (ttisCclosure(s2v(ci->func))) { /* C closure? */ CClosure *func = clCvalue(s2v(ci->func)); return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : &G(L)->nilvalue; } + else { /* light C function or Lua function (through a hook)?) */ + api_check(L, ttislcf(s2v(ci->func)), "caller not a C function"); + return &G(L)->nilvalue; /* no upvalues */ } } +} -static StkId index2stack (lua_State *L, int idx) { + +/* +** Convert a valid actual index (not a pseudo-index) to its address. +*/ +l_sinline StkId index2stack (lua_State *L, int idx) { CallInfo *ci = L->ci; if (idx > 0) { StkId o = ci->func + idx; - api_check(L, o < L->top, "unacceptable index"); + api_check(L, o < L->top, "invalid index"); return o; } else { /* non-positive index */ @@ -277,7 +287,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)); @@ -497,7 +507,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); @@ -815,7 +825,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)) { @@ -890,7 +900,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 @@ -1407,18 +1417,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; /* stopped 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: { @@ -1437,8 +1448,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); @@ -1448,7 +1459,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; @@ -1466,7 +1477,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/third_party/lua/lauxlib.c b/third_party/lua/lauxlib.c index 5e75a2793..6731dc7bf 100644 --- a/third_party/lua/lauxlib.c +++ b/third_party/lua/lauxlib.c @@ -39,8 +39,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -1243,6 +1243,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { * the result of the call as its result. */ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + idx = lua_absindex(L,idx); if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ if (!lua_isstring(L, -1)) luaL_error(L, "'__tostring' must return a string"); diff --git a/third_party/lua/lauxlib.h b/third_party/lua/lauxlib.h index 8ff7b43e0..ca6acc60c 100644 --- a/third_party/lua/lauxlib.h +++ b/third_party/lua/lauxlib.h @@ -94,7 +94,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); @@ -149,6 +149,14 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, #define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) +/* +** Perform arithmetic operations on lua_Integer values with wrap-around +** semantics, as the Lua core does. +*/ +#define luaL_intop(op,v1,v2) \ + ((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2))) + + /* push the value used to represent failure/error */ #define luaL_pushfail(L) lua_pushnil(L) diff --git a/third_party/lua/lbaselib.c b/third_party/lua/lbaselib.c index b550dc1b2..436f4de10 100644 --- a/third_party/lua/lbaselib.c +++ b/third_party/lua/lbaselib.c @@ -37,8 +37,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -203,12 +203,20 @@ static int luaB_rawset (lua_State *L) { static int pushmode (lua_State *L, int oldmode) { + 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", @@ -221,12 +229,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; } @@ -234,11 +244,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; } @@ -255,10 +267,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; } @@ -282,6 +297,11 @@ static int luaB_next (lua_State *L) { } +static int pairscont (lua_State *L, int status, lua_KContext k) { + (void)L; (void)status; (void)k; /* unused */ + return 3; +} + static int luaB_pairs (lua_State *L) { luaL_checkany(L, 1); if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */ @@ -291,7 +311,7 @@ static int luaB_pairs (lua_State *L) { } else { lua_pushvalue(L, 1); /* argument 'self' to metamethod */ - lua_call(L, 1, 3); /* get 3 values from metamethod */ + lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */ } return 3; } @@ -301,7 +321,8 @@ static int luaB_pairs (lua_State *L) { ** Traversal function for 'ipairs' */ static int ipairsaux (lua_State *L) { - lua_Integer i = luaL_checkinteger(L, 2) + 1; + lua_Integer i = luaL_checkinteger(L, 2); + i = luaL_intop(+, i, 1); lua_pushinteger(L, i); return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; } diff --git a/third_party/lua/lcode.c b/third_party/lua/lcode.c index 942b061de..0bd8041db 100644 --- a/third_party/lua/lcode.c +++ b/third_party/lua/lcode.c @@ -47,8 +47,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -602,24 +602,41 @@ static int stringK (FuncState *fs, TString *s) { /* ** Add an integer to list of constants and return its index. -** Integers use userdata as keys to avoid collision with floats with -** same value; conversion to 'void*' is used only for hashing, so there -** are no "precision" problems. */ static int luaK_intK (FuncState *fs, lua_Integer n) { - TValue k, o; - setpvalue(&k, cast_voidp(cast_sizet(n))); + TValue o; setivalue(&o, n); - return addk(fs, &k, &o); + return addk(fs, &o, &o); /* use integer itself as key */ } /* -** Add a float to list of constants and return its index. +** Add a float to list of constants and return its index. Floats +** with integral values need a different key, to avoid collision +** with actual integers. To that, we add to the number its smaller +** power-of-two fraction that is still significant in its scale. +** For doubles, that would be 1/2^52. +** (This method is not bulletproof: there may be another float +** with that value, and for floats larger than 2^53 the result is +** still an integer. At worst, this only wastes an entry with +** a duplicate.) */ static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; + lua_Integer ik; setfltvalue(&o, r); + if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */ return addk(fs, &o, &o); /* use number itself as key */ + else { /* must build an alternative key */ + const int nbm = l_floatatt(MANT_DIG); + const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1); + const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */ + TValue kv; + setfltvalue(&kv, k); + /* result is not an integral value, unless value is too large */ + lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) || + l_mathop(fabs)(r) >= l_mathop(1e6)); + return addk(fs, &kv, &o); + } } diff --git a/third_party/lua/lcorolib.c b/third_party/lua/lcorolib.c index 739ad94df..102ec5b73 100644 --- a/third_party/lua/lcorolib.c +++ b/third_party/lua/lcorolib.c @@ -36,8 +36,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -101,7 +101,7 @@ static int luaB_auxwrap (lua_State *L) { if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ stat = lua_resetthread(co); /* close its tbc variables */ lua_assert(stat != LUA_OK); - lua_xmove(co, L, 1); /* copy error message */ + lua_xmove(co, L, 1); /* move error message to the caller */ } if (stat != LUA_ERRMEM && /* not a memory error and ... */ lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */ @@ -202,7 +202,7 @@ static int luaB_close (lua_State *L) { } else { lua_pushboolean(L, 0); - lua_xmove(co, L, 1); /* copy error message */ + lua_xmove(co, L, 1); /* move error message */ return 2; } } diff --git a/third_party/lua/ldblib.c b/third_party/lua/ldblib.c index 3365f4db9..d6fa30705 100644 --- a/third_party/lua/ldblib.c +++ b/third_party/lua/ldblib.c @@ -37,8 +37,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/ldebug.c b/third_party/lua/ldebug.c index 03cdbe3ff..2eddb9d89 100644 --- a/third_party/lua/ldebug.c +++ b/third_party/lua/ldebug.c @@ -47,15 +47,15 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) -static const char *funcnamefromcode (lua_State *L, CallInfo *ci, +static const char *funcnamefromcall (lua_State *L, CallInfo *ci, const char **name); @@ -85,7 +85,7 @@ static int getbaseline (const Proto *f, int pc, int *basepc) { } else { int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */ - /* estimate must be a lower bond of the correct base */ + /* estimate must be a lower bound of the correct base */ lua_assert(i < 0 || (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc)); while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc) @@ -322,7 +322,14 @@ static void collectvalidlines (lua_State *L, Closure *f) { sethvalue2s(L, L->top, t); /* push it on stack */ api_incr_top(L); setbtvalue(&v); /* boolean 'true' to be the value of all indices */ - for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */ + if (!p->is_vararg) /* regular function? */ + i = 0; /* consider all instructions */ + else { /* vararg function */ + lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); + currentline = nextline(p, currentline, 0); + i = 1; /* skip first instruction (OP_VARARGPREP) */ + } + for (; i < p->sizelineinfo; i++) { /* for each instruction */ currentline = nextline(p, currentline, i); /* get its line */ luaH_setint(L, t, currentline, &v); /* table[line] = true */ } @@ -331,15 +338,9 @@ static void collectvalidlines (lua_State *L, Closure *f) { static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { - if (ci == NULL) /* no 'ci'? */ - return NULL; /* no info */ - else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ - *name = "__gc"; - return "metamethod"; /* report it as such */ - } - /* calling function is a known Lua function? */ - else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) - return funcnamefromcode(L, ci->previous, name); + /* calling function is a known function? */ + if (ci != NULL && !(ci->callstatus & CIST_TAIL)) + return funcnamefromcall(L, ci->previous, name); else return NULL; /* no way to find a name */ } @@ -611,16 +612,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, ** Returns what the name is (e.g., "for iterator", "method", ** "metamethod") and sets '*name' to point to the name. */ -static const char *funcnamefromcode (lua_State *L, CallInfo *ci, - const char **name) { +static const char *funcnamefromcode (lua_State *L, const Proto *p, + int pc, const char **name) { TMS tm = (TMS)0; /* (initial value avoids warnings) */ - const Proto *p = ci_func(ci)->p; /* calling function */ - int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->code[pc]; /* calling instruction */ - if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ - *name = "?"; - return "hook"; - } switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: @@ -657,6 +652,26 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, return "metamethod"; } + +/* +** Try to find a name for a function based on how it was called. +*/ +static const char *funcnamefromcall (lua_State *L, CallInfo *ci, + const char **name) { + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } + else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */ + *name = "__gc"; + return "metamethod"; /* report it as such */ + } + else if (isLua(ci)) + return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name); + else + return NULL; +} + /* }====================================================== */ @@ -696,9 +711,21 @@ static const char *getupvalname (CallInfo *ci, const TValue *o, } +static const char *formatvarinfo (lua_State *L, const char *kind, + const char *name) { + if (kind == NULL) + return ""; /* no information */ + else + return luaO_pushfstring(L, " (%s '%s')", kind, name); +} + +/* +** Build a string with a "description" for the value 'o', such as +** "variable 'x'" or "upvalue 'y'". +*/ static const char *varinfo (lua_State *L, const TValue *o) { - const char *name = NULL; /* to avoid warnings */ CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ const char *kind = NULL; if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ @@ -706,26 +733,40 @@ static const char *varinfo (lua_State *L, const TValue *o) { kind = getobjname(ci_func(ci)->p, currentpc(ci), cast_int(cast(StkId, o) - (ci->func + 1)), &name); } - return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; + return formatvarinfo(L, kind, name); } -l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { +/* +** Raise a type error +*/ +static l_noret typeerror (lua_State *L, const TValue *o, const char *op, + const char *extra) { const char *t = luaT_objtypename(L, o); - luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra); } +/* +** Raise a type error with "standard" information about the faulty +** object 'o' (using 'varinfo'). +*/ +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + typeerror(L, o, op, varinfo(L, o)); +} + + +/* +** Raise an error for calling a non-callable object. Try to find a name +** for the object based on how it was called ('funcnamefromcall'); if it +** cannot get a name there, try 'varinfo'. +*/ l_noret luaG_callerror (lua_State *L, const TValue *o) { CallInfo *ci = L->ci; const char *name = NULL; /* to avoid warnings */ - const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL; - if (what != NULL) { - const char *t = luaT_objtypename(L, o); - luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t); - } - else - luaG_typeerror(L, o, "call"); + const char *kind = funcnamefromcall(L, ci, &name); + const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o); + typeerror(L, o, "call", extra); } diff --git a/third_party/lua/ldo.c b/third_party/lua/ldo.c index bacfe6058..42f9991ee 100644 --- a/third_party/lua/ldo.c +++ b/third_party/lua/ldo.c @@ -56,8 +56,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -414,15 +414,18 @@ 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) { - const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); +StkId luaD_tryfuncTM (lua_State *L, StkId func) { + const TValue *tm; StkId p; + checkstackGCp(L, 1, func); /* space for metamethod */ + tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ 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; } @@ -432,7 +435,7 @@ void 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 */ @@ -500,19 +503,64 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { #define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) +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; + ci->callstatus = mask; + ci->top = top; + return ci; +} + + +/* +** precall for C functions +*/ +l_sinline int 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 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). +** (so that it includes the function itself). Return the number of +** results, if it was a C function, or -1 for a Lua function. */ -void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { +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; + 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 */ @@ -521,6 +569,15 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { 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 */ + } + } } @@ -533,35 +590,14 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { ** 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; - 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 = next_ci(L); - ci->nresults = nresults; - ci->callstatus = 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; - 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); + precallC(L, func, nresults, clCvalue(s2v(func))->f); + return NULL; + case LUA_VLCF: /* light C function */ + precallC(L, func, nresults, fvalue(s2v(func))); return NULL; - } case LUA_VLCL: { /* Lua function */ CallInfo *ci; Proto *p = clLvalue(s2v(func))->p; @@ -569,20 +605,16 @@ 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; + L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); 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); 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 */ + /* return luaD_precall(L, func, nresults); */ goto retry; /* try again with metamethod */ } } @@ -594,7 +626,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)) @@ -755,11 +787,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 */ @@ -810,6 +841,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); diff --git a/third_party/lua/ldo.h b/third_party/lua/ldo.h index 873db6fdf..8e0f2eab8 100644 --- a/third_party/lua/ldo.h +++ b/third_party/lua/ldo.h @@ -52,11 +52,11 @@ 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); -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/third_party/lua/ldump.c b/third_party/lua/ldump.c index 2bc9ba025..7ca3e170d 100644 --- a/third_party/lua/ldump.c +++ b/third_party/lua/ldump.c @@ -37,8 +37,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lfunc.c b/third_party/lua/lfunc.c index dfa340838..6beb34565 100644 --- a/third_party/lua/lfunc.c +++ b/third_party/lua/lfunc.c @@ -42,8 +42,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lgc.c b/third_party/lua/lgc.c index ac8fafe66..3469ddd77 100644 --- a/third_party/lua/lgc.c +++ b/third_party/lua/lgc.c @@ -45,8 +45,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -929,18 +929,18 @@ 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"); + luaE_warnerror(L, "__gc"); L->top--; /* pops error object */ } } @@ -1034,7 +1034,8 @@ static void correctpointers (global_State *g, GCObject *o) { void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { global_State *g = G(L); if (tofinalize(o) || /* obj. is already marked... */ - gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ + gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */ + (g->gcstp & GCSTPCLS)) /* or closing state? */ return; /* nothing to be done */ else { /* move 'o' to 'finobj' list */ GCObject **p; @@ -1525,12 +1526,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) { */ void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); + g->gcstp = GCSTPCLS; /* no extra finalizers after here */ luaC_changemode(L, KGC_INC); separatetobefnz(g, 1); /* separate all objects with finalizers */ lua_assert(g->finobj == NULL); callallpendingfinalizers(L); deletelist(L, g->allgc, obj2gco(g->mainthread)); - deletelist(L, g->finobj, NULL); + lua_assert(g->finobj == NULL); /* no new finalizers */ deletelist(L, g->fixedgc, NULL); /* collect fixed objects */ lua_assert(g->strt.nuse == 0); } @@ -1670,6 +1672,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 @@ -1701,7 +1704,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/third_party/lua/lgc.h b/third_party/lua/lgc.h index 52a09a675..42060d898 100644 --- a/third_party/lua/lgc.h +++ b/third_party/lua/lgc.h @@ -143,6 +143,16 @@ */ #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 GCSTPCLS 4 /* bit true when closing Lua state */ +#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/third_party/lua/linit.c b/third_party/lua/linit.c index c28832b97..24b6a25e6 100644 --- a/third_party/lua/linit.c +++ b/third_party/lua/linit.c @@ -52,8 +52,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/liolib.c b/third_party/lua/liolib.c index 9c925f7f4..d9f19cbdf 100644 --- a/third_party/lua/liolib.c +++ b/third_party/lua/liolib.c @@ -43,8 +43,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/llex.c b/third_party/lua/llex.c index df3b8cb07..4550a4e3b 100644 --- a/third_party/lua/llex.c +++ b/third_party/lua/llex.c @@ -45,8 +45,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/llimits.h b/third_party/lua/llimits.h index f7c66a9df..1f0a12b1b 100644 --- a/third_party/lua/llimits.h +++ b/third_party/lua/llimits.h @@ -156,6 +156,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) @@ -338,7 +352,7 @@ typedef l_uint32 Instruction; #define condchangemem(L,pre,pos) ((void)0) #else #define condchangemem(L,pre,pos) \ - { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } + { if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } } #endif #endif diff --git a/third_party/lua/lmathlib.c b/third_party/lua/lmathlib.c index 187720c0b..68c0716de 100644 --- a/third_party/lua/lmathlib.c +++ b/third_party/lua/lmathlib.c @@ -39,8 +39,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -497,7 +497,7 @@ static lua_Number I2d (Rand64 x) { /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ #define scaleFIG \ - ((lua_Number)1.0 / (UONE << 30) / 8.0 / (UONE << (FIGS - 33))) + (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) /* ** use FIGS - 32 bits from lower half, throwing out the other @@ -508,7 +508,7 @@ static lua_Number I2d (Rand64 x) { /* ** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32) */ -#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * 2.0) +#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0)) static lua_Number I2d (Rand64 x) { diff --git a/third_party/lua/lmem.c b/third_party/lua/lmem.c index 0f1c832ec..40b99dcc8 100644 --- a/third_party/lua/lmem.c +++ b/third_party/lua/lmem.c @@ -41,8 +41,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/loadlib.c b/third_party/lua/loadlib.c index 9a5a82777..2cf3708d5 100644 --- a/third_party/lua/loadlib.c +++ b/third_party/lua/loadlib.c @@ -38,8 +38,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lobject.c b/third_party/lua/lobject.c index 5f8ea2f23..e7b8dbec9 100644 --- a/third_party/lua/lobject.c +++ b/third_party/lua/lobject.c @@ -43,8 +43,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -168,7 +168,7 @@ static int isneg (const char **s) { */ static lua_Number lua_strx2number (const char *s, char **endptr) { int dot = lua_getlocaledecpoint(); - lua_Number r = 0.0; /* result (accumulator) */ + lua_Number r = l_mathop(0.0); /* result (accumulator) */ int sigdig = 0; /* number of significant digits */ int nosigdig = 0; /* number of non-significant digits */ int e = 0; /* exponent correction */ @@ -178,7 +178,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); /* check sign */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ - return 0.0; /* invalid format (no '0x') */ + return l_mathop(0.0); /* invalid format (no '0x') */ for (s += 2; ; s++) { /* skip '0x' and read numeral */ if (*s == dot) { if (hasdot) break; /* second dot? stop loop */ @@ -188,14 +188,14 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ nosigdig++; else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ - r = (r * cast_num(16.0)) + luaO_hexavalue(*s); + r = (r * l_mathop(16.0)) + luaO_hexavalue(*s); else e++; /* too many digits; ignore, but still count for exponent */ if (hasdot) e--; /* decimal digit? correct exponent */ } else break; /* neither a dot nor a digit */ } if (nosigdig + sigdig == 0) /* no digits? */ - return 0.0; /* invalid format */ + return l_mathop(0.0); /* invalid format */ *endptr = cast_charp(s); /* valid up to here */ e *= 4; /* each digit multiplies/divides value by 2^4 */ if (*s == 'p' || *s == 'P') { /* exponent part? */ @@ -204,7 +204,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { s++; /* skip 'p' */ neg1 = isneg(&s); /* sign */ if (!lisdigit(cast_uchar(*s))) - return 0.0; /* invalid; must have at least one digit */ + return l_mathop(0.0); /* invalid; must have at least one digit */ while (lisdigit(cast_uchar(*s))) /* read exponent */ exp1 = exp1 * 10 + *(s++) - '0'; if (neg1) exp1 = -exp1; diff --git a/third_party/lua/lobject.h b/third_party/lua/lobject.h index b3396fb56..685d8d12f 100644 --- a/third_party/lua/lobject.h +++ b/third_party/lua/lobject.h @@ -14,11 +14,14 @@ #define LUA_TPROTO (LUA_NUMTYPES + 1) /* function prototypes */ #define LUA_TDEADKEY (LUA_NUMTYPES + 2) /* removed keys in tables */ + + /* ** number of all possible types (including LUA_TNONE but excluding DEADKEY) */ #define LUA_TOTALTYPES (LUA_TPROTO + 2) + /* ** tags for Tagged Values have the following use of bits: ** bits 0-3: actual tag (a LUA_T* constant) @@ -56,7 +59,7 @@ typedef struct TValue { #define val_(o) ((o)->value_) -#define valraw(o) (&val_(o)) +#define valraw(o) (val_(o)) /* raw type tag of a TValue */ @@ -100,7 +103,7 @@ typedef struct TValue { #define settt_(o,t) ((o)->tt_=(t)) -/* main macro to copy values (from 'obj1' to 'obj2') */ +/* main macro to copy values (from 'obj2' to 'obj1') */ #define setobj(L,obj1,obj2) \ { TValue *io1=(obj1); const TValue *io2=(obj2); \ io1->value_ = io2->value_; settt_(io1, io2->tt_); \ diff --git a/third_party/lua/lopcodes.c b/third_party/lua/lopcodes.c index 649ea2fa7..28b2f8f11 100644 --- a/third_party/lua/lopcodes.c +++ b/third_party/lua/lopcodes.c @@ -34,8 +34,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lopcodes.h b/third_party/lua/lopcodes.h index 39f726fc7..0ceadc95d 100644 --- a/third_party/lua/lopcodes.h +++ b/third_party/lua/lopcodes.h @@ -185,7 +185,8 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ /* -** grep "ORDER OP" if you change these enums +** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*) +** has extra descriptions in the notes after the enumeration. */ typedef enum { @@ -198,7 +199,7 @@ OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */ OP_LOADK,/* A Bx R[A] := K[Bx] */ OP_LOADKX,/* A R[A] := K[extra arg] */ OP_LOADFALSE,/* A R[A] := false */ -OP_LFALSESKIP,/*A R[A] := false; pc++ */ +OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */ OP_LOADTRUE,/* A R[A] := true */ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */ OP_GETUPVAL,/* A B R[A] := UpValue[B] */ @@ -249,7 +250,7 @@ OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */ OP_SHL,/* A B C R[A] := R[B] << R[C] */ OP_SHR,/* A B C R[A] := R[B] >> R[C] */ -OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] */ +OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */ OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */ OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */ @@ -275,7 +276,7 @@ OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */ OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */ OP_TEST,/* A k if (not R[A] == k) then pc++ */ -OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */ +OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */ OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */ OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */ @@ -310,6 +311,18 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ /*=========================================================================== Notes: + + (*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean + value, in a code equivalent to (not cond ? false : true). (It + produces false and skips the next instruction producing true.) + + (*) Opcodes OP_MMBIN and variants follow each arithmetic and + bitwise opcode. If the operation succeeds, it skips this next + opcode. Otherwise, this opcode calls the corresponding metamethod. + + (*) Opcode OP_TESTSET is used in short-circuit expressions that need + both to jump and to produce a value, such as (a = b or c). + (*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then 'top' is set to last_result+1, so next open instruction (OP_CALL, OP_RETURN*, OP_SETLIST) may use 'top'. diff --git a/third_party/lua/loslib.c b/third_party/lua/loslib.c index 4e9d87e32..98e43312a 100644 --- a/third_party/lua/loslib.c +++ b/third_party/lua/loslib.c @@ -46,8 +46,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lparser.c b/third_party/lua/lparser.c index 4f2bc77df..e62ddc88f 100644 --- a/third_party/lua/lparser.c +++ b/third_party/lua/lparser.c @@ -47,8 +47,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -438,6 +438,17 @@ static void markupval (FuncState *fs, int level) { } +/* +** Mark that current block has a to-be-closed variable. +*/ +static void marktobeclosed (FuncState *fs) { + BlockCnt *bl = fs->bl; + bl->upval = 1; + bl->insidetbc = 1; + fs->needclose = 1; +} + + /* ** Find a variable with the given name 'n'. If it is an upvalue, add ** this upvalue into all intermediate functions. If it is a global, set @@ -1621,7 +1632,7 @@ static void forlist (LexState *ls, TString *indexname) { line = ls->linenumber; adjust_assign(ls, 4, explist(ls, &e), &e); adjustlocalvars(ls, 4); /* control variables */ - markupval(fs, fs->nactvar); /* last control var. must be closed */ + marktobeclosed(fs); /* last control var. must be closed */ luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 4, 1); } @@ -1725,11 +1736,9 @@ static int getlocalattribute (LexState *ls) { } -static void checktoclose (LexState *ls, int level) { +static void checktoclose (FuncState *fs, int level) { if (level != -1) { /* is there a to-be-closed variable? */ - FuncState *fs = ls->fs; - markupval(fs, level + 1); - fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ + marktobeclosed(fs); luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); } } @@ -1773,7 +1782,7 @@ static void localstat (LexState *ls) { adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } - checktoclose(ls, toclose); + checktoclose(fs, toclose); } @@ -1798,6 +1807,7 @@ static void funcstat (LexState *ls, int line) { luaX_next(ls); /* skip FUNCTION */ ismethod = funcname(ls, &v); body(ls, &b, ismethod, line); + check_readonly(ls, &v); luaK_storevar(ls->fs, &v, &b); luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ } diff --git a/third_party/lua/lprefix.h b/third_party/lua/lprefix.h index 7d76a1067..33ded6885 100644 --- a/third_party/lua/lprefix.h +++ b/third_party/lua/lprefix.h @@ -24,6 +24,7 @@ #endif /* } */ + /* ** Windows stuff */ diff --git a/third_party/lua/lrepl.c b/third_party/lua/lrepl.c index f7e63121b..336854525 100644 --- a/third_party/lua/lrepl.c +++ b/third_party/lua/lrepl.c @@ -51,8 +51,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lstate.c b/third_party/lua/lstate.c index bd64619b8..755b92511 100644 --- a/third_party/lua/lstate.c +++ b/third_party/lua/lstate.c @@ -47,8 +47,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -187,7 +187,7 @@ void luaE_checkcstack (lua_State *L) { if (getCcalls(L) == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ + luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ } @@ -257,7 +257,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); } @@ -290,8 +290,9 @@ static void preinit_thread (lua_State *L, global_State *g) { static void close_state (lua_State *L) { global_State *g = G(L); if (!completestate(g)) /* closing a partially built state? */ - luaC_freeallobjects(L); /* jucst collect its objects */ + luaC_freeallobjects(L); /* just 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); @@ -361,13 +362,13 @@ int luaE_resetthread (lua_State *L, int status) { ci->callstatus = CIST_C; if (status == LUA_YIELD) status = LUA_OK; + L->status = LUA_OK; /* so it can run __close metamethods */ status = luaD_closeprotected(L, 1, status); if (status != LUA_OK) /* errors? */ luaD_seterrorobj(L, status, L->stack + 1); else L->top = L->stack + 1; ci->top = L->top + LUA_MINSTACK; - L->status = cast_byte(status); luaD_reallocstack(L, cast_int(ci->top - L->stack), 0); return status; } @@ -403,7 +404,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/third_party/lua/lstate.h b/third_party/lua/lstate.h index cd54d8a96..572945f22 100644 --- a/third_party/lua/lstate.h +++ b/third_party/lua/lstate.h @@ -159,7 +159,7 @@ typedef struct stringtable { ** - field 'nyield' is used only while a function is "doing" an ** yield (from the yield until the next resume); ** - field 'nres' is used only while closing tbc variables when -** returning from a C function; +** returning from a function; ** - field 'transferinfo' is used only during call/returnhooks, ** before the function starts or after it ends. */ @@ -203,7 +203,7 @@ typedef struct CallInfo { #define CIST_YPCALL (1<<4) /* doing a yieldable protected call */ #define CIST_TAIL (1<<5) /* call was tail called */ #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ -#define CIST_FIN (1<<7) /* call is running a finalizer */ +#define CIST_FIN (1<<7) /* function "called" a finalizer */ #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ #define CIST_CLSRET (1<<9) /* function is closing tbc variables */ /* Bits 10-12 are used for CIST_RECST (see below) */ @@ -257,7 +257,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" */ diff --git a/third_party/lua/lstring.c b/third_party/lua/lstring.c index ae80c9b9d..b7d84c13d 100644 --- a/third_party/lua/lstring.c +++ b/third_party/lua/lstring.c @@ -41,8 +41,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lstrlib.c b/third_party/lua/lstrlib.c index 462fc6b11..e52dd827e 100644 --- a/third_party/lua/lstrlib.c +++ b/third_party/lua/lstrlib.c @@ -39,8 +39,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -1134,13 +1134,31 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, /* valid flags in a format specification */ -#if !defined(L_FMTFLAGS) -#define L_FMTFLAGS "-+ #0" +#if !defined(L_FMTFLAGSF) + +/* valid flags for a, A, e, E, f, F, g, and G conversions */ +#define L_FMTFLAGSF "-+#0 " + +/* valid flags for o, x, and X conversions */ +#define L_FMTFLAGSX "-#0" + +/* valid flags for d and i conversions */ +#define L_FMTFLAGSI "-+0 " + +/* valid flags for u conversions */ +#define L_FMTFLAGSU "-0" + +/* valid flags for c, p, and s conversions */ +#define L_FMTFLAGSC "-" + #endif /* -** maximum size of each format specification (such as "%-099.99d") +** Maximum size of each format specification (such as "%-099.99d"): +** Initial '%', flags (up to 5), width (2), period, precision (2), +** length modifier (8), conversion specifier, and final '\0', plus some +** extra. */ #define MAX_FORMAT 32 @@ -1233,25 +1251,53 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { } -static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { - const char *p = strfrmt; - while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */ - if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char)) - luaL_error(L, "invalid format (repeated flags)"); - if (isdigit(uchar(*p))) p++; /* skip width */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - if (*p == '.') { - p++; - if (isdigit(uchar(*p))) p++; /* skip precision */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ +static const char *get2digits (const char *s) { + if (isdigit(uchar(*s))) { + s++; + if (isdigit(uchar(*s))) s++; /* (2 digits at most) */ } - if (isdigit(uchar(*p))) - luaL_error(L, "invalid format (width or precision too long)"); + return s; +} + + +/* +** Check whether a conversion specification is valid. When called, +** first character in 'form' must be '%' and last character must +** be a valid conversion specifier. 'flags' are the accepted flags; +** 'precision' signals whether to accept a precision. +*/ +static void checkformat (lua_State *L, const char *form, const char *flags, + int precision) { + const char *spec = form + 1; /* skip '%' */ + spec += strspn(spec, flags); /* skip flags */ + if (*spec != '0') { /* a width cannot start with '0' */ + spec = get2digits(spec); /* skip width */ + if (*spec == '.' && precision) { + spec++; + spec = get2digits(spec); /* skip precision */ + } + } + if (!isalpha(uchar(*spec))) /* did not go to the end? */ + luaL_error(L, "invalid conversion specification: '%s'", form); + } + + +/* +** Get a conversion specification and copy it to 'form'. +** Return the address of its last character. +*/ +static const char *getformat (lua_State *L, const char *strfrmt, + char *form) { + /* spans flags, width, and precision ('0' is included as a flag) */ + size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789."); + len++; /* adds following character (should be the specifier) */ + /* still needs space for '%', '\0', plus a length modifier */ + if (len >= MAX_FORMAT - 10) + luaL_error(L, "invalid format (too long)"); *(form++) = '%'; - memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); - form += (p - strfrmt) + 1; - *form = '\0'; - return p; + memcpy(form, strfrmt, len * sizeof(char)); + *(form + len) = '\0'; + return strfrmt + len - 1; } @@ -1274,6 +1320,7 @@ static int str_format (lua_State *L) { size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); const char *strfrmt_end = strfrmt+sfl; + const char *flags; luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { @@ -1283,25 +1330,35 @@ static int str_format (lua_State *L) { luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format ('%...') */ - int maxitem = MAX_ITEM; - char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */ - int nb = 0; /* number of bytes in added item */ + int maxitem = MAX_ITEM; /* maximum length for the result */ + char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */ + int nb = 0; /* number of bytes in result */ if (++arg > top) return luaL_argerror(L, arg, "no value"); - strfrmt = scanformat(L, strfrmt, form); + strfrmt = getformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { + checkformat(L, form, L_FMTFLAGSC, 0); nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); break; } case 'd': case 'i': - case 'o': case 'u': case 'x': case 'X': { + flags = L_FMTFLAGSI; + goto intcase; + case 'u': + flags = L_FMTFLAGSU; + goto intcase; + case 'o': case 'x': case 'X': + flags = L_FMTFLAGSX; + intcase: { lua_Integer n = luaL_checkinteger(L, arg); + checkformat(L, form, flags, 1); addlenmod(form, LUA_INTEGER_FRMLEN); nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); break; } case 'a': case 'A': + checkformat(L, form, L_FMTFLAGSF, 1); addlenmod(form, LUA_NUMBER_FRMLEN); nb = lua_number2strx(L, buff, maxitem, form, luaL_checknumber(L, arg)); @@ -1312,12 +1369,14 @@ static int str_format (lua_State *L) { /* FALLTHROUGH */ case 'e': case 'E': case 'g': case 'G': { lua_Number n = luaL_checknumber(L, arg); + checkformat(L, form, L_FMTFLAGSF, 1); addlenmod(form, LUA_NUMBER_FRMLEN); nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); break; } case 'p': { const void *p = lua_topointer(L, arg); + checkformat(L, form, L_FMTFLAGSC, 0); if (p == NULL) { /* avoid calling 'printf' with argument NULL */ p = "(null)"; /* result */ form[strlen(form) - 1] = 's'; /* format it as a string */ @@ -1338,7 +1397,8 @@ static int str_format (lua_State *L) { luaL_addvalue(&b); /* keep entire string */ else { luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); - if (!strchr(form, '.') && l >= 100) { + checkformat(L, form, L_FMTFLAGSC, 1); + if (strchr(form, '.') == NULL && l >= 100) { /* no precision and string is too long to be formatted */ luaL_addvalue(&b); /* keep entire string */ } @@ -1396,15 +1456,6 @@ static const union { } nativeendian = {1}; -/* dummy structure to get native alignment requirements */ -struct cD { - char c; - union { double d; void *p; lua_Integer i; lua_Number n; } u; -}; - -#define MAXALIGN (offsetof(struct cD, u)) - - /* ** information to pack/unpack stuff */ @@ -1479,6 +1530,8 @@ static void initheader (lua_State *L, Header *h) { ** Read and classify next option. 'size' is filled with option's size. */ static KOption getoption (Header *h, const char **fmt, int *size) { + /* dummy structure to get native alignment requirements */ + struct cD { char c; union { LUAI_MAXALIGN; } u; }; int opt = *((*fmt)++); *size = 0; /* default */ switch (opt) { @@ -1509,7 +1562,11 @@ static KOption getoption (Header *h, const char **fmt, int *size) { case '<': h->islittle = 1; break; case '>': h->islittle = 0; break; case '=': h->islittle = nativeendian.little; break; - case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; + case '!': { + const int maxalign = offsetof(struct cD, u); + h->maxalign = getnumlimit(h, fmt, maxalign); + break; + } default: luaL_error(h->L, "invalid format option '%c'", opt); } return Knop; diff --git a/third_party/lua/ltable.c b/third_party/lua/ltable.c index 740dcd8f2..3d11d6d96 100644 --- a/third_party/lua/ltable.c +++ b/third_party/lua/ltable.c @@ -43,8 +43,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -107,8 +107,6 @@ asm(".include \"libc/disclaimer.inc\""); #define hashstr(t,str) hashpow2(t, (str)->hash) #define hashboolean(t,p) hashpow2(t, p) -#define hashint(t,i) hashpow2(t, i) - #define hashpointer(t,p) hashmod(t, point2uint(p)) @@ -124,6 +122,20 @@ static const Node dummynode_ = { static const TValue absentkey = {ABSTKEYCONSTANT}; +/* +** Hash for integers. To allow a good hash, use the remainder operator +** ('%'). If integer fits as a non-negative int, compute an int +** remainder, which is faster. Otherwise, use an unsigned-integer +** remainder, which uses all bits and ensures a non-negative result. +*/ +static Node *hashint (const Table *t, lua_Integer i) { + lua_Unsigned ui = l_castS2U(i); + if (ui <= (unsigned int)INT_MAX) + return hashmod(t, cast_int(ui)); + else + return hashmod(t, ui); +} + /* ** Hash for floating-point numbers. @@ -157,26 +169,24 @@ static int l_hashfloat (lua_Number n) { /* ** returns the 'main' position of an element in a table (that is, -** the index of its hash value). The key comes broken (tag in 'ktt' -** and value in 'vkl') so that we can call it on keys inserted into -** nodes. +** the index of its hash value). */ -static Node *mainposition (const Table *t, int ktt, const Value *kvl) { - switch (withvariant(ktt)) { +static Node *mainpositionTV (const Table *t, const TValue *key) { + switch (ttypetag(key)) { case LUA_VNUMINT: { - lua_Integer key = ivalueraw(*kvl); - return hashint(t, key); + lua_Integer i = ivalue(key); + return hashint(t, i); } case LUA_VNUMFLT: { - lua_Number n = fltvalueraw(*kvl); + lua_Number n = fltvalue(key); return hashmod(t, l_hashfloat(n)); } case LUA_VSHRSTR: { - TString *ts = tsvalueraw(*kvl); + TString *ts = tsvalue(key); return hashstr(t, ts); } case LUA_VLNGSTR: { - TString *ts = tsvalueraw(*kvl); + TString *ts = tsvalue(key); return hashpow2(t, luaS_hashlongstr(ts)); } case LUA_VFALSE: @@ -184,26 +194,25 @@ static Node *mainposition (const Table *t, int ktt, const Value *kvl) { case LUA_VTRUE: return hashboolean(t, 1); case LUA_VLIGHTUSERDATA: { - void *p = pvalueraw(*kvl); + void *p = pvalue(key); return hashpointer(t, p); } case LUA_VLCF: { - lua_CFunction f = fvalueraw(*kvl); + lua_CFunction f = fvalue(key); return hashpointer(t, f); } default: { - GCObject *o = gcvalueraw(*kvl); + GCObject *o = gcvalue(key); return hashpointer(t, o); } } } -/* -** Returns the main position of an element given as a 'TValue' -*/ -static Node *mainpositionTV (const Table *t, const TValue *key) { - return mainposition(t, rawtt(key), valraw(key)); +l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) { + TValue key; + getnodekey(cast(lua_State *, NULL), &key, nd); + return mainpositionTV(t, &key); } @@ -702,7 +711,7 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { return; } lua_assert(!isdummy(t)); - othern = mainposition(t, keytt(mp), &keyval(mp)); + othern = mainpositionfromnode(t, mp); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (othern + gnext(othern) != mp) /* find previous */ diff --git a/third_party/lua/ltablib.c b/third_party/lua/ltablib.c index 6315a65c9..f6304e66a 100644 --- a/third_party/lua/ltablib.c +++ b/third_party/lua/ltablib.c @@ -39,8 +39,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -83,8 +83,9 @@ static void checktab (lua_State *L, int arg, int what) { static int tinsert (lua_State *L) { - lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ lua_Integer pos; /* where to insert new element */ + lua_Integer e = aux_getn(L, 1, TAB_RW); + e = luaL_intop(+, e, 1); /* first empty element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ @@ -171,7 +172,7 @@ static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { lua_geti(L, 1, i); if (l_unlikely(!lua_isstring(L, -1))) luaL_error(L, "invalid value (%s) at index %I in table for 'concat'", - luaL_typename(L, -1), i); + luaL_typename(L, -1), (LUAI_UACINT)i); luaL_addvalue(b); } diff --git a/third_party/lua/ltests.c b/third_party/lua/ltests.c index 284464bac..e26488242 100644 --- a/third_party/lua/ltests.c +++ b/third_party/lua/ltests.c @@ -48,8 +48,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -1761,6 +1761,9 @@ static struct X { int x; } x; (void)s1; /* to avoid warnings */ lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0); } + else if EQ("Ltolstring") { + luaL_tolstring(L1, getindex, NULL); + } else if EQ("type") { lua_pushstring(L1, luaL_typename(L1, getnum)); } diff --git a/third_party/lua/ltm.c b/third_party/lua/ltm.c index ab0aad6ee..0ebc819ab 100644 --- a/third_party/lua/ltm.c +++ b/third_party/lua/ltm.c @@ -43,8 +43,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lua.h b/third_party/lua/lua.h index 681154720..c36264dbb 100644 --- a/third_party/lua/lua.h +++ b/third_party/lua/lua.h @@ -10,14 +10,14 @@ COSMOPOLITAN_C_START_ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "4" -#define LUA_VERSION_RELEASE "3" +#define LUA_VERSION_RELEASE "4" #define LUA_VERSION_NUM 504 -#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0) +#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4) #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2021 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" diff --git a/third_party/lua/lua.main.c b/third_party/lua/lua.main.c index 54af3280b..807c79740 100644 --- a/third_party/lua/lua.main.c +++ b/third_party/lua/lua.main.c @@ -55,8 +55,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -92,7 +92,8 @@ static void print_usage (const char *badoption) { "Available options are:\n" " -e stat execute string 'stat'\n" " -i enter interactive mode after executing 'script'\n" - " -l name require library 'name' into global 'name'\n" + " -l mod require library 'mod' into global 'mod'\n" + " -l g=mod require library 'mod' into global 'g'\n" " -v show version information\n" " -E ignore environment variables\n" " -W turn warnings on\n" @@ -147,17 +148,23 @@ static int dostring (lua_State *L, const char *s, const char *name) { /* -** Calls 'require(name)' and stores the result in a global variable -** with the given name. +** Receives 'globname[=modname]' and runs 'globname = require(modname)'. */ -static int dolibrary (lua_State *L, const char *name) { +static int dolibrary (lua_State *L, char *globname) { int status; + char *modname = strchr(globname, '='); + if (modname == NULL) /* no explicit name? */ + modname = globname; /* module name is equal to global name */ + else { + *modname = '\0'; /* global name ends here */ + modname++; /* module name starts after the '=' */ + } lua_getglobal(L, "require"); - lua_pushstring(L, name); - status = lua_runchunk(L, 1, 1); /* call 'require(name)' */ + lua_pushstring(L, modname); + status = docall(L, 1, 1); /* call 'require(modname)' */ if (status == LUA_OK) - lua_setglobal(L, name); /* global[name] = require return */ - return lua_report(L, status); + lua_setglobal(L, globname); /* globname = require(modname) */ + return report(L, status); } @@ -267,7 +274,7 @@ static int runargs (lua_State *L, char **argv, int n) { switch (option) { case 'e': case 'l': { int status; - const char *extra = argv[i] + 2; /* both options need an argument */ + char *extra = argv[i] + 2; /* both options need an argument */ if (*extra == '\0') extra = argv[++i]; lua_assert(extra != NULL); status = (option == 'e') diff --git a/third_party/lua/luac.main.c b/third_party/lua/luac.main.c index df3fede39..9138fc634 100644 --- a/third_party/lua/luac.main.c +++ b/third_party/lua/luac.main.c @@ -48,8 +48,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -183,6 +183,7 @@ static const Proto* combine(lua_State* L, int n) f->p[i]=toproto(L,i-n-1); if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; } + luaM_freearray(L,f->lineinfo,f->sizelineinfo); f->sizelineinfo=0; return f; } @@ -628,11 +629,11 @@ static void PrintCode(const Proto* f) if (c==0) printf("all out"); else printf("%d out",c-1); break; case OP_TAILCALL: - printf("%d %d %d",a,b,c); + printf("%d %d %d%s",a,b,c,ISK); printf(COMMENT "%d in",b-1); break; case OP_RETURN: - printf("%d %d %d",a,b,c); + printf("%d %d %d%s",a,b,c,ISK); printf(COMMENT); if (b==0) printf("all out"); else printf("%d out",b-1); break; @@ -647,7 +648,7 @@ static void PrintCode(const Proto* f) break; case OP_FORPREP: printf("%d %d",a,bx); - printf(COMMENT "to %d",pc+bx+2); + printf(COMMENT "exit to %d",pc+bx+3); break; case OP_TFORPREP: printf("%d %d",a,bx); diff --git a/third_party/lua/luaconf.h b/third_party/lua/luaconf.h index 2424acce1..c66615806 100644 --- a/third_party/lua/luaconf.h +++ b/third_party/lua/luaconf.h @@ -424,7 +424,6 @@ @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. @@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED. -@@ LUA_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED. @@ lua_integer2str converts an integer to a string. */ @@ -445,9 +444,6 @@ #define LUA_UNSIGNED unsigned LUAI_UACINT -#define LUA_UNSIGNEDBITS (sizeof(LUA_UNSIGNED) * CHAR_BIT) - - /* now the variable definitions */ #if LUA_INT_TYPE == LUA_INT_INT /* { int */ diff --git a/third_party/lua/lundump.c b/third_party/lua/lundump.c index 118ca51c7..d5a4e492d 100644 --- a/third_party/lua/lundump.c +++ b/third_party/lua/lundump.c @@ -43,8 +43,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/lutf8lib.c b/third_party/lua/lutf8lib.c index 3496960bd..eb92d9f37 100644 --- a/third_party/lua/lutf8lib.c +++ b/third_party/lua/lutf8lib.c @@ -36,8 +36,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -244,14 +244,11 @@ static int byteoffset (lua_State *L) { static int iter_aux (lua_State *L, int strict) { size_t len; const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = lua_tointeger(L, 2) - 1; - if (n < 0) /* first iteration? */ - n = 0; /* start from here */ - else if (n < (lua_Integer)len) { - n++; /* skip current byte */ - while (iscont(s + n)) n++; /* and its continuations */ + lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2); + if (n < len) { + while (iscont(s + n)) n++; /* skip continuation bytes */ } - if (n >= (lua_Integer)len) + if (n >= len) /* (also handles original 'n' being negative) */ return 0; /* no more codepoints */ else { utfint code; diff --git a/third_party/lua/lvm.c b/third_party/lua/lvm.c index 4e4d69457..c93c436f2 100644 --- a/third_party/lua/lvm.c +++ b/third_party/lua/lvm.c @@ -47,7 +47,7 @@ asm(".ident\t\"\\n\\n\ Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); @@ -426,7 +426,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) */ @@ -443,7 +443,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) */ @@ -460,7 +460,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 */ @@ -477,7 +477,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 */ @@ -493,7 +493,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); @@ -515,7 +515,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); @@ -786,7 +786,8 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) { /* ** Shift left operation. (Shift right just negates 'y'.) */ -#define luaV_shiftr(x,y) luaV_shiftl(x,-(y)) +#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y)) + lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { if (y < 0) { /* shift right? */ @@ -867,10 +868,19 @@ void luaV_finishOp (lua_State *L) { luaV_concat(L, total); /* concat them (may yield again) */ break; } - case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */ + case OP_CLOSE: { /* yielded closing variables */ ci->u.l.savedpc--; /* repeat instruction to close other vars. */ break; } + case OP_RETURN: { /* yielded closing variables */ + StkId ra = base + GETARG_A(inst); + /* adjust top to signal correct number of returns, in case the + return is "up to top" ('isIT') */ + L->top = ra + ci->u2.nres; + /* repeat instruction to close other vars. and complete the return */ + ci->u.l.savedpc--; + break; + } default: { /* only these other opcodes can yield */ lua_assert(op == OP_TFORCALL || op == OP_CALL || @@ -1119,7 +1129,7 @@ void luaV_finishOp (lua_State *L) { #define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) /* -** Protect code that can only raise errors. (That is, it cannnot change +** Protect code that can only raise errors. (That is, it cannot change ** the stack or hooks.) */ #define halfProtect(exp) (savestate(L,ci), (exp)) @@ -1176,8 +1186,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { Instruction i; /* instruction being executed */ StkId ra; /* instruction's A register */ vmfetch(); -// low-level line tracing for debugging Lua -// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); + #if 0 + /* low-level line tracing for debugging Lua */ + printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); + #endif lua_assert(base == ci->func + 1); lua_assert(base <= L->top && L->top < L->stack_last); /* invalidate top for instructions not expecting it */ @@ -1645,13 +1657,13 @@ 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; /* call re-uses 'luaV_execute' */ goto startfunc; } vmbreak; } 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; @@ -1665,23 +1677,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? */ - 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 */ + 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 */ } - 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 */ @@ -1690,6 +1693,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { n = cast_int(L->top - ra); /* get what is available */ savepc(ci); if (TESTARG_k(i)) { /* may there be open upvalues? */ + ci->u2.nres = n; /* save number of returns */ if (L->top < ci->top) L->top = ci->top; luaF_close(L, base, CLOSEKTOP, 1); diff --git a/third_party/lua/lzio.c b/third_party/lua/lzio.c index 4a617cd8f..b0c975bef 100644 --- a/third_party/lua/lzio.c +++ b/third_party/lua/lzio.c @@ -39,8 +39,8 @@ // clang-format off asm(".ident\t\"\\n\\n\ -Lua 5.4.3 (MIT License)\\n\ -Copyright 1994–2021 Lua.org, PUC-Rio.\""); +Lua 5.4.4 (MIT License)\\n\ +Copyright 1994–2022 Lua.org, PUC-Rio.\""); asm(".include \"libc/disclaimer.inc\""); diff --git a/third_party/lua/test/api.lua b/third_party/lua/test/api.lua index b9b4312da..6e3426d25 100644 --- a/third_party/lua/test/api.lua +++ b/third_party/lua/test/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/third_party/lua/test/bitwise.lua b/third_party/lua/test/bitwise.lua index 426ecce18..cee029017 100644 --- a/third_party/lua/test/bitwise.lua +++ b/third_party/lua/test/bitwise.lua @@ -45,6 +45,11 @@ assert(-1 >> numbits == 0 and -1 << numbits == 0 and -1 << -numbits == 0) +assert(1 >> math.mininteger == 0) +assert(1 >> math.maxinteger == 0) +assert(1 << math.mininteger == 0) +assert(1 << math.maxinteger == 0) + assert((2^30 - 1) << 2^30 == 0) assert((2^30 - 1) >> 2^30 == 0) diff --git a/third_party/lua/test/code.lua b/third_party/lua/test/code.lua index 8cff521df..fd4cec704 100644 --- a/third_party/lua/test/code.lua +++ b/third_party/lua/test/code.lua @@ -69,6 +69,20 @@ foo = function (f, a) checkKlist(foo, {100000, 100000.0, -100000, -100000.0}) +-- floats x integers +foo = function (t, a) + t[a] = 1; t[a] = 1.0 + t[a] = 1; t[a] = 1.0 + t[a] = 2; t[a] = 2.0 + t[a] = 0; t[a] = 0.0 + t[a] = 1; t[a] = 1.0 + t[a] = 2; t[a] = 2.0 + t[a] = 0; t[a] = 0.0 +end + +checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0}) + + -- testing opcodes -- check that 'f' opcodes match '...' diff --git a/third_party/lua/test/coroutine.lua b/third_party/lua/test/coroutine.lua index fd8b04041..ccb4888ac 100644 --- a/third_party/lua/test/coroutine.lua +++ b/third_party/lua/test/coroutine.lua @@ -136,6 +136,10 @@ do assert(coroutine.status(co) == "dead") local st, msg = coroutine.close(co) assert(st and msg == nil) + -- also ok to close it again + st, msg = coroutine.close(co) + assert(st and msg == nil) + -- cannot close the running coroutine local st, msg = pcall(coroutine.close, coroutine.running()) @@ -149,6 +153,22 @@ do assert(not st and string.find(msg, "normal")) end))() + -- cannot close a coroutine while closing it + do + local co + co = coroutine.create( + function() + local x = func2close(function() + coroutine.close(co) -- try to close it again + end) + coroutine.yield(20) + end) + local st, msg = coroutine.resume(co) + assert(st and msg == 20) + st, msg = coroutine.close(co) + assert(not st and string.find(msg, "running coroutine")) + end + -- to-be-closed variables in coroutines local X @@ -158,6 +178,9 @@ do assert(not st and msg == 100) st, msg = coroutine.close(co) assert(not st and msg == 100) + -- after closing, no more errors + st, msg = coroutine.close(co) + assert(st and msg == nil) co = coroutine.create(function () local x = func2close(function (self, err) @@ -189,6 +212,9 @@ do local st, msg = coroutine.close(co) assert(st == false and coroutine.status(co) == "dead" and msg == 200) assert(x == 200) + -- after closing, no more errors + st, msg = coroutine.close(co) + assert(st and msg == nil) end do @@ -205,7 +231,7 @@ do co = coroutine.create(function () return pcall(foo) end) local st1, st2, err = coroutine.resume(co) assert(st1 and not st2 and err == 43) - assert(X == 43 and Y.name == "pcall") + assert(X == 43 and Y.what == "C") -- recovering from errors in __close metamethods local track = {} @@ -419,7 +445,7 @@ do local X = false A = coroutine.wrap(function() - local _ = setmetatable({}, {__close = function () X = true end}) + local _ = func2close(function () X = true end) return pcall(A, 1) end) st, res = A() @@ -427,6 +453,22 @@ do end +-- bug in 5.4.1 +do + -- coroutine ran close metamethods with invalid status during a + -- reset. + local co + co = coroutine.wrap(function() + local x = func2close(function() return pcall(co) end) + error(111) + end) + local st, errobj = pcall(co) + assert(not st and errobj == 111) + st, errobj = pcall(co) + assert(not st and string.find(errobj, "dead coroutine")) +end + + -- attempt to resume 'normal' coroutine local co1, co2 co1 = coroutine.create(function () return co2() end) diff --git a/third_party/lua/test/cstack.lua b/third_party/lua/test/cstack.lua index b0f653c79..95c55ab53 100644 --- a/third_party/lua/test/cstack.lua +++ b/third_party/lua/test/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/third_party/lua/test/db.lua b/third_party/lua/test/db.lua index cf375ffd5..a025913da 100644 --- a/third_party/lua/test/db.lua +++ b/third_party/lua/test/db.lua @@ -195,6 +195,49 @@ do -- testing line info/trace with large gaps in source end end + +do -- testing active lines + local function checkactivelines (f, lines) + local t = debug.getinfo(f, "SL") + for _, l in pairs(lines) do + l = l + t.linedefined + assert(t.activelines[l]) + t.activelines[l] = undef + end + assert(next(t.activelines) == nil) -- no extra lines + end + + checkactivelines(function (...) -- vararg function + -- 1st line is empty + -- 2nd line is empty + -- 3th line is empty + local a = 20 + -- 5th line is empty + local b = 30 + -- 7th line is empty + end, {4, 6, 8}) + + checkactivelines(function (a) + -- 1st line is empty + -- 2nd line is empty + local a = 20 + local b = 30 + -- 5th line is empty + end, {3, 4, 6}) + + checkactivelines(function (a, b, ...) end, {0}) + + checkactivelines(function (a, b) + end, {1}) + + for _, n in pairs{0, 1, 2, 10, 50, 100, 1000, 10000} do + checkactivelines( + load(string.format("%s return 1", string.rep("\n", n))), + {n + 1}) + end + +end + print'+' -- invalid levels in [gs]etlocal @@ -844,7 +887,7 @@ do -- testing debug info for finalizers -- create a piece of garbage with a finalizer setmetatable({}, {__gc = function () - local t = debug.getinfo(2) -- get callee information + local t = debug.getinfo(1) -- get function information assert(t.namewhat == "metamethod") name = t.name end}) diff --git a/third_party/lua/test/errors.lua b/third_party/lua/test/errors.lua index b1d1b137d..48f7e6ec2 100644 --- a/third_party/lua/test/errors.lua +++ b/third_party/lua/test/errors.lua @@ -26,7 +26,7 @@ end local function checkmessage (prog, msg, debug) local m = doit(prog) - if debug then print(m) end + if debug then print(m, msg) end assert(string.find(m, msg, 1, true)) end @@ -228,6 +228,22 @@ do -- named objects (field '__name') checkmessage("return {} < XX", "table with My Type") checkmessage("return XX < io.stdin", "My Type with FILE*") _G.XX = nil + + if T then -- extra tests for 'luaL_tolstring' + -- bug in 5.4.3; 'luaL_tolstring' with negative indices + local x = setmetatable({}, {__name="TABLE"}) + assert(T.testC("Ltolstring -1; return 1", x) == tostring(x)) + + local a, b = T.testC("pushint 10; Ltolstring -2; return 2", x) + assert(a == 10 and b == tostring(x)) + + setmetatable(x, {__tostring=function (o) + assert(o == x) + return "ABC" + end}) + local a, b, c = T.testC("pushint 10; Ltolstring -2; return 3", x) + assert(a == x and b == 10 and c == "ABC") + end end -- global functions @@ -289,7 +305,7 @@ end]], "global 'insert'") checkmessage([[ -- tail call return math.sin("a") -]], "'sin'") +]], "sin") checkmessage([[collectgarbage("nooption")]], "invalid option") diff --git a/third_party/lua/test/files.lua b/third_party/lua/test/files.lua index 01159d9f9..9dcff4fa7 100644 --- a/third_party/lua/test/files.lua +++ b/third_party/lua/test/files.lua @@ -610,6 +610,7 @@ do assert(os.remove(file)) end + io.output(file) assert(io.write("qualquer coisa\n")) assert(io.write("mais qualquer coisa")) @@ -743,7 +744,7 @@ if not _port then {"exit 129", "exit", 129}, {"kill -s HUP $$", "signal", 1}, {"kill -s KILL $$", "signal", 9}, - {"sh -c 'kill -s HUP $$'", "signal", 1}, + {"sh -c 'kill -s HUP $$'", "signal", 1}, -- [jart] {progname .. ' -e " "', "ok"}, {progname .. ' -e "os.exit(0, true)"', "ok"}, {progname .. ' -e "os.exit(20, true)"', "exit", 20}, diff --git a/third_party/lua/test/gc.lua b/third_party/lua/test/gc.lua index f6eb7c9f0..f15c18260 100644 --- a/third_party/lua/test/gc.lua +++ b/third_party/lua/test/gc.lua @@ -371,7 +371,7 @@ if T then warn("@on"); warn("@store") collectgarbage() - assert(string.find(_WARN, "error in __gc metamethod")) + assert(string.find(_WARN, "error in __gc")) assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = false for i = 8, 10 do assert(s[i]) end @@ -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/third_party/lua/test/literals.lua b/third_party/lua/test/literals.lua index 4e368292c..7bbfeb49d 100644 --- a/third_party/lua/test/literals.lua +++ b/third_party/lua/test/literals.lua @@ -208,6 +208,30 @@ a = nil b = nil +do -- reuse of long strings + + -- get the address of a string + local function getadd (s) return string.format("%p", s) end + + local s1 = "01234567890123456789012345678901234567890123456789" + local s2 = "01234567890123456789012345678901234567890123456789" + local s3 = "01234567890123456789012345678901234567890123456789" + local function foo() return s1 end + local function foo1() return s3 end + local function foo2() + return "01234567890123456789012345678901234567890123456789" + end + local a1 = getadd(s1) + assert(a1 == getadd(s2)) + assert(a1 == getadd(foo())) + assert(a1 == getadd(foo1())) + assert(a1 == getadd(foo2())) + + local sd = "0123456789" .. "0123456789012345678901234567890123456789" + assert(sd == s1 and getadd(sd) ~= a1) +end + + -- testing line ends prog = [[ a = 1 -- a comment diff --git a/third_party/lua/test/locals.lua b/third_party/lua/test/locals.lua index 2af78913d..d0ccf0466 100644 --- a/third_party/lua/test/locals.lua +++ b/third_party/lua/test/locals.lua @@ -187,6 +187,8 @@ do -- constants checkro("y", "local x, y , z = 10, 20, 30; x = 11; y = 12") checkro("x", "local x , y, z = 10, 20, 30; x = 11") checkro("z", "local x , y, z = 10, 20, 30; y = 10; z = 11") + checkro("foo", "local foo = 10; function foo() end") + checkro("foo", "local foo = {}; function foo() end") checkro("z", [[ local a, z , b = 10; @@ -335,6 +337,29 @@ do end +do + -- bug in 5.4.3: previous condition (calls cannot be tail in the + -- scope of to-be-closed variables) must be valid for tbc variables + -- created by 'for' loops. + + local closed = false + + local function foo () + return function () return true end, 0, 0, + func2close(function () closed = true end) + end + + local function tail() return closed end + + local function foo1 () + for k in foo() do return tail() end + end + + assert(foo1() == false) + assert(closed == true) +end + + do print("testing errors in __close") -- original error is in __close @@ -790,6 +815,65 @@ do end +do + -- yielding inside closing metamethods while returning + -- (bug in 5.4.3) + + local extrares -- result from extra yield (if any) + + local function check (body, extra, ...) + local t = table.pack(...) -- expected returns + local co = coroutine.wrap(body) + if extra then + extrares = co() -- runs until first (extra) yield + end + local res = table.pack(co()) -- runs until yield inside '__close' + assert(res.n == 2 and res[2] == nil) + local res2 = table.pack(co()) -- runs until end of function + assert(res2.n == t.n) + for i = 1, #t do + if t[i] == "x" then + assert(res2[i] == res[1]) -- value that was closed + else + assert(res2[i] == t[i]) + end + end + end + + local function foo () + local x = func2close(coroutine.yield) + local extra = func2close(function (self) + assert(self == extrares) + coroutine.yield(100) + end) + extrares = extra + return table.unpack{10, x, 30} + end + check(foo, true, 10, "x", 30) + assert(extrares == 100) + + local function foo () + local x = func2close(coroutine.yield) + return + end + check(foo, false) + + local function foo () + local x = func2close(coroutine.yield) + local y, z = 20, 30 + return x + end + check(foo, false, "x") + + local function foo () + local x = func2close(coroutine.yield) + local extra = func2close(coroutine.yield) + return table.unpack({}, 1, 100) -- 100 nils + end + check(foo, true, table.unpack({}, 1, 100)) + +end + do -- yielding inside closing metamethods after an error diff --git a/third_party/lua/test/main.lua b/third_party/lua/test/main.lua index 1fa8c0fb5..83e403aaa 100644 --- a/third_party/lua/test/main.lua +++ b/third_party/lua/test/main.lua @@ -190,6 +190,11 @@ prepfile(("print(a); print(_G['%s'].x)"):format(prog), otherprog) RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out) checkout("1\n2\n15\n2\n15\n") +-- test explicit global names in -l +prepfile("print(str.upper'alo alo', m.max(10, 20))") +RUN("lua -l 'str=string' '-lm=math' -e 'print(m.sin(0))' %s > %s", prog, out) +checkout("0.0\nALO ALO\t20\n") + -- test 'arg' table local a = [[ assert(#arg == 3 and arg[1] == 'a' and @@ -256,6 +261,34 @@ u2 = setmetatable({}, {__gc = function () error("ZYX") end}) RUN('lua -W %s 2> %s', prog, out) checkprogout("ZYX)\nXYZ)\n") +-- bug since 5.2: finalizer called when closing a state could +-- subvert finalization order +prepfile[[ +-- should be called last +print("creating 1") +setmetatable({}, {__gc = function () print(1) end}) + +print("creating 2") +setmetatable({}, {__gc = function () + print("2") + print("creating 3") + -- this finalizer should not be called, as object will be + -- created after 'lua_close' has been called + setmetatable({}, {__gc = function () print(3) end}) + print(collectgarbage()) -- cannot call collector here + os.exit(0, true) +end}) +]] +RUN('lua -W %s > %s', prog, out) +checkout[[ +creating 1 +creating 2 +2 +creating 3 +nil +1 +]] + -- test many arguments prepfile[[print(({...})[30])]] diff --git a/third_party/lua/test/math.lua b/third_party/lua/test/math.lua index d8954b6c4..0e468a6d6 100644 --- a/third_party/lua/test/math.lua +++ b/third_party/lua/test/math.lua @@ -849,6 +849,7 @@ do math.randomseed(x, y) -- again should repeat the state assert(math.random(0) == res) -- keep the random seed for following tests + print(string.format("random seeds: %d, %d", x, y)) end do -- test random for floats diff --git a/third_party/lua/test/nextvar.lua b/third_party/lua/test/nextvar.lua index 8b39dc6f1..0d06d6bbc 100644 --- a/third_party/lua/test/nextvar.lua +++ b/third_party/lua/test/nextvar.lua @@ -43,6 +43,14 @@ assert(i == 4) assert(type(ipairs{}) == 'function' and ipairs{} == ipairs{}) +do -- overflow (must wrap-around) + local f = ipairs{} + local k, v = f({[math.mininteger] = 10}, math.maxinteger) + assert(k == math.mininteger and v == 10) + k, v = f({[math.mininteger] = 10}, k) + assert(k == nil) +end + if not T then (Message or print) ('\n >>> testC not active: skipping tests for table sizes <<<\n') @@ -499,6 +507,15 @@ do -- testing table library with metamethods end +do -- testing overflow in table.insert (must wrap-around) + + local t = setmetatable({}, + {__len = function () return math.maxinteger end}) + table.insert(t, 20) + local k, v = next(t) + assert(k == math.mininteger and v == 20) +end + if not T then (Message or print) ('\n >>> testC not active: skipping tests for table library on non-tables <<<\n') @@ -764,4 +781,25 @@ for k,v in ipairs(a) do end assert(i == a.n) + +-- testing yield inside __pairs +do + local t = setmetatable({10, 20, 30}, {__pairs = function (t) + local inc = coroutine.yield() + return function (t, i) + if i > 1 then return i - inc, t[i - inc] else return nil end + end, t, #t + 1 + end}) + + local res = {} + local co = coroutine.wrap(function () + for i,p in pairs(t) do res[#res + 1] = p end + end) + + co() -- start coroutine + co(1) -- continue after yield + assert(res[1] == 30 and res[2] == 20 and res[3] == 10 and #res == 3) + +end + print"OK" diff --git a/third_party/lua/test/strings.lua b/third_party/lua/test/strings.lua index f2012143c..a86b0507c 100644 --- a/third_party/lua/test/strings.lua +++ b/third_party/lua/test/strings.lua @@ -202,13 +202,11 @@ assert(string.format("\0%c\0%c%x\0", string.byte("\xe4"), string.byte("b"), 140) "\0\xe4\0b8c\0") assert(string.format('') == "") assert(string.format("%c",34)..string.format("%c",48)..string.format("%c",90)..string.format("%c",100) == - string.format("%c%c%c%c", 34, 48, 90, 100)) + string.format("%1c%-c%-1c%c", 34, 48, 90, 100)) assert(string.format("%s\0 is not \0%s", 'not be', 'be') == 'not be\0 is not \0be') assert(string.format("%%%d %010d", 10, 23) == "%10 0000000023") assert(tonumber(string.format("%f", 10.3)) == 10.3) -x = string.format('"%-50s"', 'a') -assert(#x == 52) -assert(string.sub(x, 1, 4) == '"a ') +assert(string.format('"%-50s"', 'a') == '"a' .. string.rep(' ', 49) .. '"') assert(string.format("-%.20s.20s", string.rep("%", 2000)) == "-"..string.rep("%", 20)..".20s") @@ -237,7 +235,6 @@ end assert(string.format("\0%s\0", "\0\0\1") == "\0\0\0\1\0") checkerror("contains zeros", string.format, "%10s", "\0") -checkerror("cannot have modifiers", string.format, "%10q", "1") -- format x tostring assert(string.format("%s %s", nil, true) == "nil true") @@ -341,6 +338,21 @@ do print("testing 'format %a %A'") end +-- testing some flags (all these results are required by ISO C) +assert(string.format("%#12o", 10) == " 012") +assert(string.format("%#10x", 100) == " 0x64") +assert(string.format("%#-17X", 100) == "0X64 ") +assert(string.format("%013i", -100) == "-000000000100") +assert(string.format("%2.5d", -100) == "-00100") +assert(string.format("%.u", 0) == "") +assert(string.format("%+#014.0f", 100) == "+000000000100.") +assert(string.format("% 1.0E", 100) == " 1E+02") +assert(string.format("%-16c", 97) == "a ") +assert(string.format("%+.3G", 1.5) == "+1.5") +assert(string.format("% .1g", 2^10) == " 1e+03") +assert(string.format("%.0s", "alo") == "") +assert(string.format("%.s", "alo") == "") + -- errors in format local function check (fmt, msg) @@ -348,13 +360,21 @@ local function check (fmt, msg) end local aux = string.rep('0', 600) -check("%100.3d", "too long") +check("%100.3d", "invalid conversion") check("%1"..aux..".3d", "too long") -check("%1.100d", "too long") +check("%1.100d", "invalid conversion") check("%10.1"..aux.."004d", "too long") check("%t", "invalid conversion") -check("%"..aux.."d", "repeated flags") +check("%"..aux.."d", "too long") check("%d %d", "no value") +check("%010c", "invalid conversion") +check("%.10c", "invalid conversion") +check("%0.34s", "invalid conversion") +check("%#i", "invalid conversion") +check("%3.1p", "invalid conversion") +check("%0.s", "invalid conversion") +check("%10q", "cannot have modifiers") +check("%F", "invalid conversion") -- useless and not in C89 assert(load("return 1\n--comment without ending EOL")() == 1) diff --git a/third_party/lua/test/utf8.lua b/third_party/lua/test/utf8.lua index 07896608f..c195e6bce 100644 --- a/third_party/lua/test/utf8.lua +++ b/third_party/lua/test/utf8.lua @@ -112,6 +112,12 @@ do end errorcodes("ab\xff") errorcodes("\u{110000}") + + -- calling interation function with invalid arguments + local f = utf8.codes("") + assert(f("", 2) == nil) + assert(f("", -1) == nil) + assert(f("", math.mininteger) == nil) end -- error in initial position for offset