Compare commits

..

5 Commits
rc ... v5.5.0

Author SHA1 Message Date
Roberto I
a5522f06d2 GC checks stack space before running finalizer
If the stack does not have some 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.
2025-12-13 16:16:59 -03:00
Roberto I
3d03ae5bd6 'luaL_newstate' starts state with warnings on
It is easier to forget to turn them on then to turn them off.
2025-12-13 11:00:30 -03:00
Roberto I
82d721a855 Format adjust in the manual
Lists in inline code don't get a space after commas. (That keeps the
code more compact and avoids line breaks in the middle of the code.)
2025-12-10 10:35:05 -03:00
Roberto I
104b0fc700 Details
- Avoid fixing name "_ENV" in the code
- Small improvements in the manual
2025-12-08 13:09:47 -03:00
Roberto I
8164d09338 Wrong assert in 'luaK_indexed' 2025-12-08 11:08:12 -03:00
8 changed files with 50 additions and 34 deletions

View File

@@ -1185,7 +1185,7 @@ LUALIB_API lua_State *(luaL_newstate) (void) {
lua_State *L = lua_newstate(luaL_alloc, NULL, luaL_makeseed(NULL)); lua_State *L = lua_newstate(luaL_alloc, NULL, luaL_makeseed(NULL));
if (l_likely(L)) { if (l_likely(L)) {
lua_atpanic(L, &panic); lua_atpanic(L, &panic);
lua_setwarnf(L, warnfoff, L); /* default is warnings off */ lua_setwarnf(L, warnfon, L);
} }
return L; return L;
} }

View File

@@ -1370,9 +1370,11 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
fillidxk(t, k->u.info, VINDEXUP); /* literal short string */ fillidxk(t, k->u.info, VINDEXUP); /* literal short string */
} }
else if (t->k == VVARGVAR) { /* indexing the vararg parameter? */ else if (t->k == VVARGVAR) { /* indexing the vararg parameter? */
lua_assert(t->u.ind.t == fs->f->numparams); int kreg = luaK_exp2anyreg(fs, k); /* put key in some register */
t->u.ind.t = cast_byte(t->u.var.ridx); lu_byte vreg = cast_byte(t->u.var.ridx); /* register with vararg param. */
fillidxk(t, luaK_exp2anyreg(fs, k), VVARGIND); /* register */ lua_assert(vreg == fs->f->numparams);
t->u.ind.t = vreg; /* (avoid a direct assignment; values may overlap) */
fillidxk(t, kreg, VVARGIND); /* 't' represents 'vararg[k]' */
} }
else { else {
/* register index of the table */ /* register index of the table */

11
ldo.c
View File

@@ -220,6 +220,17 @@ 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.
*/
int luaD_checkminstack (lua_State *L) {
return ((stacksize(L) < MAXSTACK - BASIC_STACK_SIZE) &&
(getCcalls(L) < LUAI_MAXCCALLS - 2));
}
/* /*
** 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
** undefined behavior. So, before a stack reallocation, all pointers ** undefined behavior. So, before a stack reallocation, all pointers

1
ldo.h
View File

@@ -89,6 +89,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, TStatus errcode); LUAI_FUNC l_noret luaD_throw (lua_State *L, TStatus errcode);
LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode); LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode);

7
lgc.c
View File

@@ -1293,7 +1293,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->gcemergency && luaD_checkminstack(L))
callallpendingfinalizers(L); callallpendingfinalizers(L);
} }
@@ -1667,12 +1667,13 @@ static l_mem singlestep (lua_State *L, int fast) {
break; break;
} }
case GCScallfin: { /* call finalizers */ case GCScallfin: { /* call 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 */
GCTM(L); /* call one finalizer */ GCTM(L); /* call one finalizer */
stepresult = CWUFIN; stepresult = CWUFIN;
} }
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 */
stepresult = step2pause; stepresult = step2pause;
} }

View File

