1
0
mirror of https://github.com/lua/lua synced 2026-06-08 15:34:49 +00:00

Compare commits

...

34 Commits

Author SHA1 Message Date
Roberto I 40b76de2d7 Removed unused function 'luaD_inctop'
Commit 3228a97 removed all its uses.
2026-06-03 11:58:39 -03:00
Roberto I 0465c23b3e Cleaning 'luaP_isIT' and 'luaP_isOT'
- 'luaP_isOT' is only used for tests, so it is defined as a macro to avoid
wasting space with an unused function.
- 'luaP_isIT' must include OP_VARARGPREP.
2026-05-28 15:10:17 -03:00
Roberto I 53b41d0cdd Avoid warning in some compilers
In function 'funcargs', some compilers can complain that 'args' can be
used unitialized, due to the default case (syntax error).
2026-05-08 15:01:59 -03:00
Roberto I 36c1f6d949 Small correction in luaP_opmodes
OP_VARARGPREP neither sets nor uses L->top.
2026-04-29 15:17:55 -03:00
Roberto Ierusalimschy 0da6d320f7 Details 2026-04-28 13:44:29 -03:00
Roberto I ae23e72601 new macro 'setnilvalue2s' 2026-04-23 18:00:23 -03:00
Roberto I 4c5d5063a5 'load' reader function doesn't need to preserve stack 2026-04-23 17:58:55 -03:00
Roberto I 3228a97c6a Bug: 'lua_load' does not preserve the stack
'lua_load' does not preserve the stack through the calls to the
reader function, as it should. Immediately after the first call (to
detect whether chunk is binary) it adds stuff, and it also adds a new
table when starting the compilation of each new function.
2026-04-23 17:57:42 -03:00
Roberto I 0c16a42d61 Details
Added compiler option LUA_NODEBUGLIB to make Lua with no open debug
library + small improvements in the manual.
2026-04-21 15:27:22 -03:00
Roberto I d0bd25d2e7 Better error messages for vararg-table fields 2026-04-13 14:06:23 -03:00
Roberto I 29cf284089 Avoid macros luaL_loadbuffer and luaL_loadfile
Use luaL_loadbufferx and luaL_loadfilex instead, being explicit about
whether to accept binary chunks.
2026-04-07 13:42:34 -03:00
Roberto I c037162a1a Stricter test for use of '__builtin_expect'
GCC introduced this macro in version 3.
2026-04-01 15:09:07 -03:00
Roberto Ierusalimschy efddc2309c Bug: wrong initialization in result from 'gmatch'
Function returned by 'string.gmatch' can be left in an inconsistent
state after an error.
2026-04-01 15:01:58 -03:00
Roberto I f1bb2773bb Bug: Loading a binary chunk does not run the GC 2026-04-01 14:59:41 -03:00
Roberto I 51269bd783 Adjustment in useless parameter L in macros luai_num* 2026-03-15 15:14:14 -03:00
Roberto I 377cbea61b 'table.tunpack' using 'aux_getn' like the others
'table.tunpack' was not checking its first argument, which could
result in error messages generated inside the API, without location
information.
2026-03-09 16:24:49 -03:00
Roberto I 36d5d2b284 Details 2026-03-09 16:24:06 -03:00
Roberto I 9e501d9855 Slightly better documentation for LUAI_MAXALIGN 2026-03-09 16:23:03 -03:00
Roberto I 10eb89d114 BUG: shift overflow in utf-8 decode
An initial byte \xFF will ask for 7 continuation bytes, and then the
shift by (count * 5) will try to shift 35 bits.
2026-02-18 13:24:04 -03:00
Roberto Ierusalimschy 7c40c5edb2 Details
Spaces + added initialization to the documentation of global
declarations.
2026-02-10 16:41:02 -03:00
Roberto Ierusalimschy b60e2bcd7c Avoid an assignment of values that overlap
The original code was like this, where t->u.ind.t and t->u.info overlap:

  t->u.ind.t = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info);
