Compare commits

..

12 Commits
v5.4.8 ... v5.4

Author SHA1 Message Date
Roberto I
312b9efaa1 Small corrections in the manual 2026-08-07 15:59:21 -03:00
Roberto I
03aabbc636 New copyright year (2026) 2026-08-05 15:04:44 -03:00
Roberto I
2f8fe031c7 New release number (5.4.9) 2026-07-24 11:39:24 -03:00
Roberto I
f4f4968fd3 Bug: 'luaL_newmetatable' used in a wrong way
The call to 'luaL_newmetatable' in 'newbox' can leave an incomplete
metatable in the registry, if 'luaL_setfuncs' raises a memory error.
2026-07-24 11:38:45 -03:00
Roberto I
e282da498c Bug: wrong initialization in result from 'gmatch'
Function returned by 'string.gmatch' can be left in an inconsistent
state after an error.
2026-07-24 11:21:24 -03:00
Roberto I
b18086ea34 Bug: Loading a binary chunk does not run the GC 2026-07-24 11:16:38 -03:00
Roberto I
af19891bce 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-07-22 15:07:52 -03:00
Roberto I
8511e90b7d Bug: GC checks stack space before running finalizer
If some stack does not have a minimum available space, the GC defers
calling a finalizer until the next cycle. That avoids errors while
running a finalizer that the programmer cannot control.
2026-07-22 14:42:55 -03:00
Roberto I
0f781f836a Bug: Issues with write barrier for __newindex
In 'luaV_finishset', there is an update on a table that is a field on
another table. If the first table is the same as the one with the field
(e.g., after 't.__newindex = t'), the update can change the value on
that field (if the field being updated is '__newindex' itself). After
that, the barrier is called with the table stored in that field, which
is not the correct table anymore.
2026-07-13 15:55:36 -03:00
Roberto Ierusalimschy
934fdd481c Bug: Constructors with nils can overflow counters 2025-08-27 14:58:02 -03:00
Roberto Ierusalimschy
9ac9d23f41 Bug: error with option '--' without a script 2025-08-27 14:55:35 -03:00
Roberto Ierusalimschy
1b0f943da7 Bug: new metatable in weak table can fool the GC
All-weak tables are not being revisited after being visited during
propagation; if it gets a new metatable after that, the new metatable
may not be marked.
2025-06-16 16:33:02 -03:00
18 changed files with 117 additions and 41 deletions

1
lapi.c
View File

@@ -1089,6 +1089,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
ZIO z; ZIO z;
int status; int status;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
if (!chunkname) chunkname = "?"; if (!chunkname) chunkname = "?";
luaZ_init(L, &z, reader, data); luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode); status = luaD_protectedparser(L, &z, chunkname, mode);

View File

@@ -501,12 +501,25 @@ static const luaL_Reg boxmt[] = { /* box metamethods */
}; };
/*
** Get/create metatable (MT) for boxes
*/
static void getBoxMT (lua_State *L) {
const char *BOXMT = "_UBOX*"; /* key for the metatable */
if (luaL_getmetatable(L, BOXMT) == LUA_TNIL) { /* MT not created yet? */
luaL_newlibtable(L, boxmt); /* create it */
luaL_setfuncs(L, boxmt, 0); /* initialize it */
lua_copy(L, -1, -2); /* change stack from nil,MT to MT,MT */
lua_setfield(L, LUA_REGISTRYINDEX, BOXMT); /* store MT in the registry */
}
}
static void newbox (lua_State *L) { static void newbox (lua_State *L) {
UBox *box = (UBox *)lua_newuserdatauv(L, sizeof(UBox), 0); UBox *box = (UBox *)lua_newuserdatauv(L, sizeof(UBox), 0);
box->box = NULL; box->box = NULL;
box->bsize = 0; box->bsize = 0;
if (luaL_newmetatable(L, "_UBOX*")) /* creating metatable? */ getBoxMT(L);
luaL_setfuncs(L, boxmt, 0); /* set its metamethods */
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
} }

21
ldo.c
View File