@@ -505,8 +505,8 @@ static void buildglobal (LexState *ls, TString *varname, expdesc *var) {
init_exp(var, VGLOBAL, -1); /* global by default */ init_exp(var, VGLOBAL, -1); /* global by default */
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
if (var->k == VGLOBAL) if (var->k == VGLOBAL)
luaK_semerror(ls, "_ENV is global when accessing variable '%s'", luaK_semerror(ls, "%s is global when accessing variable '%s'",
getstr(varname)); LUA_ENV, getstr(varname));
luaK_exp2anyregup(fs, var); /* _ENV could be a constant */ luaK_exp2anyregup(fs, var); /* _ENV could be a constant */
codestring(&key, varname); /* key is variable name */ codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* 'var' represents _ENV[varname] */ luaK_indexed(fs, var, &key); /* 'var' represents _ENV[varname] */

3
lua.c
View File

@@ -349,6 +349,7 @@ static int collectargs (char **argv, int *first) {
*/ */
static int runargs (lua_State *L, char **argv, int n) { static int runargs (lua_State *L, char **argv, int n) {
int i; int i;
lua_warning(L, "@off", 0); /* by default, Lua stand-alone has warnings off */
for (i = 1; i < n; i++) { for (i = 1; i < n; i++) {
int option = argv[i][1]; int option = argv[i][1];
lua_assert(argv[i][0] == '-'); /* already checked */ lua_assert(argv[i][0] == '-'); /* already checked */
@@ -725,7 +726,7 @@ static int pmain (lua_State *L) {
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */ return 0; /* error running LUA_INIT */
} }
if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */ if (!runargs(L, argv, optlim)) /* execute arguments -e, -l, and -W */
return 0; /* something failed */ return 0; /* something failed */
if (script > 0) { /* execute main script (if there is one) */ if (script > 0) { /* execute main script (if there is one) */
if (handle_script(L, argv + script) != LUA_OK) if (handle_script(L, argv + script) != LUA_OK)

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,
@@ -2091,12 +2091,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.
@@ -2449,22 +2449,22 @@ These are the places where Lua expects a list of expressions:
@description{ @description{
@item{A @rw{return} statement, @item{A @rw{return} statement,
for instance @T{return e1, e2, e3} @see{control}.} for instance @T{return e1,e2,e3} @see{control}.}
@item{A table constructor, @item{A table constructor,
for instance @T{{e1, e2, e3}} @see{tableconstructor}.} for instance @T{{e1,e2,e3}} @see{tableconstructor}.}
@item{The arguments of a function call, @item{The arguments of a function call,
for instance @T{foo(e1, e2, e3)} @see{functioncall}.} for instance @T{foo(e1,e2,e3)} @see{functioncall}.}
@item{A multiple assignment, @item{A multiple assignment,
for instance @T{a , b, c = e1, e2, e3} @see{assignment}.} for instance @T{a,b,c = e1,e2,e3} @see{assignment}.}
@item{A local or global declaration, @item{A local or global declaration,
which is similar to a multiple assignment.} which is similar to a multiple assignment.}
@item{The initial values in a generic @rw{for} loop, @item{The initial values in a generic @rw{for} loop,
for instance @T{for k in e1, e2, e3 do ... end} @see{for}.} for instance @T{for k in e1,e2,e3 do ... end} @see{for}.}
} }
In the last four cases, In the last four cases,
@@ -2501,7 +2501,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.
@@ -3107,7 +3107,7 @@ void *luaL_alloc (void *ud, void *ptr, size_t osize,
} }
Note that @N{ISO C} ensures Note that @N{ISO C} ensures
that @T{free(NULL)} has no effect and that that @T{free(NULL)} has no effect and that
@T{realloc(NULL, size)} is equivalent to @T{malloc(size)}. @T{realloc(NULL,size)} is equivalent to @T{malloc(size)}.
} }
@@ -3640,9 +3640,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
@@ -3879,7 +3879,7 @@ is a seed for the hashing of strings.
@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)}.
} }
@@ -5439,7 +5439,7 @@ the auxiliary library provides higher-level functions for some
common tasks. common tasks.
All functions and types from the auxiliary library All functions and types from the auxiliary library
are defined in header file @id{lauxlib.h} and are defined in the header file @id{lauxlib.h} and
have a prefix @id{luaL_}. have a prefix @id{luaL_}.
All functions in the auxiliary library are built on All functions in the auxiliary library are built on
@@ -5583,7 +5583,7 @@ Its pattern of use is as follows:
@item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.} @item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.}
@item{Then initialize it with a call @T{luaL_buffinit(L, &b)}.} @item{Then initialize it with a call @T{luaL_buffinit(L,&b)}.}
@item{ @item{
Then add string pieces to the buffer calling any of Then add string pieces to the buffer calling any of
@@ -5604,12 +5604,12 @@ you can use the buffer like this:
@item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.} @item{First declare a variable @id{b} of type @Lid{luaL_Buffer}.}
@item{Then initialize it and preallocate a space of @item{Then initialize it and preallocate a space of
size @id{sz} with a call @T{luaL_buffinitsize(L, &b, sz)}.} size @id{sz} with a call @T{luaL_buffinitsize(L,&b,sz)}.}
@item{Then produce the string into that space.} @item{Then produce the string into that space.}
@item{ @item{
Finish by calling @T{luaL_pushresultsize(&b, sz)}, Finish by calling @T{luaL_pushresultsize(&b,sz)},
where @id{sz} is the total size of the resulting string where @id{sz} is the total size of the resulting string
copied into that space (which may be less than or copied into that space (which may be less than or
equal to the preallocated size). equal to the preallocated size).
@@ -6214,7 +6214,7 @@ You should not manually set integer keys in the table
after the first use of @Lid{luaL_ref}. after the first use of @Lid{luaL_ref}.
You can retrieve an object referred by the reference @id{r} You can retrieve an object referred by the reference @id{r}
by calling @T{lua_rawgeti(L, t, r)} or @T{lua_geti(L, t, r)}. by calling @T{lua_rawgeti(L,t,r)} or @T{lua_geti(L,t,r)}.
The function @Lid{luaL_unref} frees a reference. The function @Lid{luaL_unref} frees a reference.
If the object on the top of the stack is @nil, If the object on the top of the stack is @nil,
@@ -6492,7 +6492,7 @@ the host program can call the function @Lid{luaL_openlibs}.
Alternatively, Alternatively,
the host can select which libraries to open, the host can select which libraries to open,
by using @Lid{luaL_openselectedlibs}. by using @Lid{luaL_openselectedlibs}.
Both functions are defined in the header file @id{lualib.h}. Both functions are declared in the header file @id{lualib.h}.
@index{lualib.h} @index{lualib.h}
The stand-alone interpreter @id{lua} @see{lua-sa} The stand-alone interpreter @id{lua} @see{lua-sa}
@@ -7744,7 +7744,7 @@ If @id{j} is absent, then it is assumed to be equal to @num{-1}
In particular, In particular,
the call @T{string.sub(s,1,j)} returns a prefix of @id{s} the call @T{string.sub(s,1,j)} returns a prefix of @id{s}
with length @id{j}, with length @id{j},
and @T{string.sub(s, -i)} (for a positive @id{i}) and @T{string.sub(s,-i)} (for a positive @id{i})
returns a suffix of @id{s} returns a suffix of @id{s}
with length @id{i}. with length @id{i}.
@@ -8180,7 +8180,7 @@ the function returns @fail.
A negative @id{n} gets characters before position @id{i}. A negative @id{n} gets characters before position @id{i}.
The default for @id{i} is 1 when @id{n} is non-negative The default for @id{i} is 1 when @id{n} is non-negative
and @T{#s + 1} otherwise, and @T{#s + 1} otherwise,
so that @T{utf8.offset(s, -n)} gets the offset of the so that @T{utf8.offset(s,-n)} gets the offset of the
@id{n}-th character from the end of the string. @id{n}-th character from the end of the string.
As a special case, As a special case,
@@ -8233,7 +8233,7 @@ the table will have; its default is zero.
Inserts element @id{value} at position @id{pos} in @id{list}, Inserts element @id{value} at position @id{pos} in @id{list},
shifting up the elements shifting up the elements
@T{list[pos], list[pos+1], @Cdots, list[#list]}. @T{list[pos],list[pos+1],@Cdots,list[#list]}.
The default value for @id{pos} is @T{#list+1}, The default value for @id{pos} is @T{#list+1},
so that a call @T{table.insert(t,x)} inserts @id{x} at the end so that a call @T{table.insert(t,x)} inserts @id{x} at the end
of the list @id{t}. of the list @id{t}.
@@ -8271,7 +8271,7 @@ Removes from @id{list} the element at position @id{pos},
returning the value of the removed element. returning the value of the removed element.
When @id{pos} is an integer between 1 and @T{#list}, When @id{pos} is an integer between 1 and @T{#list},
it shifts down the elements it shifts down the elements
@T{list[pos+1], list[pos+2], @Cdots, list[#list]} @T{list[pos+1],list[pos+2],@Cdots,list[#list]}
and erases element @T{list[#list]}; and erases element @T{list[#list]};
The index @id{pos} can also be 0 when @T{#list} is 0, The index @id{pos} can also be 0 when @T{#list} is 0,
or @T{#list + 1}. or @T{#list + 1}.