2026-02-09 13:44:27 -03:00
Roberto I c6b4848238 Environment variable for readline library name
The name of the readline library can be changed from its default value
through environment variable LUA_READLINELIB.
2026-01-30 16:47:33 -03:00
Roberto I efbc297545 New year and (eventual) new release 2026-01-29 14:24:25 -03:00
Roberto I cfcaa9493b Explanation about char* parameters in the C API 2026-01-23 16:25:18 -03:00
Roberto I 3360710bd3 Another way to handle option -E
A pointer to function 'l_getenv' can point to the regular 'getenv' or
to a dumb function (that always returns NULL) to ignore environment
variables.
2026-01-22 13:47:10 -03:00
Roberto Ierusalimschy e992c6a959 Some compilation options configurable from makefile
Compilation options LUA_COMPAT_GLOBAL, LUA_COMPAT_LOOPVAR, and
LUA_READLINELIB do not affect the API, so they can be changed
through the make file.
2026-01-20 13:06:16 -03:00
Roberto I f5d1e8639b New compile option LUA_COMPAT_LOOPVAR
When on, this option makes for-loop control variables not read only.
2026-01-16 16:38:44 -03:00
Roberto I 2a7cf4f319 More effort in avoiding errors in finalizers
Before calling a finalizer, Lua not only checks stack limits, but
actually ensures that a minimum number of slots are already allocated
for the call. (If it cannot ensure that, it postpones the finalizer.)
That avoids finalizers not running due to memory errors that the
programmer cannot control.
2026-01-11 15:36:03 -03:00
Roberto I 5cfc725a8b Special case for 'string.rep' over an empty string 2026-01-04 16:39:22 -03:00
Roberto I 45c7ae5b1b BUG: Possible overflow in 'string.packsize'
'string.packsize' can overflow result in 32-bit machines using 64-bit
integers, as LUA_MAXINTEGER may not fit into size_t.
2026-01-04 16:31:17 -03:00
Roberto I 962f444a75 Details
In an assignment like 'a = &b', is looks suspicious if 'a' has a scope
larger than 'b'.
2026-01-04 16:27:54 -03:00
Roberto I c4e2c91973 Details
Some comments still talked about bit 'isrealasize', which has been
removed.
2025-12-30 10:50:49 -03:00
Roberto I 632a71b24d BUG: Arithmetic overflow in 'collectgarbage"step"'
The computation of a new debt could overflow when we give a too large
step to 'collectgarbage"step"' and the current debt was already
negative. This is only an issue if your platform cares for it or if you
compile Lua with an option like '-fsanitize=undefined'.
2025-12-27 16:22:13 -03:00
Roberto I 578ae5745c Details
typo in comment + formatting + logical 'and' was written as a bitwise
operation (makes code more fragile)
2025-12-23 14:44:06 -03:00
46 changed files with 533 additions and 230 deletions
+15 -9
View File
@@ -187,7 +187,7 @@ LUA_API void lua_settop (lua_State *L, int idx) {
api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--)
setnilvalue(s2v(L->top.p++)); /* clear new slots */
setnilvalue2s(L->top.p++); /* clear new slots */
}
else {
api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
@@ -210,7 +210,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
api_check(L, (L->ci->callstatus & CIST_TBC) && (L->tbclist.p == level),
"no variable to close at given level");
level = luaF_close(L, level, CLOSEKTOP, 0);
setnilvalue(s2v(level));
setnilvalue2s(level);
lua_unlock(L);
}
@@ -366,7 +366,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
}
LUA_API unsigned (lua_numbertocstring) (lua_State *L, int idx, char *buff) {
LUA_API unsigned lua_numbertocstring (lua_State *L, int idx, char *buff) {
const TValue *o = index2value(L, idx);
if (ttisnumber(o)) {
unsigned len = luaO_tostringbuff(o, buff);
@@ -513,7 +513,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L);
setnilvalue(s2v(L->top.p));
setnilvalue2s(L->top.p);
api_incr_top(L);
lua_unlock(L);
}
@@ -570,7 +570,7 @@ LUA_API const char *lua_pushexternalstring (lua_State *L,
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L);
if (s == NULL)
setnilvalue(s2v(L->top.p));
setnilvalue2s(L->top.p);
else {
TString *ts;
ts = luaS_new(L, s);
@@ -743,7 +743,7 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
static int finishrawget (lua_State *L, lu_byte tag) {
if (tagisempty(tag)) /* avoid copying empty items to the stack */
setnilvalue(s2v(L->top.p));
setnilvalue2s(L->top.p);
api_incr_top(L);
lua_unlock(L);
return novariant(tag);
@@ -836,7 +836,7 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) {
setnilvalue(s2v(L->top.p));
setnilvalue2s(L->top.p);
t = LUA_TNONE;
}
else {
@@ -1122,6 +1122,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
ZIO z;
TStatus status;
lua_lock(L);
luaC_checkGC(L);
if (!chunkname) chunkname = "?";
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode);
@@ -1201,11 +1202,16 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
case LUA_GCSTEP: {
lu_byte oldstp = g->gcstp;
l_mem n = cast(l_mem, va_arg(argp, size_t));
l_mem newdebt;
int work = 0; /* true if GC did some work */
g->gcstp = 0; /* allow GC to run (other bits must be zero here) */
if (n <= 0)
n = g->GCdebt; /* force to run one basic step */
luaE_setdebt(g, g->GCdebt - n);
newdebt = 0; /* force to run one basic step */
else if (g->GCdebt >= n - MAX_LMEM) /* no overflow? */
newdebt = g->GCdebt - n;
else /* overflow */
newdebt = -MAX_LMEM; /* set debt to miminum value */
luaE_setdebt(g, newdebt);
luaC_condGC(L, (void)0, work = 1);
if (work && g->gcstate == GCSpause) /* end of cycle? */
res = 1; /* signal it */
+1 -1
View File
@@ -874,7 +874,7 @@ LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
return luaL_loadbuffer(L, s, strlen(s), s);
return luaL_loadbufferx(L, s, strlen(s), s, "t");
}
/* }====================================================== */
+3 -3
View File
@@ -81,8 +81,8 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
LUALIB_API void *luaL_alloc (void *ud, void *ptr, size_t osize,
size_t nsize);
LUALIB_API void *(luaL_alloc) (void *ud, void *ptr, size_t osize,
size_t nsize);
/* predefined references */
@@ -103,7 +103,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API unsigned luaL_makeseed (lua_State *L);
LUALIB_API unsigned (luaL_makeseed) (lua_State *L);
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
+14 -21
View File
@@ -340,9 +340,11 @@ static int load_aux (lua_State *L, int status, int envidx) {
static const char *getMode (lua_State *L, int idx) {
const char *mode = luaL_optstring(L, idx, "bt");
if (strchr(mode, 'B') != NULL) /* Lua code cannot use fixed buffers */
const char *mode = luaL_optstring(L, idx, NULL);
if (mode != NULL && strchr(mode, 'B') != NULL) {
/* Lua code cannot use fixed buffers */
luaL_argerror(L, idx, "invalid mode");
}
return mode;
}
@@ -364,33 +366,24 @@ static int luaB_loadfile (lua_State *L) {
/*
** reserved slot, above all arguments, to hold a copy of the returned
** string to avoid it being collected while parsed. 'load' has four
** optional arguments (chunk, source name, mode, and environment).
*/
#define RESERVEDSLOT 5
/*
** Reader for generic 'load' function: 'lua_load' uses the
** stack for internal stuff, so the reader cannot change the
** stack top. Instead, it keeps its resulting string in a
** reserved slot inside the stack.
** Reader for generic 'load' function.
*/
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
(void)(ud); /* not used */
int *firstcall = cast(int *, ud);
luaL_checkstack(L, 2, "too many nested functions");
if (*firstcall)
*firstcall = 0;
else
lua_pop(L, 1); /* remove previous result */
lua_pushvalue(L, 1); /* get function */
lua_call(L, 0, 1); /* call it */
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop result */
*size = 0;
return NULL;
}
else if (l_unlikely(!lua_isstring(L, -1)))
luaL_error(L, "reader function must return a string");
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
return lua_tolstring(L, RESERVEDSLOT, size);
return lua_tolstring(L, -1, size);
}
@@ -405,10 +398,10 @@ static int luaB_load (lua_State *L) {
status = luaL_loadbufferx(L, s, l, chunkname, mode);
}
else { /* loading from a reader function */
int firstcall = 1; /* userdata for generic_reader */
const char *chunkname = luaL_optstring(L, 2, "=(load)");
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
status = lua_load(L, generic_reader, NULL, chunkname, mode);
status = lua_load(L, generic_reader, &firstcall, chunkname, mode);
}
return load_aux(L, status, env);
}
@@ -425,7 +418,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
lua_settop(L, 1);
if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
if (l_unlikely(luaL_loadfilex(L, fname, "bt") != LUA_OK))
return lua_error(L);
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
return dofilecont(L, 0, 0);
+9 -10
View File
@@ -663,11 +663,11 @@ static int boolT (FuncState *fs) {
** Add nil to list of constants and return its index.
*/
static int nilK (FuncState *fs) {
TValue k, v;
setnilvalue(&v);
lua_State *L = fs->ls->L;
TValue k;
/* cannot use nil as key; instead use table itself */
sethvalue(fs->ls->L, &k, fs->kcache);
return k2proto(fs, &k, &v);
sethvalue(L, &k, fs->kcache);
return k2proto(fs, &k, &G(L)->nilvalue);
}
@@ -827,7 +827,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
} /* FALLTHROUGH */
case VLOCAL: { /* already in a register */
int temp = e->u.var.ridx;
e->u.info = temp; /* (can't do a direct assignment; values overlap) */
e->u.info = temp; /* (avoid a direct assignment; values overlap) */
e->k = VNONRELOC; /* becomes a non-relocatable value */
break;
}
@@ -1365,7 +1365,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
luaK_exp2anyreg(fs, t); /* put it in a register */
if (t->k == VUPVAL) {
lu_byte temp = cast_byte(t->u.info); /* upvalue index */
t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
t->u.ind.t = temp; /* (avoid a direct assignment; values overlap) */
lua_assert(isKstr(fs, k));
fillidxk(t, k->u.info, VINDEXUP); /* literal short string */
}
@@ -1373,12 +1373,13 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
int kreg = luaK_exp2anyreg(fs, k); /* put key in some register */
lu_byte vreg = cast_byte(t->u.var.ridx); /* register with vararg param. */
lua_assert(vreg == fs->f->numparams);
t->u.ind.t = vreg; /* (avoid a direct assignment; values may overlap) */
t->u.ind.t = vreg; /* (avoid a direct assignment; values may overlap?) */
fillidxk(t, kreg, VVARGIND); /* 't' represents 'vararg[k]' */
}
else {
/* register index of the table */
t->u.ind.t = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info);
lu_byte temp = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info);
t->u.ind.t = temp; /* (avoid a direct assignment; values may overlap?) */
if (isKstr(fs, k))
fillidxk(t, k->u.info, VINDEXSTR); /* literal short string */
else if (isCint(k)) /* int. constant in proper range? */
@@ -1933,8 +1934,6 @@ void luaK_finish (FuncState *fs) {
p->flag &= cast_byte(~PF_VAHID); /* then it will not use hidden args. */
for (i = 0; i < fs->pc; i++) {
Instruction *pc = &p->code[i];
/* avoid "not used" warnings when assert is off (for 'onelua.c') */
(void)luaP_isOT; (void)luaP_isIT;
lua_assert(i == 0 || luaP_isOT(*(pc - 1)) == luaP_isIT(*pc));
switch (GET_OPCODE(*pc)) {
case OP_RETURN0: case OP_RETURN1: {
+1 -1
View File
@@ -427,7 +427,7 @@ static int db_debug (lua_State *L) {
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
if (luaL_loadbufferx(L, buffer, strlen(buffer), "=(debug command)", "t") ||
lua_pcall(L, 0, 0, 0))
lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
lua_settop(L, 0); /* remove eventual returns */
+2 -2
View File
@@ -291,7 +291,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) {
if (!LuaClosure(f)) {
setnilvalue(s2v(L->top.p));
setnilvalue2s(L->top.p);
api_incr_top(L);
}
else {
@@ -580,7 +580,7 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
kname(p, k, name);
return isEnv(p, lastpc, i, 1);
}
case OP_GETTABLE: {
case OP_GETTABLE: case OP_GETVARG: {
int k = GETARG_C(i); /* key index */
rname(p, lastpc, k, name);
return isEnv(p, lastpc, i, 0);
+48 -20
View File
@@ -221,13 +221,21 @@ l_noret luaD_errerr (lua_State *L) {
/*
** Check whether stack has enough space to run a simple function (such
** as a finalizer): At least BASIC_STACK_SIZE in the Lua stack and
** 2 slots in the C stack.
** Check whether stacks have enough space to run a simple function (such
** as a finalizer): At least BASIC_STACK_SIZE in the Lua stack, two
** available CallInfos, and two "slots" in the C stack.
*/
int luaD_checkminstack (lua_State *L) {
return ((stacksize(L) < MAXSTACK - BASIC_STACK_SIZE) &&
(getCcalls(L) < LUAI_MAXCCALLS - 2));
if (getCcalls(L) >= LUAI_MAXCCALLS - 2)
return 0; /* not enough C-stack slots */
if (L->ci->next == NULL && luaE_extendCI(L, 0) == NULL)
return 0; /* unable to allocate first ci */
if (L->ci->next->next == NULL && luaE_extendCI(L, 0) == NULL)
return 0; /* unable to allocate second ci */
if (L->stack_last.p - L->top.p >= BASIC_STACK_SIZE)
return 1; /* enough (BASIC_STACK_SIZE) free slots in the Lua stack */
else /* try to grow stack to a size with enough free slots */
return luaD_growstack(L, BASIC_STACK_SIZE, 0);
}
@@ -341,7 +349,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
correctstack(L, oldstack); /* change offsets back to pointers */
L->stack_last.p = L->stack.p + newsize;
for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */
setnilvalue2s(newstack + i); /* erase new segment */
return 1;
}
@@ -422,12 +430,6 @@ void luaD_shrinkstack (lua_State *L) {
luaE_shrinkCI(L); /* shrink CI list */
}
void luaD_inctop (lua_State *L) {
L->top.p++;
luaD_checkstack(L, 1);
}
/* }================================================================== */
@@ -546,7 +548,7 @@ l_sinline void genmoveresults (lua_State *L, StkId res, int nres,
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i));
setnilvalue2s(res + i);
L->top.p = res + wanted; /* top points after the last result */
}
@@ -566,7 +568,7 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres,
return;
case 1 + 1: /* one value needed */
if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */
setnilvalue2s(res); /* adjust with nil */
else /* at least one result */
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
L->top.p = res + 1;
@@ -616,7 +618,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L))
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L, 1))
/*
@@ -686,7 +688,7 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
setobjs2s(L, ci->func.p + i, func + i);
func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
setnilvalue2s(func + narg1); /* complete missing arguments */
ci->top.p = func + 1 + fsize; /* top for new function */
lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */
@@ -733,7 +735,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
L->ci = ci = prepCallInfo(L, func, status, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
setnilvalue2s(L->top.p++); /* complete missing arguments */
lua_assert(ci->top.p <= L->stack_last.p);
return ci;
}
@@ -1120,28 +1122,54 @@ static void checkmode (lua_State *L, const char *mode, const char *x) {
}
/*
** Before the first call to the reader function, Lua reserves a slot
** with a table for anchoring stuff.
*/
static void f_parser (lua_State *L, void *ud) {
LClosure *cl;
struct SParser *p = cast(struct SParser *, ud);
const char *mode = p->mode ? p->mode : "bt";
int c = zgetc(p->z); /* read first character */
int c;
Table *anchor;
ptrdiff_t otop = savestack(L, L->top.p); /* original top */
luaD_checkstack(L, 2);
anchor = luaH_new(L); /* create the anchor table */
sethvalue2s(L, L->top.p++, anchor); /* anchor the anchor table */
c = zgetc(p->z); /* read first character */
if (c == LUA_SIGNATURE[0]) {
int fixed = 0;
if (strchr(mode, 'B') != NULL)
fixed = 1;
else
checkmode(L, mode, "binary");
cl = luaU_undump(L, p->z, p->name, fixed);
cl = luaU_undump(L, p->z, anchor, p->name, fixed);
}
else {
checkmode(L, mode, "text");
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
cl = luaY_parser(L, p->z, anchor, &p->buff, &p->dyd, p->name, c);
}
L->top.p = restorestack(L, otop); /* restore stack */
setclLvalue2s(L, L->top.p++, cl); /* push closure */
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
luaF_initupvals(L, cl);
}
/*
** Anchor an object in a table in the stack. First, anchor the object
** temporarily in the stack, as luaH_set may call an emergency GC.
** Then, add it in the table with itself as its key.
*/
void luaD_anchorobj (lua_State *L, Table *anchor, GCObject *obj) {
setgcovalue(L, s2v(L->top.p++), obj); /* temporary anchor in the stack */
luaH_set(L, anchor, s2v(L->top.p - 1), s2v(L->top.p - 1));
/* Because this is a new key, luaH_set will call the GC barrier, so
we don't need to call the barrier again here */
L->top.p--;
}
TStatus luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode) {
struct SParser p;
+1 -1
View File
@@ -88,8 +88,8 @@ LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC int luaD_checkminstack (lua_State *L);
LUAI_FUNC void luaD_anchorobj (lua_State *L, Table *anchor, GCObject *obj);
LUAI_FUNC l_noret luaD_throw (lua_State *L, TStatus errcode);
LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode);
+3 -3
View File
@@ -709,7 +709,7 @@ static l_mem traversethread (global_State *g, lua_State *th) {
if (!g->gcemergency)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */
setnilvalue2s(o); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
th->twups = g->twups; /* link it back to the list */
@@ -1293,7 +1293,7 @@ static void finishgencycle (lua_State *L, global_State *g) {
correctgraylists(g);
checkSizes(L, g);
g->gcstate = GCSpropagate; /* skip restart */
if (!g->gcemergency && luaD_checkminstack(L))
if (g->tobefnz != NULL && !g->gcemergency && luaD_checkminstack(L))
callallpendingfinalizers(L);
}
@@ -1672,7 +1672,7 @@ static l_mem singlestep (lua_State *L, int fast) {
GCTM(L); /* call one finalizer */
stepresult = CWUFIN;
}
else { /* no more finalizers or emergency mode or no enough stack
else { /* no more finalizers or emergency mode or not enough stack
to run finalizers */
g->gcstate = GCSpause; /* finish collection */
stepresult = step2pause;
+1 -1
View File
@@ -188,7 +188,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
so they cannot be collected */
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env string */
ls->brkn = luaS_newliteral(L, "break"); /* get "break" string */
#if defined(LUA_COMPAT_GLOBAL)
#if LUA_COMPAT_GLOBAL
/* compatibility mode: "global" is not a reserved word */
ls->glbn = luaS_newliteral(L, "global"); /* get "global" string */
ls->glbn->extra = 0; /* mark it as not reserved */
+6 -6
View File
@@ -234,12 +234,12 @@ typedef unsigned long l_uint32;
/* floor division (defined as 'floor(a/b)') */
#if !defined(luai_numidiv)
#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
#define luai_numidiv(L,a,b) l_floor(luai_numdiv(L,a,b))
#endif
/* float division */
#if !defined(luai_numdiv)
#define luai_numdiv(L,a,b) ((a)/(b))
#define luai_numdiv(L,a,b) ((void)L, (a)/(b))
#endif
/*
@@ -267,10 +267,10 @@ typedef unsigned long l_uint32;
/* the others are quite standard operations */
#if !defined(luai_numadd)
#define luai_numadd(L,a,b) ((a)+(b))
#define luai_numsub(L,a,b) ((a)-(b))
#define luai_nummul(L,a,b) ((a)*(b))
#define luai_numunm(L,a) (-(a))
#define luai_numadd(L,a,b) ((void)L, (a)+(b))
#define luai_numsub(L,a,b) ((void)L, (a)-(b))
#define luai_nummul(L,a,b) ((void)L, (a)*(b))
#define luai_numunm(L,a) ((void)L, -(a))
#define luai_numeq(a,b) ((a)==(b))
#define luai_numlt(a,b) ((a)<(b))
#define luai_numle(a,b) ((a)<=(b))
+1 -1
View File
@@ -541,7 +541,7 @@ static int searcher_Lua (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
filename = findfile(L, name, "path", LUA_LSUBSEP);
if (filename == NULL) return 1; /* module not found in this path */
return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);
return checkload(L, (luaL_loadfilex(L, filename, "bt") == LUA_OK), filename);
}
+2 -1
View File
@@ -208,7 +208,8 @@ typedef union {
#define ttisstrictnil(o) checktag((o), LUA_VNIL)
#define setnilvalue(obj) settt_(obj, LUA_VNIL)
#define setnilvalue(obj) settt_(obj, LUA_VNIL)
#define setnilvalue2s(stk) setnilvalue(s2v(stk))
#define isabstkey(v) checktag((v), LUA_VABSTKEY)
+8 -17
View File
@@ -104,35 +104,26 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETVARG */
,opmode(0, 0, 0, 0, 0, iABx) /* OP_ERRNNIL */
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_VARARGPREP */
,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
};
/*
** Check whether instruction sets top for next instruction, that is,
** it results in multiple values.
*/
int luaP_isOT (Instruction i) {
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_TAILCALL: return 1;
default:
return testOTMode(op) && GETARG_C(i) == 0;
}
}
#define testITMode(m) (luaP_opmodes[m] & (1 << 5))
/*
** Check whether instruction uses top from previous instruction, that is,
** it accepts multiple results.
** Check whether instruction uses top. That happens for OP_VARARGPREP
** and for instructions that use multiple values set by the previous
** instruction.
*/
int luaP_isIT (Instruction i) {
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_SETLIST:
return testITMode(GET_OPCODE(i)) && GETARG_vB(i) == 0;
return GETARG_vB(i) == 0;
case OP_VARARGPREP:
return 1;
default:
return testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0;
}
+10 -5
View File
@@ -417,8 +417,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
** bits 0-2: op mode
** bit 3: instruction set register A
** bit 4: operator is a test (next instruction must be a jump)
** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0)
** bit 6: instruction sets 'L->top' for next instruction (when C == 0)
** bit 5: used by 'luaP_isIT'
** bit 6: used by 'luaP_isOT'
** bit 7: instruction is an MM instruction (call a metamethod)
*/
@@ -427,12 +427,17 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7))
#define testAMode(m) (luaP_opmodes[m] & (1 << 3))
#define testTMode(m) (luaP_opmodes[m] & (1 << 4))
#define testITMode(m) (luaP_opmodes[m] & (1 << 5))
#define testOTMode(m) (luaP_opmodes[m] & (1 << 6))
#define testMMMode(m) (luaP_opmodes[m] & (1 << 7))
LUAI_FUNC int luaP_isOT (Instruction i);
/* Check whether instruction sets top for next instruction, that is,
** it results in multiple values. Used only for tests.
*/
#define luaP_isOT(i) \
(GET_OPCODE(i) == OP_TAILCALL || \
((luaP_opmodes[GET_OPCODE(i)] & (1 << 6)) && GETARG_C(i) == 0))
LUAI_FUNC int luaP_isIT (Instruction i);
+24 -15
View File
@@ -821,8 +821,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
luaC_objbarrier(L, f, f->source);
f->maxstacksize = 2; /* registers 0/1 are always valid */
fs->kcache = luaH_new(L); /* create table for function */
sethvalue2s(L, L->top.p, fs->kcache); /* anchor it */
luaD_inctop(L);
luaD_anchorobj(L, ls->h, obj2gco(fs->kcache)); /* anchor it */
enterblock(fs, bl, 0);
}
@@ -831,6 +830,7 @@ static void close_func (LexState *ls) {
lua_State *L = ls->L;
FuncState *fs = ls->fs;
Proto *f = fs->f;
TValue temp;
luaK_ret(fs, luaY_nvarstack(fs), 0); /* final return */
leaveblock(fs);
lua_assert(fs->bl == NULL);
@@ -843,8 +843,10 @@ static void close_func (LexState *ls) {
luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *);
luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar);
luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
/* remove kcache table from scanner table ("weigh" its anchor) */
sethvalue(L, &temp, fs->kcache); /* key to be set to nil */
luaH_set(L, ls->h, &temp, &G(L)->nilvalue);
ls->fs = fs->prev;
L->top.p--; /* pop kcache table */
luaC_checkGC(L);
}
@@ -1164,6 +1166,7 @@ static void funcargs (LexState *ls, expdesc *f) {
}
default: {
luaX_syntaxerror(ls, "function arguments expected");
return; /* to avoid warnings */
}
}
lua_assert(f->k == VNONRELOC);
@@ -1682,13 +1685,22 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isgen) {
}
/*
** Control whether for-loop control variables are read-only
*/
#if LUA_COMPAT_LOOPVAR
#define LOOPVARKIND VDKREG
#else /* by default, these variables are read only */
#define LOOPVARKIND RDKCONST
#endif
static void fornum (LexState *ls, TString *varname, int line) {
/* fornum -> NAME = exp,exp[,exp] forbody */
FuncState *fs = ls->fs;
int base = fs->freereg;
new_localvarliteral(ls, "(for state)");
new_localvarliteral(ls, "(for state)");
new_varkind(ls, varname, RDKCONST); /* control variable */
new_varkind(ls, varname, LOOPVARKIND); /* control variable */
checknext(ls, '=');
exp1(ls); /* initial value */
checknext(ls, ',');
@@ -1715,7 +1727,7 @@ static void forlist (LexState *ls, TString *indexname) {
new_localvarliteral(ls, "(for state)"); /* iterator function */
new_localvarliteral(ls, "(for state)"); /* state */
new_localvarliteral(ls, "(for state)"); /* closing var. (after swap) */
new_varkind(ls, indexname, RDKCONST); /* control variable */
new_varkind(ls, indexname, LOOPVARKIND); /* control variable */
/* other declared variables */
while (testnext(ls, ',')) {
new_localvar(ls, str_checkname(ls));
@@ -2111,7 +2123,7 @@ static void statement (LexState *ls) {
gotostat(ls, line);
break;
}
#if defined(LUA_COMPAT_GLOBAL)
#if LUA_COMPAT_GLOBAL
case TK_NAME: {
/* compatibility code to parse global keyword when "global"
is not reserved */
@@ -2165,16 +2177,14 @@ static void mainfunc (LexState *ls, FuncState *fs) {
}
LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor, Mbuffer *buff,
Dyndata *dyd, const char *name, int firstchar) {
LexState lexstate;
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L);
LClosure *cl;
lexstate.h = anchor; /* table for scanner */
cl = luaF_newLclosure(L, 1); /* create main closure */
luaD_anchorobj(L, anchor, obj2gco(cl)); /* anchor it in scanner table */
funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
@@ -2187,7 +2197,6 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */
return cl;
}
+3 -2
View File
@@ -189,8 +189,9 @@ typedef struct FuncState {
LUAI_FUNC lu_byte luaY_nvarstack (FuncState *fs);
LUAI_FUNC void luaY_checklimit (FuncState *fs, int v, int l,
const char *what);
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
Dyndata *dyd, const char *name, int firstchar);
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor,
Mbuffer *buff, Dyndata *dyd,
const char *name, int firstchar);
#endif
+13 -8
View File
@@ -68,14 +68,19 @@ void luaE_setdebt (global_State *g, l_mem debt) {
}
CallInfo *luaE_extendCI (lua_State *L) {
CallInfo *luaE_extendCI (lua_State *L, int err) {
CallInfo *ci;
lua_assert(L->ci->next == NULL);
ci = luaM_new(L, CallInfo);
lua_assert(L->ci->next == NULL);
L->ci->next = ci;
ci = luaM_reallocvector(L, NULL, 0, 1, CallInfo);
if (l_unlikely(ci == NULL)) { /* allocation failed? */
if (err)
luaM_error(L); /* raise the error */
return NULL; /* else only report it */
}
ci->next = L->ci->next;
ci->previous = L->ci;
ci->next = NULL;
L->ci->next = ci;
if (ci->next)
ci->next->previous = ci;
ci->u.l.trap = 0;
L->nci++;
return ci;
@@ -146,7 +151,7 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void resetCI (lua_State *L) {
CallInfo *ci = L->ci = &L->base_ci;
ci->func.p = L->stack.p;
setnilvalue(s2v(ci->func.p)); /* 'function' entry for basic 'ci' */
setnilvalue2s(ci->func.p); /* 'function' entry for basic 'ci' */
ci->top.p = ci->func.p + 1 + LUA_MINSTACK; /* +1 for 'function' entry */
ci->u.c.k = NULL;
ci->callstatus = CIST_C;
@@ -161,7 +166,7 @@ static void stack_init (lua_State *L1, lua_State *L) {
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
setnilvalue2s(L1->stack.p + i); /* erase new stack */
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */
resetCI(L1);
+1 -1
View File
@@ -438,7 +438,7 @@ union GCUnion {
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
LUAI_FUNC lu_mem luaE_threadsize (lua_State *L);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L, int err);
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
LUAI_FUNC void luaE_checkcstack (lua_State *L);
LUAI_FUNC void luaE_incCstack (lua_State *L);
+12 -6
View File
@@ -141,8 +141,8 @@ static int str_rep (lua_State *L) {
const char *s = luaL_checklstring(L, 1, &len);
lua_Integer n = luaL_checkinteger(L, 2);
const char *sep = luaL_optlstring(L, 3, "", &lsep);
if (n <= 0)
lua_pushliteral(L, "");
if (n <= 0 || (len | lsep) == 0)
lua_pushliteral(L, ""); /* no repetitions or both strings empty */
else if (l_unlikely(len > MAX_SIZE - lsep ||
cast_st2S(len + lsep) > cast_st2S(MAX_SIZE) / n))
return luaL_error(L, "resulting string too large");
@@ -757,19 +757,25 @@ static int nospecials (const char *p, size_t l) {
}
/*
** Prepare state for matches. These fields are not affected by each match.
*/
static void prepstate (MatchState *ms, lua_State *L,
const char *s, size_t ls, const char *p, size_t lp) {
ms->L = L;
ms->matchdepth = MAXCCALLS;
ms->src_init = s;
ms->src_end = s + ls;
ms->p_end = p + lp;
}
/*
** (Re)prepare state for a match, setting fields that change during
** each match.
*/
static void reprepstate (MatchState *ms) {
ms->matchdepth = MAXCCALLS;
ms->level = 0;
lua_assert(ms->matchdepth == MAXCCALLS);
}
@@ -968,7 +974,7 @@ static int str_gsub (lua_State *L) {
reprepstate(&ms); /* (re)prepare state for new match */
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
n++;
changed = add_value(&ms, &b, src, e, tr) | changed;
changed = add_value(&ms, &b, src, e, tr) || changed;
src = lastmatch = e;
}
else if (src < ms.src_end) /* otherwise, skip one character */
@@ -1726,7 +1732,7 @@ static int str_packsize (lua_State *L) {
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
"variable-length format");
size += ntoalign; /* total space used by option */
luaL_argcheck(L, totalsize <= LUA_MAXINTEGER - size,
luaL_argcheck(L, totalsize <= MAX_SIZE - size,
1, "format result too large");
totalsize += size;
}
+8 -8
View File
@@ -651,10 +651,9 @@ static void reinserthash (lua_State *L, Table *ot, Table *t) {
/*
** Exchange the hash part of 't1' and 't2'. (In 'flags', only the
** dummy bit must be exchanged: The 'isrealasize' is not related
** to the hash part, and the metamethod bits do not change during
** a resize, so the "real" table can keep their values.)
** Exchange the hash part of 't1' and 't2'. (In 'flags', only the dummy
** bit must be exchanged: The metamethod bits do not change during a
** resize, so the "real" table can keep their values.)
*/
static void exchangehashpart (Table *t1, Table *t2) {
lu_byte lsizenode = t1->lsizenode;
@@ -1156,14 +1155,15 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key,
lua_assert(hres != HOK);
if (hres == HNOTFOUND) {
TValue aux;
const TValue *actk = key; /* actual key to insert */
if (l_unlikely(ttisnil(key)))
luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) {
lua_Number f = fltvalue(key);
lua_Integer k;
if (luaV_flttointeger(f, &k, F2Ieq)) {
setivalue(&aux, k); /* key is equal to an integer */
key = &aux; /* insert it as an integer */
if (luaV_flttointeger(f, &k, F2Ieq)) { /* is key equal to an integer? */
setivalue(&aux, k);
actk = &aux; /* use the integer as the key */
}
else if (l_unlikely(luai_numisnan(f)))
luaG_runerror(L, "table index is NaN");
@@ -1176,7 +1176,7 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key,
L->top.p--;
return;
}
luaH_newkey(L, t, key, value);
luaH_newkey(L, t, actk, value);
}
else if (hres > 0) { /* regular Node? */
setobj2t(L, gval(gnode(t, hres - HFIRSTNODE)), value);
+7 -4
View File
@@ -42,15 +42,17 @@ static int checkfield (lua_State *L, const char *key, int n) {
/*
** Check that 'arg' either is a table or can behave like one (that is,
** has a metatable with the required metamethods)
** has a metatable with the required metamethods).
*/
static void checktab (lua_State *L, int arg, int what) {
if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
int tp = lua_type(L, arg);
if (tp != LUA_TTABLE) { /* is it not a table? */
int n = 1; /* number of elements to pop */
if (lua_getmetatable(L, arg) && /* must have metatable */
(!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
(!(what & TAB_L) || checkfield(L, "__len", ++n))) {
(!(what & TAB_L) || /* strings don't need '__len' to have a length */
tp == LUA_TSTRING || checkfield(L, "__len", ++n))) {
lua_pop(L, n); /* pop metatable and tested metamethods */
}
else
@@ -204,8 +206,9 @@ static int tpack (lua_State *L) {
static int tunpack (lua_State *L) {
lua_Unsigned n;
lua_Integer len = aux_getn(L, 1, TAB_R);
lua_Integer i = luaL_optinteger(L, 2, 1);
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, len);
if (i > e) return 0; /* empty range */
n = l_castS2U(e) - l_castS2U(i); /* number of elements minus 1 */
if (l_unlikely(n >= (unsigned int)INT_MAX ||
+27 -4
View File
@@ -1106,6 +1106,27 @@ static int stacklevel (lua_State *L) {
}
static int resetCI (lua_State *L) {
CallInfo *ci = L->ci;
while (ci->next != NULL) {
CallInfo *tofree = ci->next;
ci->next = ci->next->next;
luaM_free(L, tofree);
L->nci--;
}
return 0;
}
static int reallocstack (lua_State *L) {
int n = cast_int(luaL_checkinteger(L, 1));
lua_lock(L);
luaD_reallocstack(L, cast_int(L->top.p - L->stack.p) + n, 1);
lua_unlock(L);
return 0;
}
static int table_query (lua_State *L) {
const Table *t;
int i = cast_int(luaL_optinteger(L, 2, -1));
@@ -1124,7 +1145,7 @@ static int table_query (lua_State *L) {
if (!tagisempty(*getArrTag(t, i)))
arr2obj(t, cast_uint(i), s2v(L->top.p));
else
setnilvalue(s2v(L->top.p));
setnilvalue2s(L->top.p);
api_incr_top(L);
lua_pushnil(L);
}
@@ -1281,7 +1302,7 @@ static int doonnewstack (lua_State *L) {
lua_State *L1 = lua_newthread(L);
size_t l;
const char *s = luaL_checklstring(L, 1, &l);
int status = luaL_loadbuffer(L1, s, l, s);
int status = luaL_loadbufferx(L1, s, l, s, "t");
if (status == LUA_OK)
status = lua_pcall(L1, 0, 0, 0);
lua_pushinteger(L, status);
@@ -1361,7 +1382,7 @@ static int doremote (lua_State *L) {
const char *code = luaL_checklstring(L, 2, &lcode);
int status;
lua_settop(L1, 0);
status = luaL_loadbuffer(L1, code, lcode, code);
status = luaL_loadbufferx(L1, code, lcode, code, "t");
if (status == LUA_OK)
status = lua_pcall(L1, 0, LUA_MULTRET, 0);
if (status != LUA_OK) {
@@ -1717,7 +1738,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
lua_pushinteger(L1, luaL_len(L1, getindex));
}
else if EQ("loadfile") {
luaL_loadfile(L1, luaL_checkstring(L1, getnum));
luaL_loadfilex(L1, luaL_checkstring(L1, getnum), "t");
}
else if EQ("loadstring") {
size_t slen;
@@ -2182,6 +2203,8 @@ static const struct luaL_Reg tests_funcs[] = {
{"s2d", s2d},
{"sethook", sethook},
{"stacklevel", stacklevel},
{"resetCI", resetCI},
{"reallocstack", reallocstack},
{"sizes", get_sizes},
{"testC", testC},
{"makeCfunc", makeCfunc},
+1
View File
@@ -14,6 +14,7 @@
/* test Lua with compatibility code */
#define LUA_COMPAT_MATHLIB
#undef LUA_COMPAT_GLOBAL
#define LUA_COMPAT_GLOBAL 0
#define LUA_DEBUG
+5 -5
View File
@@ -262,7 +262,7 @@ static void buildhiddenargs (lua_State *L, CallInfo *ci, const Proto *p,
/* move fixed parameters to after the copied function */
for (i = 1; i <= nfixparams; i++) {
setobjs2s(L, L->top.p++, ci->func.p + i);
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
setnilvalue2s(ci->func.p + i); /* erase original parameter (for GC) */
}
ci->func.p += totalargs + 1; /* 'func' now lives after hidden arguments */
ci->top.p += totalargs + 1;
@@ -283,7 +283,7 @@ void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
lua_assert(p->flag & PF_VAHID);
buildhiddenargs(L, ci, p, totalargs, nfixparams, nextra);
/* set vararg parameter to nil */
setnilvalue(s2v(ci->func.p + nfixparams + 1));
setnilvalue2s(ci->func.p + nfixparams + 1);
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
}
}
@@ -307,7 +307,7 @@ void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc) {
return;
}
}
setnilvalue(s2v(ra)); /* else produce nil */
setnilvalue2s(ra); /* else produce nil */
}
@@ -355,10 +355,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted,
for (i = 0; i < touse; i++) {
lu_byte tag = luaH_getint(h, i + 1, s2v(where + i));
if (tagisempty(tag))
setnilvalue(s2v(where + i));
setnilvalue2s(where + i);
}
}
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
setnilvalue2s(where + i);
}
+1 -1
View File
@@ -49,7 +49,7 @@ typedef enum {
** Mask with 1 in all fast-access methods. A 1 in any of these bits
** in the flag of a (meta)table means the metatable does not have the
** corresponding metamethod field. (Bit 6 of the flag indicates that
** the table is using the dummy node; bit 7 is used for 'isrealasize'.)
** the table is using the dummy node.)
*/
#define maskflags cast_byte(~(~0u << (TM_EQ + 1)))
+47 -19
View File
@@ -30,6 +30,12 @@
#define LUA_INIT_VAR "LUA_INIT"
#endif
/* Name of the environment variable with the name of the readline library */
#if !defined(LUA_RLLIB_VAR)
#define LUA_RLLIB_VAR "LUA_READLINELIB"
#endif
#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
@@ -201,12 +207,12 @@ static int dochunk (lua_State *L, int status) {
static int dofile (lua_State *L, const char *name) {
return dochunk(L, luaL_loadfile(L, name));
return dochunk(L, luaL_loadfilex(L, name, "bt"));
}
static int dostring (lua_State *L, const char *s, const char *name) {
return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name));
return dochunk(L, luaL_loadbufferx(L, s, strlen(s), name, "t"));
}
@@ -260,7 +266,7 @@ static int handle_script (lua_State *L, char **argv) {
const char *fname = argv[0];
if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
fname = NULL; /* stdin */
status = luaL_loadfile(L, fname);
status = luaL_loadfilex(L, fname, "bt");
if (status == LUA_OK) {
int n = pushargs(L); /* push arguments to script */
status = docall(L, n, LUA_MULTRET);
@@ -374,12 +380,21 @@ static int runargs (lua_State *L, char **argv, int n) {
}
static char *(*l_getenv)(const char *name);
/* Function to ignore environment variables, used by option -E */
static char *no_getenv (const char *name) {
UNUSED(name);
return NULL;
}
static int handle_luainit (lua_State *L) {
const char *name = "=" LUA_INITVARVERSION;
const char *init = getenv(name + 1);
const char *init = l_getenv(name + 1);
if (init == NULL) {
name = "=" LUA_INIT_VAR;
init = getenv(name + 1); /* try alternative name */
init = l_getenv(name + 1); /* try alternative name */
}
if (init == NULL) return LUA_OK;
else if (init[0] == '@')
@@ -498,18 +513,24 @@ static void lua_freeline (char *line) {
#include <dlfcn.h>
static void lua_initreadline (lua_State *L) {
void *lib = dlopen(LUA_READLINELIB, RTLD_NOW | RTLD_LOCAL);
if (lib == NULL)
lua_warning(L, "library '" LUA_READLINELIB "' not found", 0);
else {
const char *rllib = l_getenv(LUA_RLLIB_VAR); /* name of readline library */
void *lib; /* library handle */
if (rllib == NULL) /* no environment variable? */
rllib = LUA_READLINELIB; /* use default name */
lib = dlopen(rllib, RTLD_NOW | RTLD_LOCAL);
if (lib != NULL) {
const char **name = cast(const char**, dlsym(lib, "rl_readline_name"));
if (name != NULL)
*name = "lua";
l_readline = cast(l_readlineT, cast_func(dlsym(lib, "readline")));
l_addhist = cast(l_addhistT, cast_func(dlsym(lib, "add_history")));
if (l_readline == NULL)
lua_warning(L, "unable to load 'readline'", 0);
if (l_readline != NULL) /* could load readline function? */
return; /* everything ok */
/* else emit a warning */
}
lua_warning(L, "unable to load readline library '", 1);
lua_warning(L, rllib, 1);
lua_warning(L, "'", 0);
}
#else /* }{ */
@@ -588,11 +609,11 @@ static int pushline (lua_State *L, int firstline) {
static int addreturn (lua_State *L) {
const char *line = lua_tostring(L, -1); /* original line */
const char *retline = lua_pushfstring(L, "return %s;", line);
int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
int status = luaL_loadbufferx(L, retline, strlen(retline), "=stdin", "t");
if (status == LUA_OK)
lua_remove(L, -2); /* remove modified line */
else
lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
lua_pop(L, 2); /* pop result from 'luaL_loadbufferx' and modified line */
return status;
}
@@ -619,7 +640,7 @@ static int multiline (lua_State *L) {
const char *line = lua_tolstring(L, 1, &len); /* get first line */
checklocal(line);
for (;;) { /* repeat until gets a complete statement */
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
int status = luaL_loadbufferx(L, line, len, "=stdin", "t"); /* try it */
if (!incomplete(L, status) || !pushline(L, 0))
return status; /* should not or cannot try to add continuation line */
lua_remove(L, -2); /* remove error message (from incomplete line) */
@@ -693,7 +714,13 @@ static void doREPL (lua_State *L) {
/* }================================================================== */
#if !defined(luai_openlibs)
#define luai_openlibs(L) luaL_openselectedlibs(L, ~0, 0)
#if defined(LUA_NODEBUGLIB)
/* With this option, code must require the debug library before using it */
#define luai_openlibs(L) luaL_openselectedlibs(L, ~LUA_DBLIBK, LUA_DBLIBK)
#else
/* The default is to open all standard libraries */
#define luai_openlibs(L) luaL_openselectedlibs(L, ~0, 0)
#endif
#endif
@@ -715,17 +742,18 @@ static int pmain (lua_State *L) {
if (args & has_v) /* option '-v'? */
print_version();
if (args & has_E) { /* option '-E'? */
l_getenv = &no_getenv; /* program will ignore environment variables */
lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
}
else
l_getenv = &getenv;
luai_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCRESTART); /* start GC... */
lua_gc(L, LUA_GCGEN); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
}
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
if (!runargs(L, argv, optlim)) /* execute arguments -e, -l, and -W */
return 0; /* something failed */
if (script > 0) { /* execute main script (if there is one) */
+3 -3
View File
@@ -13,13 +13,13 @@
#include <stddef.h>
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2025 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2026 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
#define LUA_VERSION_MAJOR_N 5
#define LUA_VERSION_MINOR_N 5
#define LUA_VERSION_RELEASE_N 0
#define LUA_VERSION_RELEASE_N 1
#define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N)
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N)
@@ -521,7 +521,7 @@ struct lua_Debug {
/******************************************************************************
* Copyright (C) 1994-2025 Lua.org, PUC-Rio.
* Copyright (C) 1994-2026 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
+35 -13
View File
@@ -70,15 +70,19 @@
#if defined(LUA_USE_LINUX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
#if !defined(LUA_READLINELIB)
#define LUA_READLINELIB "libreadline.so"
#endif
#endif
#if defined(LUA_USE_MACOSX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* macOS does not need -ldl */
#if !defined(LUA_READLINELIB)
#define LUA_READLINELIB "libedit.dylib"
#endif
#endif
#if defined(LUA_USE_IOS)
@@ -224,17 +228,17 @@
#if !defined(LUA_PATH_DEFAULT)
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
LUA_LDIR "?.lua;" LUA_LDIR "?\\init.lua;" \
LUA_CDIR "?.lua;" LUA_CDIR "?\\init.lua;" \
LUA_SHRDIR "?.lua;" LUA_SHRDIR "?\\init.lua;" \
".\\?.lua;" ".\\?\\init.lua"
#endif
#if !defined(LUA_CPATH_DEFAULT)
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.dll;" \
LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
LUA_CDIR"loadall.dll;" ".\\?.dll"
LUA_CDIR "?.dll;" \
LUA_CDIR "..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
LUA_CDIR "loadall.dll;" ".\\?.dll"
#endif
#else /* }{ */
@@ -245,14 +249,14 @@
#if !defined(LUA_PATH_DEFAULT)
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
LUA_LDIR "?.lua;" LUA_LDIR "?/init.lua;" \
LUA_CDIR "?.lua;" LUA_CDIR "?/init.lua;" \
"./?.lua;" "./?/init.lua"
#endif
#if !defined(LUA_CPATH_DEFAULT)
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
LUA_CDIR "?.so;" LUA_CDIR "loadall.so;" "./?.so"
#endif
#endif /* } */
@@ -339,7 +343,18 @@
/*
@@ LUA_COMPAT_GLOBAL avoids 'global' being a reserved word
*/
#define LUA_COMPAT_GLOBAL
#if !defined(LUA_COMPAT_GLOBAL)
#define LUA_COMPAT_GLOBAL 1
#endif
/*
@@ LUA_COMPAT_LOOPVAR makes for-loop control variables not read-only,
** as they were in previous versions.
*/
#if !defined(LUA_COMPAT_LOOPVAR)
#define LUA_COMPAT_LOOPVAR 0
#endif
/*
@@ -649,7 +664,7 @@
*/
#if !defined(luai_likely)
#if defined(__GNUC__) && !defined(LUA_NOBUILTIN)
#if !defined(LUA_NOBUILTIN) && defined(__GNUC__) && (__GNUC__ >= 3)
#define luai_likely(x) (__builtin_expect(((x) != 0), 1))
#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0))
#else
@@ -721,10 +736,17 @@
/*
@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure
** maximum alignment for the other items in that union.
@@ LUAI_MAXALIGN defines fields that ensure proper alignment for
** memory areas offered by Lua (e.g., userdata memory).
** Add fields to it if you need alignment for non-ISO objects.
*/
#if defined(LLONG_MAX)
/* use ISO C99 stuff */
#define LUAI_MAXALIGN long double u; void *s; long long l
#else
/* use only C89 stuff */
#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l
#endif
/* }================================================================== */
+5 -8
View File
@@ -392,7 +392,8 @@ static void checkHeader (LoadState *S) {
/*
** Load precompiled chunk.
*/
LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
LClosure *luaU_undump (lua_State *L, ZIO *Z, Table *anchor, const char *name,
int fixed) {
LoadState S;
LClosure *cl;
if (*name == '@' || *name == '=')
@@ -405,20 +406,16 @@ LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
S.fixed = cast_byte(fixed);
S.offset = 1; /* fist byte was already read */
checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S));
setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L);
S.h = luaH_new(L); /* create list of saved strings */
S.h = anchor;
S.nstr = 0;
sethvalue2s(L, L->top.p, S.h); /* anchor it */
luaD_inctop(L);
cl = luaF_newLclosure(L, loadByte(&S));
luaD_anchorobj(L, anchor, obj2gco(cl));
cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
loadFunction(&S, cl->p);
if (cl->nupvalues != cl->p->sizeupvalues)
error(&S, "corrupted chunk");
luai_verifycode(L, cl->p);
L->top.p--; /* pop table */
return cl;
}
+2 -2
View File
@@ -30,8 +30,8 @@
/* load one chunk; from lundump.c */
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name,
int fixed);
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Table *anchor,
const char* name, int fixed);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
+5 -2
View File
@@ -56,6 +56,8 @@ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
l_uint32 res = 0; /* final result */
if (c < 0x80) /* ASCII? */
res = c;
else if (c >= 0xfe) /* c >= 1111 1110b ? */
return NULL; /* would need six or more continuation bytes */
else {
int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
@@ -64,8 +66,9 @@ static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
}
lua_assert(count <= 5);
res |= ((l_uint32)(c & 0x7F) << (count * 5)); /* add first byte */
if (count > 5 || res > MAXUTF || res < limits[count])
if (res > MAXUTF || res < limits[count])
return NULL; /* invalid byte sequence */
s += count; /* skip continuation bytes read */
}
@@ -146,7 +149,7 @@ static int codepoint (lua_State *L) {
static void pushutfchar (lua_State *L, int arg) {
lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg);
luaL_argcheck(L, code <= MAXUTF, arg, "value out of range");
lua_pushfstring(L, "%U", (long)code);
lua_pushfstring(L, "%U", cast(unsigned long, code));
}
+4 -4
View File
@@ -268,9 +268,9 @@ static int forprep (lua_State *L, StkId ra) {
/*
** Execute a step of a float numerical for loop, returning
** true iff the loop must continue. (The integer case is
** written online with opcode OP_FORLOOP, for performance.)
** written inline with opcode OP_FORLOOP, for performance.)
*/
static int floatforloop (StkId ra) {
static int floatforloop (lua_State *L, StkId ra) {
lua_Number step = fltvalue(s2v(ra + 1));
lua_Number limit = fltvalue(s2v(ra));
lua_Number idx = fltvalue(s2v(ra + 2)); /* control variable */
@@ -303,7 +303,7 @@ lu_byte luaV_finishget (lua_State *L, const TValue *t, TValue *key,
else { /* 't' is a table */
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
if (tm == NULL) { /* no metamethod? */
setnilvalue(s2v(val)); /* result is nil */
setnilvalue2s(val); /* result is nil */
return LUA_VNIL;
}
/* else will try the metamethod */
@@ -1841,7 +1841,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
pc -= GETARG_Bx(i); /* jump back */
}
}
else if (floatforloop(ra)) /* float loop */
else if (floatforloop(L, ra)) /* float loop */
pc -= GETARG_Bx(i); /* jump back */
updatetrap(ci); /* allows a signal to break the loop */
vmbreak;
+8 -3
View File
@@ -60,10 +60,13 @@ CWARNS= $(CWARNSCPP) $(CWARNSC) $(CWARNGCC)
# create problems; some are only available in newer gcc versions. To
# use some of them, we also have to define an environment variable
# ASAN_OPTIONS="detect_invalid_pointer_pairs=2".
# -fsanitize=undefined
# -fsanitize=undefined (you may need to add "-lubsan" to libs)
# -fsanitize=pointer-subtract -fsanitize=address -fsanitize=pointer-compare
# TESTS= -DLUA_USER_H='"ltests.h"' -Og -g
# Test mode: Add test library, turn on asserts, redefine several
# constants ("to give some bugs a chance"), track memory use, and add
# debug information.
# TESTS= -DLUA_USER_H='"ltests.h"' -Og -g
LOCAL = $(TESTS) $(CWARNS)
@@ -71,13 +74,15 @@ LOCAL = $(TESTS) $(CWARNS)
# To enable Linux goodies, -DLUA_USE_LINUX
# For C89, "-std=c89 -DLUA_USE_C89"
# Note that Linux/Posix options are not compatible with C89
# (For 32-bit, add option "-m32" to MYCFLAGS and MYLDFLAGS.)
MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX
MYLDFLAGS= -Wl,-E
MYLIBS= -ldl
CC= gcc
CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common -march=native
# (Optionally we can use -march=native -mno-avx512f.)
CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common
AR= ar rc
RANLIB= ranlib
RM= rm -f
+2 -2
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env lua5.3
#!/usr/bin/env lua
-- special marks:
@@ -30,7 +30,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p>
<small>
<a href="http://www.lua.org/copyright.html">Copyright</a>
&copy; 2025 Lua.org, PUC-Rio. All rights reserved.
&copy; 2026 Lua.org, PUC-Rio. All rights reserved.
</small>
<hr>
+40 -14
View File
@@ -2692,7 +2692,19 @@ which behaves like a nil value.
@sect3{constchar|@title{Pointers to Strings}
Several functions in the API return pointers (@T{const char*})
Several functions in the API accept pointers (@T{const char*})
to C strings.
Some of there parameters have an associated length (@T{size_t}).
Unless stated otherwise,
when there is an associated length,
the string can contain embedded zeros;
moreover, the pointer can be @id{NULL} if the length is zero.
When there is no associated length,
the pointer must point to a zero-terminated string.
In any case, the string contents should remain unchanged
until the function returns.
Several functions in the API also return pointers (@T{const char*})
to Lua strings in the stack.
(See @Lid{lua_pushfstring}, @Lid{lua_pushlstring},
@Lid{lua_pushstring}, and @Lid{lua_tolstring}.
@@ -3903,8 +3915,12 @@ like any Lua object.
This function creates and pushes on the stack a new full userdata,
with @id{nuvalue} associated Lua values, called @id{user values},
plus an associated block of raw memory with @id{size} bytes.
(The user values can be set and read with the functions
@Lid{lua_setiuservalue} and @Lid{lua_getiuservalue}.)
The user values can be set and read with the functions
@Lid{lua_setiuservalue} and @Lid{lua_getiuservalue}.
The block of memory is suitably aligned for any @N{ISO C} object.
(See macro @id{LUAI_MAXALIGN} in file @id{luaconf.h} for other
alignment requirements.)
The function returns the address of the block of memory.
Lua ensures that this address is valid as long as
@@ -3946,8 +3962,8 @@ this confuses the next call to @Lid{lua_next}.
This function may raise an error if the given key
is neither @nil nor present in the table.
See function @Lid{next} for the caveats of modifying
the table during its traversal.
See function @Lid{next} for more details about the traversal.
}
@@ -4432,7 +4448,7 @@ Starts and resumes a coroutine in the given thread @id{L}.
To start a coroutine,
you push the main function plus any arguments
onto the empty stack of the thread.
then you call @Lid{lua_resume},
Then you call @Lid{lua_resume},
with @id{nargs} being the number of arguments.
The function returns when the coroutine suspends,
finishes its execution, or raises an unprotected error.
@@ -4612,7 +4628,7 @@ You can resume threads with status @Lid{LUA_OK}
}
@APIEntry{size_t lua_stringtonumber (lua_State *L, const char *s);|
@apii{0,1,-}
@apii{0,0|1,-}
Converts the zero-terminated string @id{s} to a number,
pushes that number into the stack,
@@ -4942,7 +4958,7 @@ Lua calls the given @x{continuation function} @id{k} to continue
the execution of the @N{C function} that yielded @see{continuations}.
This continuation function receives the same stack
from the previous function,
with the @id{n} results removed and
with all the results (@id{nresults}) removed and
replaced by the arguments passed to @Lid{lua_resume}.
Moreover,
the continuation function receives the value @id{ctx}
@@ -5032,7 +5048,7 @@ the function was defined in a string where
}
@item{@id{srclen}|
The length of the string @id{source}.
the length of the string @id{source}.
}
@item{@id{short_src}|
@@ -5196,7 +5212,7 @@ running at the given level;
}
@item{@Char{S}|
fills in the fields @id{source}, @id{short_src},
fills in the fields @id{source}, @id{srclen}, @id{short_src},
@id{linedefined}, @id{lastlinedefined}, and @id{what};
}
@@ -5372,7 +5388,9 @@ Returns @id{NULL} (and pops nothing)
when the index is greater than
the number of active local variables.
Parameters @id{ar} and @id{n} are as in the function @Lid{lua_getlocal}.
Parameters @id{ar} and @id{n} are as in the function @Lid{lua_getlocal},
except that @id{ar} cannot be @id{NULL},
as @id{lua_setlocal} only operates on activation records.
}
@@ -6816,8 +6834,7 @@ for k,v in pairs(t) do @rep{body} end
}
will iterate over all key@En{}value pairs of table @id{t}.
See function @Lid{next} for the caveats of modifying
the table during its traversal.
See function @Lid{next} for more details about the traversal.
}
@@ -9107,6 +9124,7 @@ which automatically removes the file when the program ends.
This library provides
the functionality of the @link{debugI|debug interface} to Lua programs.
You should exert care when using this library.
Several of its functions
violate basic assumptions about Lua code
@@ -9116,6 +9134,8 @@ that userdata metatables cannot be changed by Lua code;
that Lua programs do not crash)
and therefore can compromise otherwise secure code.
Moreover, some functions in this library may be slow.
It is good practice to always require this library explicitly
before using it.
All functions in this library are provided
inside the @defid{debug} table.
@@ -9594,12 +9614,18 @@ change between versions.
@item{
The word @Rw{global} is a reserved word.
Do not use it as a regular name.
The compilation option @id{LUA_COMPAT_GLOBAL} (see @id{luaconf.h})
makes @id{global} a regular word.
}
@item{
The control variable in @Rw{for} loops is read only.
If you need to change it,
declare a local variable with the same name in the loop body.
The compilation option @id{LUA_COMPAT_LOOPVAR} (see @id{luaconf.h})
makes these variables regular (writable).
}
@item{
@@ -9725,7 +9751,7 @@ and @bnfNter{LiteralString}, see @See{lexical}.)
@OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody
@OrNL @Rw{global} @Rw{function} @bnfNter{Name} funcbody
@OrNL @Rw{local} attnamelist @bnfopt{@bnfter{=} explist}
@OrNL @Rw{global} attnamelist
@OrNL @Rw{global} attnamelist @bnfopt{@bnfter{=} explist}
@OrNL @Rw{global} @bnfopt{attrib} @bnfter{*}
}
+26
View File
@@ -372,6 +372,32 @@ do -- another bug (in 5.4.0)
end
if T then
-- check stack level when calling reader function
local function get (str)
local pos = 0
local level = nil
return function ()
pos = pos + 1
local c = string.sub(str, pos, pos)
local newlevel = T.stacklevel()
if not level then
level = newlevel
else
assert(level == newlevel)
end
return #c > 0 and c or nil
end
end
local str = "local function foo () end; return 121"
assert(assert(load(get(str)))() == 121)
str = string.dump(load(str))
assert(assert(load(get(str)))() == 121)
end
x = string.dump(load("x = 1; return x"))
a = assert(load(read1(x), nil, "b"))
assert(a() == 1 and _G.x == 1)
+3
View File
@@ -159,6 +159,9 @@ assert(not string.find(doit"aaa={13}; local bbbb=1; aaa[bbbb](3)", "'bbbb'"))
checkmessage("aaa={13}; local bbbb=1; aaa[bbbb](3)", "number")
checkmessage("aaa=(1)..{}", "a table value")
checkmessage("local function foo (...t) return t.xx + 1 end; foo()",
"field 'xx'")
-- bug in 5.4.6
checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'")
+42
View File
@@ -707,4 +707,46 @@ end
collectgarbage(oldmode)
if T then
print("testing stack issues when calling finalizers")
local X
local obj
local function initobj ()
X = false
obj = setmetatable({}, {__gc = function () X = true end})
end
local function loop (n)
if n > 0 then loop(n - 1) end
end
-- should not try to call finalizer without a CallInfo available
initobj()
loop(20) -- ensure stack space
T.resetCI() -- remove extra CallInfos
T.alloccount(0) -- cannot allocate more CallInfos
obj = nil
collectgarbage() -- will not call finalizer
T.alloccount()
assert(X == false)
collectgarbage() -- now will call finalizer (it was still pending)
assert(X == true)
-- should not try to call finalizer without stack space available
initobj()
loop(5) -- ensure enough CallInfos
T.reallocstack(0) -- remove extra stack slots
T.alloccount(0) -- cannot reallocate stack
obj = nil
collectgarbage() -- will not call finalizer
T.alloccount()
assert(X == false)
collectgarbage() -- now will call finalizer (it was still pending)
assert(X == true)
end
print('OK')
+22 -1
View File
@@ -78,6 +78,9 @@ end
RUN('lua -v')
RUN('lua -v > %s', out)
local release = string.match(getoutput(), "Lua (%d+%.%d+%.%d+)")
print(string.format("(temporary program file used in these tests: %s)", prog))
-- running stdin as a file
@@ -167,7 +170,9 @@ checkout("10\n11\n")
-- test errors in LUA_INIT
NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua')
-- test option '-E'
print("testing option '-E'")
local defaultpath, defaultCpath
do
@@ -192,6 +197,22 @@ assert(not string.find(defaultpath, "xxx") and
string.find(defaultCpath, "lua"))
-- (LUA_READLINELIB was introduced in 5.5.1)
if release >= "5.5.1" then
print"testing readline library name"
-- should generate a warning when trying to load inexistent library "xuxu"
local env = [[LUA_READLINELIB=xuxu LUA_INIT="warn('@allow')"]]
local code = 'echo " " | env %s lua %s -W -i >%s 2>&1'
RUN(code, env, "", out) -- run code with no extra options
assert(string.find(getoutput(),
"warning: unable to load readline library 'xuxu'"))
RUN(code, env, "-E", out) -- run again with option -E
-- no warning when LUA_READLINELIB is to be ignored
assert(not string.find(getoutput(), "warning"))
end
-- test replacement of ';;' to default path
local function convert (p)
prepfile("print(package.path)")
+19
View File
@@ -282,6 +282,25 @@ testamem("growing stack", function ()
return foo(100)
end)
collectgarbage()
collectgarbage()
global io, T, setmetatable, collectgarbage, print
local Count = 0
testamem("finalizers", function ()
local X = false
local obj = setmetatable({}, {__gc = function () X = true end})
obj = nil
T.resetCI() -- remove extra CallInfos
T.reallocstack(18) -- remove extra stack slots
Count = Count + 1
io.stderr:write(Count, "\n")
T.trick(io)
collectgarbage()
return X
end)
-- }==================================================================
+10
View File
@@ -347,6 +347,16 @@ do -- init parameter in gmatch
end
do -- bug since 5.3
local N = 20000
local iter = string.gmatch(string.rep("a", N), string.rep("a?", N))
pcall(iter) -- error for pattern too complex
-- calling function again found recursion count ('matchdepth') equal
-- to -1, so it did not detect next C-stack overflow
pcall(iter)
end
-- tests for `%f' (`frontiers')
assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x")
+13
View File
@@ -72,6 +72,19 @@ assert(a==1 and x==nil)
a,x = unpack({1,2}, 1, 1)
assert(a==1 and x==nil)
do -- unpack with non-tables
local debug = require"debug"
local oldmt = debug.getmetatable(0)
local str = "hello"
debug.setmetatable(0,
{ __len = function () return #str end,
__index = function (_, i) return string.sub(str, i, i) end})
assert(table.concat({table.unpack(0)}) == str)
debug.setmetatable(0, oldmt) -- restore original metatable for numbers
end
do
local maxi = (1 << 31) - 1 -- maximum value for an int (usually)
local mini = -(1 << 31) -- minimum value for an int (usually)
+7 -2
View File
@@ -1,10 +1,15 @@
-- track collections
local M = {}
-- import list
local setmetatable, stderr, collectgarbage =
setmetatable, io.stderr, collectgarbage
local stderr, collectgarbage = io.stderr, collectgarbage
-- the debug version of setmetatable does not create any object (such as
-- a '__metatable' string), and so it is more appropriate to be used in
-- a finalizer
local setmetatable = require"debug".setmetatable
global none
+13 -1
View File
@@ -238,10 +238,18 @@ s = "\0 \x7F\z
s = string.gsub(s, " ", "")
check(s, {0,0x7F, 0x80,0x7FF, 0x800,0xFFFF, 0x10000,0x10FFFF})
-- again, without strictness
s = "\xF0\x90\x80\x80 \xF7\xBF\xBF\xBF\z
\xF8\x88\x80\x80\x80 \xFB\xBF\xBF\xBF\xBF\z
\xFC\x84\x80\x80\x80\x80 \xFD\xBF\xBF\xBF\xBF\xBF"
s = string.gsub(s, " ", "")
check(s, {0x10000,0x1FFFFF, 0x200000,0x3FFFFFF, 0x4000000,0x7FFFFFFF}, true)
do
-- original UTF-8 values
local s = "\u{4000000}\u{7FFFFFFF}"
assert(#s == 12)
assert(s == "\xFC\x84\x80\x80\x80\x80\xFD\xBF\xBF\xBF\xBF\xBF")
check(s, {0x4000000, 0x7FFFFFFF}, true)
s = "\u{200000}\u{3FFFFFF}"
@@ -257,6 +265,10 @@ local x = "日本語a-4\0éó"
check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})
-- more than 5 continuation bytes
assert(not utf8.len("\xff\x8f\x8f\x8f\x8f\x8f\x8f\x8f"))
-- Supplementary Characters
check("𣲷𠜎𠱓𡁻𠵼ab𠺢",
{0x23CB7, 0x2070E, 0x20C53, 0x2107B, 0x20D7C, 0x61, 0x62, 0x20EA2,})