@@ -205,6 +205,25 @@ l_noret luaD_errerr (lua_State *L) {
} }
/*
** 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) {
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);
}
/* /*
** Reallocate the stack to a new size, correcting all pointers into it. ** Reallocate the stack to a new size, correcting all pointers into it.
** In ISO C, any pointer use after the pointer has been deallocated is ** In ISO C, any pointer use after the pointer has been deallocated is
@@ -503,7 +522,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))
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,

1
ldo.h
View File

@@ -80,6 +80,7 @@ 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 int luaD_growstack (lua_State *L, int n, int raiseerror);
LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC void luaD_inctop (lua_State *L); LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC int luaD_checkminstack (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);

15
lgc.c
View File

@@ -553,8 +553,12 @@ static lu_mem traversetable (global_State *g, Table *h) {
traverseweakvalue(g, h); traverseweakvalue(g, h);
else if (!weakvalue) /* strong values? */ else if (!weakvalue) /* strong values? */
traverseephemeron(g, h, 0); traverseephemeron(g, h, 0);
else /* all weak */ else { /* all weak */
linkgclist(h, g->allweak); /* nothing to traverse now */ if (g->gcstate == GCSpropagate)
linkgclist(h, g->grayagain); /* must visit again its metatable */
else
linkgclist(h, g->allweak); /* must clear collected entries */
}
} }
else /* not weak */ else /* not weak */
traversestrongtable(g, h); traversestrongtable(g, h);
@@ -1238,7 +1242,7 @@ static void finishgencycle (lua_State *L, global_State *g) {
correctgraylists(g); correctgraylists(g);
checkSizes(L, g); checkSizes(L, g);
g->gcstate = GCSpropagate; /* skip restart */ g->gcstate = GCSpropagate; /* skip restart */
if (!g->gcemergency) if (g->tobefnz != NULL && !g->gcemergency && luaD_checkminstack(L))
callallpendingfinalizers(L); callallpendingfinalizers(L);
} }
@@ -1628,11 +1632,12 @@ static lu_mem singlestep (lua_State *L) {
break; break;
} }
case GCScallfin: { /* call remaining finalizers */ case GCScallfin: { /* call remaining finalizers */
if (g->tobefnz && !g->gcemergency) { if (g->tobefnz && !g->gcemergency && luaD_checkminstack(L)) {
g->gcstopem = 0; /* ok collections during finalizers */ g->gcstopem = 0; /* ok collections during finalizers */
work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST;
} }
else { /* emergency mode or no more finalizers */ else { /* no more finalizers or emergency mode or no enough stack
to run finalizers */
g->gcstate = GCSpause; /* finish collection */ g->gcstate = GCSpause; /* finish collection */
work = 0; work = 0;
} }

View File

@@ -940,6 +940,8 @@ static void constructor (LexState *ls, expdesc *t) {
if (ls->t.token == '}') break; if (ls->t.token == '}') break;
closelistfield(fs, &cc); closelistfield(fs, &cc);
field(ls, &cc); field(ls, &cc);
checklimit(fs, cc.tostore + cc.na + cc.nh, INT_MAX/2,
"items in a constructor");
} while (testnext(ls, ',') || testnext(ls, ';')); } while (testnext(ls, ',') || testnext(ls, ';'));
check_match(ls, '}', '{', line); check_match(ls, '}', '{', line);
lastlistfield(fs, &cc); lastlistfield(fs, &cc);

View File

@@ -102,14 +102,19 @@ LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
} }
CallInfo *luaE_extendCI (lua_State *L) { CallInfo *luaE_extendCI (lua_State *L, int err) {
CallInfo *ci; CallInfo *ci;
lua_assert(L->ci->next == NULL); ci = luaM_reallocvector(L, NULL, 0, 1, CallInfo);
ci = luaM_new(L, CallInfo); if (l_unlikely(ci == NULL)) { /* allocation failed? */
lua_assert(L->ci->next == NULL); if (err)
L->ci->next = ci; luaM_error(L); /* raise the error */
return NULL; /* else only report it */
}
ci->next = L->ci->next;
ci->previous = L->ci; ci->previous = L->ci;
ci->next = NULL; L->ci->next = ci;
if (ci->next)
ci->next->previous = ci;
ci->u.l.trap = 0; ci->u.l.trap = 0;
L->nci++; L->nci++;
return ci; return ci;

View File

@@ -395,7 +395,7 @@ union GCUnion {
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
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_shrinkCI (lua_State *L);
LUAI_FUNC void luaE_checkcstack (lua_State *L); LUAI_FUNC void luaE_checkcstack (lua_State *L);
LUAI_FUNC void luaE_incCstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L);

View File

@@ -757,7 +757,6 @@ static int nospecials (const char *p, size_t l) {
static void prepstate (MatchState *ms, lua_State *L, static void prepstate (MatchState *ms, lua_State *L,
const char *s, size_t ls, const char *p, size_t lp) { const char *s, size_t ls, const char *p, size_t lp) {
ms->L = L; ms->L = L;
ms->matchdepth = MAXCCALLS;
ms->src_init = s; ms->src_init = s;
ms->src_end = s + ls; ms->src_end = s + ls;
ms->p_end = p + lp; ms->p_end = p + lp;
@@ -765,8 +764,8 @@ static void prepstate (MatchState *ms, lua_State *L,
static void reprepstate (MatchState *ms) { static void reprepstate (MatchState *ms) {
ms->matchdepth = MAXCCALLS;
ms->level = 0; ms->level = 0;
lua_assert(ms->matchdepth == MAXCCALLS);
} }

3
lua.c
View File

@@ -302,7 +302,8 @@ static int collectargs (char **argv, int *first) {
case '-': /* '--' */ case '-': /* '--' */
if (argv[i][2] != '\0') /* extra characters after '--'? */ if (argv[i][2] != '\0') /* extra characters after '--'? */
return has_error; /* invalid option */ return has_error; /* invalid option */
*first = i + 1; /* if there is a script name, it comes after '--' */
*first = (argv[i + 1] != NULL) ? i + 1 : 0;
return args; return args;
case '\0': /* '-' */ case '\0': /* '-' */
return args; /* script "name" is '-' */ return args; /* script "name" is '-' */

8
lua.h
View File

@@ -18,14 +18,14 @@
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4" #define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "8" #define LUA_VERSION_RELEASE "9"
#define LUA_VERSION_NUM 504 #define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 8) #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 9)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#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_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -497,7 +497,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 * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@@ -65,6 +65,8 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
utfint res = 0; /* final result */ utfint res = 0; /* final result */
if (c < 0x80) /* ascii? */ if (c < 0x80) /* ascii? */
res = c; res = c;
else if (c >= 0xfe) /* c >= 1111 1110b ? */
return NULL; /* would need six or more continuation bytes */
else { else {
int count = 0; /* to count number of continuation bytes */ int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
@@ -74,7 +76,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
} }
res |= ((utfint)(c & 0x7F) << (count * 5)); /* add first byte */ res |= ((utfint)(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 */ return NULL; /* invalid byte sequence */
s += count; /* skip continuation bytes read */ s += count; /* skip continuation bytes read */
} }

7
lvm.c
View File

@@ -361,7 +361,12 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
} }
t = tm; /* else repeat assignment over 'tm' */ t = tm; /* else repeat assignment over 'tm' */
if (luaV_fastget(L, t, key, slot, luaH_get)) { if (luaV_fastget(L, t, key, slot, luaH_get)) {
luaV_finishfastset(L, t, slot, val); /* execute 'luaV_finishfastset', but preserving the original 't'
for the barrier. 't' and 'slot' can point to the same value,
and so the assignment can change 't' value */
GCObject *h = gcvalue(t);
setobj2t(L, cast(TValue *,slot), val);
luaC_barrierback(L, h, val);
return; /* done */ return; /* done */
} }
/* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */

View File

@@ -30,7 +30,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p> <p>
<small> <small>
<a href="http://www.lua.org/copyright.html">Copyright</a> <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> </small>
<hr> <hr>
@@ -58,7 +58,7 @@ end
local function compose (f,g) local function compose (f,g)
assert(f and g) assert(f and g)
return function (s) return g(f(s)) end return function (...) return g(f(...)) end
end end
local function concat (f, g) local function concat (f, g)
@@ -395,9 +395,10 @@ APIEntry = function (e)
local apiicmd, ne = string.match(e, "^(.-</span>)(.*)") local apiicmd, ne = string.match(e, "^(.-</span>)(.*)")
--io.stderr:write(e) --io.stderr:write(e)
if not apiicmd then if not apiicmd then
return antipara(Tag.hr() .. Tag.h3(a)) .. Tag.pre(h) .. e return antipara(Tag.hr() .. Tag.h3(a)) .. Tag.pre(h, {class="api"}) .. e
else else
return antipara(Tag.hr() .. Tag.h3(a)) .. apiicmd .. Tag.pre(h) .. ne return antipara(Tag.hr() .. Tag.h3(a)) .. apiicmd ..
Tag.pre(h, {class="api"}) .. ne
end end
end, end,

View File

@@ -107,7 +107,7 @@ for small machines and embedded systems.
Unless stated otherwise, Unless stated otherwise,
any overflow when manipulating integer values @def{wrap around}, any overflow when manipulating integer values @def{wrap around},
according to the usual rules of two-complement arithmetic. according to the usual rules of two's complement arithmetic.
(In other words, (In other words,
the actual result is the unique representable integer the actual result is the unique representable integer
that is equal modulo @M{2@sp{n}} to the mathematical result, that is equal modulo @M{2@sp{n}} to the mathematical result,
@@ -609,7 +609,7 @@ as soon as the collector can be sure the object
will not be accessed again in the normal execution of the program. will not be accessed again in the normal execution of the program.
(@Q{Normal execution} here excludes finalizers, (@Q{Normal execution} here excludes finalizers,
which can resurrect dead objects @see{finalizers}, which can resurrect dead objects @see{finalizers},
and excludes also operations using the debug library.) and it excludes also operations using the debug library.)
Note that the time when the collector can be sure that an object Note that the time when the collector can be sure that an object
is dead may not coincide with the programmer's expectations. is dead may not coincide with the programmer's expectations.
The only guarantees are that Lua will not collect an object The only guarantees are that Lua will not collect an object
@@ -1950,12 +1950,12 @@ Note that keys that are not positive integers
do not interfere with borders. do not interfere with borders.
A table with exactly one border is called a @def{sequence}. A table with exactly one border is called a @def{sequence}.
For instance, the table @T{{10, 20, 30, 40, 50}} is a sequence, For instance, the table @T{{10,20,30,40,50}} is a sequence,
as it has only one border (5). as it has only one border (5).
The table @T{{10, 20, 30, nil, 50}} has two borders (3 and 5), The table @T{{10,20,30,nil,50}} has two borders (3 and 5),
and therefore it is not a sequence. and therefore it is not a sequence.
(The @nil at index 4 is called a @emphx{hole}.) (The @nil at index 4 is called a @emphx{hole}.)
The table @T{{nil, 20, 30, nil, nil, 60, nil}} The table @T{{nil,20,30,nil,nil,60,nil}}
has three borders (0, 3, and 6), has three borders (0, 3, and 6),
so it is not a sequence, too. so it is not a sequence, too.
The table @T{{}} is a sequence with border 0. The table @T{{}} is a sequence with border 0.
@@ -2318,7 +2318,7 @@ we recommend assigning the vararg expression
to a single variable and using that variable to a single variable and using that variable
in its place. in its place.
Here are some examples of uses of mutlres expressions. Here are some examples of uses of multires expressions.
In all cases, when the construction needs In all cases, when the construction needs
@Q{the n-th result} and there is no such result, @Q{the n-th result} and there is no such result,
it uses a @nil. it uses a @nil.
@@ -3471,9 +3471,9 @@ because a pseudo-index is not an actual stack position.
The type of integers in Lua. The type of integers in Lua.
By default this type is @id{long long}, By default this type is @id{long long},
(usually a 64-bit two-complement integer), (usually a 64-bit two's complement integer),
but that can be changed to @id{long} or @id{int} but that can be changed to @id{long} or @id{int}
(usually a 32-bit two-complement integer). (usually a 32-bit two's complement integer).
(See @id{LUA_INT_TYPE} in @id{luaconf.h}.) (See @id{LUA_INT_TYPE} in @id{luaconf.h}.)
Lua also defines the constants Lua also defines the constants
@@ -3689,7 +3689,7 @@ passes to the allocator in every call.
@apii{0,1,m} @apii{0,1,m}
Creates a new empty table and pushes it onto the stack. Creates a new empty table and pushes it onto the stack.
It is equivalent to @T{lua_createtable(L, 0, 0)}. It is equivalent to @T{lua_createtable(L,0,0)}.
} }

View File

@@ -382,6 +382,16 @@ do
end end
do -- bug in 5.4
local parent = {}
parent.__newindex = parent
collectgarbage()
local child = setmetatable({}, parent)
child.__newindex = {x = "hello"}
collectgarbage("step")
assert(parent.__newindex.x == "hello")
end
-- concat metamethod x numbers (bug in 5.1.1) -- concat metamethod x numbers (bug in 5.1.1)
c = {} c = {}

View File

@@ -301,6 +301,16 @@ collectgarbage()
assert(next(a) == string.rep('$', 11)) assert(next(a) == string.rep('$', 11))
if T then -- bug since 5.3: all-weak tables are not being revisited
T.gcstate("propagate")
local t = setmetatable({}, {__mode = "kv"})
T.gcstate("atomic") -- 't' was visited
setmetatable(t, {__mode = "kv"})
T.gcstate("pause") -- its new metatable is not being visited
assert(getmetatable(t).__mode == "kv")
end
-- 'bug' in 5.1 -- 'bug' in 5.1
a = {} a = {}
local t = {x = 10} local t = {x = 10}

View File

@@ -90,7 +90,7 @@ prepfile[[
1, a 1, a
) )
]] ]]
RUN('lua - < %s > %s', prog, out) RUN('lua - -- < %s > %s', prog, out)
checkout("1\tnil\n") checkout("1\tnil\n")
RUN('echo "print(10)\nprint(2)\n" | lua > %s', out) RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
@@ -133,7 +133,7 @@ checkout("-h\n")
prepfile("print(package.path)") prepfile("print(package.path)")
-- test LUA_PATH -- test LUA_PATH
RUN('env LUA_INIT= LUA_PATH=x lua %s > %s', prog, out) RUN('env LUA_INIT= LUA_PATH=x lua -- %s > %s', prog, out)
checkout("x\n") checkout("x\n")
-- test LUA_PATH_version -- test LUA_PATH_version
@@ -346,7 +346,7 @@ RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
checkprogout("6\n10\n10\n\n") checkprogout("6\n10\n10\n\n")
prepfile("a = [[b\nc\nd\ne]]\n=a") prepfile("a = [[b\nc\nd\ne]]\n=a")
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i -- < %s > %s]], prog, out)
checkprogout("b\nc\nd\ne\n\n") checkprogout("b\nc\nd\ne\n\n")
-- input interrupted in continuation line -- input interrupted in continuation line
@@ -478,12 +478,14 @@ assert(not os.remove(out))
-- invalid options -- invalid options
NoRun("unrecognized option '-h'", "lua -h") NoRun("unrecognized option '-h'", "lua -h")
NoRun("unrecognized option '---'", "lua ---") NoRun("unrecognized option '---'", "lua ---")
NoRun("unrecognized option '-Ex'", "lua -Ex") NoRun("unrecognized option '-Ex'", "lua -Ex --")
NoRun("unrecognized option '-vv'", "lua -vv") NoRun("unrecognized option '-vv'", "lua -vv")
NoRun("unrecognized option '-iv'", "lua -iv") NoRun("unrecognized option '-iv'", "lua -iv")
NoRun("'-e' needs argument", "lua -e") NoRun("'-e' needs argument", "lua -e")
NoRun("syntax error", "lua -e a") NoRun("syntax error", "lua -e a")
NoRun("'-l' needs argument", "lua -l") NoRun("'-l' needs argument", "lua -l")
NoRun("-i", "lua -- -i") -- handles -i as a script name
if T then -- test library? if T then -- test library?