diffu-lua-5.4.6-lua-5.4.7
Makefile
@@ -46,7 +46,7 @@
# Lua version and release.
V= 5.4
-R= $V.6
+R= $V.7
# Targets start here.
all: $(PLAT)
README
@@ -1,5 +1,5 @@
-This is Lua 5.4.6, released on 02 May 2023.
+This is Lua 5.4.7, released on 13 Jun 2024.
For installation instructions, license details, and
further information about Lua, see doc/readme.html.
Only in lua-5.4.7/doc: OSIApproved_100X125.png
doc/contents.html
@@ -10,7 +10,7 @@
<BODY>
<H1>
-<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
+<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Lua 5.4 Reference Manual
</H1>
@@ -18,7 +18,7 @@
The reference manual is the official definition of the Lua language.
<BR>
For a complete introduction to Lua programming, see the book
-<A HREF="http://www.lua.org/pil/">Programming in Lua</A>.
+<A HREF="https://www.lua.org/pil/">Programming in Lua</A>.
<DIV CLASS="menubar">
<A HREF="manual.html">start</A>
@@ -27,14 +27,14 @@
·
<A HREF="#index">index</A>
·
-<A HREF="http://www.lua.org/manual/">other versions</A>
+<A HREF="https://www.lua.org/manual/">other versions</A>
</DIV>
<P>
<SMALL>
-Copyright © 2020–2023 Lua.org, PUC-Rio.
+Copyright © 2020–2024 Lua.org, PUC-Rio.
Freely available under the terms of the
-<A HREF="http://www.lua.org/license.html">Lua license</A>.
+<A HREF="https://www.lua.org/license.html">Lua license</A>.
</SMALL>
<H2><A NAME="contents">Contents</A></H2>
@@ -668,10 +668,10 @@
<P CLASS="footer">
Last update:
-Sat Apr 1 17:57:05 UTC 2023
+Thu May 9 14:47:09 UTC 2024
</P>
<!--
-Last change: revised for Lua 5.4.5
+Last change: revised for Lua 5.4.7
-->
</BODY>
doc/lua.1
@@ -1,5 +1,5 @@
-.\" $Id: lua.man,v 1.14 2022/09/23 09:06:36 lhf Exp $
-.TH LUA 1 "$Date: 2022/09/23 09:06:36 $"
+.\" $Id: lua.man,v 1.14 2024/05/08 18:48:27 lhf Exp $
+.TH LUA 1 "$Date: 2024/05/08 18:48:27 $"
.SH NAME
lua \- Lua interpreter
.SH SYNOPSIS
@@ -123,7 +123,7 @@
Code to be executed before command line options and scripts.
.TP
.B LUA_PATH, LUA_PATH_5_4
-Initial value of package.cpath,
+Initial value of package.path,
the path used by require to search for Lua loaders.
.TP
.B LUA_CPATH, LUA_CPATH_5_4
doc/lua.css
@@ -143,6 +143,7 @@
table.book img {
border: solid #000080 1px ;
+ border-radius: 2px ;
}
table.book span {
doc/manual.html
@@ -10,7 +10,7 @@
<BODY>
<H1>
-<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
+<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Lua 5.4 Reference Manual
</H1>
@@ -19,9 +19,9 @@
<P>
<SMALL>
-Copyright © 2020–2023 Lua.org, PUC-Rio.
+Copyright © 2020–2024 Lua.org, PUC-Rio.
Freely available under the terms of the
-<a href="http://www.lua.org/license.html">Lua license</a>.
+<a href="https://www.lua.org/license.html">Lua license</a>.
</SMALL>
<DIV CLASS="menubar">
@@ -29,7 +29,7 @@
·
<A HREF="contents.html#index">index</A>
·
-<A HREF="http://www.lua.org/manual/">other versions</A>
+<A HREF="https://www.lua.org/manual/">other versions</A>
</DIV>
<!-- ====================================================================== -->
@@ -391,7 +391,7 @@
an <em>error object</em>
is propagated with information about the error.
Lua itself only generates errors whose error object is a string,
-but programs may generate errors with
+but programs can generate errors with
any value as the error object.
It is up to the Lua program or its host to handle such error objects.
For historical reasons,
@@ -401,7 +401,7 @@
<p>
When you use <a href="#pdf-xpcall"><code>xpcall</code></a> (or <a href="#lua_pcall"><code>lua_pcall</code></a>, in C)
-you may give a <em>message handler</em>
+you can give a <em>message handler</em>
to be called in case of errors.
This function is called with the original error object
and returns a new error object.
@@ -453,7 +453,7 @@
In the previous example, the key is the string "<code>__add</code>"
and the metamethod is the function that performs the addition.
Unless stated otherwise,
-a metamethod may in fact be any callable value,
+a metamethod can in fact be any callable value,
which is either a function or a value with a <code>__call</code> metamethod.
@@ -1725,7 +1725,7 @@
<p>
A label is visible in the entire block where it is defined,
except inside nested functions.
-A goto may jump to any visible label as long as it does not
+A goto can jump to any visible label as long as it does not
enter into the scope of a local variable.
A label should not be declared
where a label with the same name is visible,
@@ -5571,7 +5571,7 @@
<hr><h3><a name="lua_toclose"><code>lua_toclose</code></a></h3><p>
-<span class="apii">[-0, +0, <em>m</em>]</span>
+<span class="apii">[-0, +0, <em>v</em>]</span>
<pre>void lua_toclose (lua_State *L, int index);</pre>
<p>
@@ -5592,6 +5592,11 @@
<p>
+This function raises an error if the value at the given slot
+neither has a <code>__close</code> metamethod nor is a false value.
+
+
+<p>
This function should not be called for an index
that is equal to or below an active to-be-closed slot.
@@ -5664,6 +5669,12 @@
but can contain other zeros in its body.
+<p>
+This function can raise memory errors only
+when converting a number to a string
+(as then it may create a new string).
+
+
@@ -11276,13 +11287,13 @@
with the string <code>what</code> describing which fields to fill in.
The default for <code>what</code> is to get all information available,
except the table of valid lines.
-If present,
-the option '<code>f</code>'
+The option '<code>f</code>'
adds a field named <code>func</code> with the function itself.
-If present,
-the option '<code>L</code>'
-adds a field named <code>activelines</code> with the table of
-valid lines.
+The option '<code>L</code>' adds a field named <code>activelines</code>
+with the table of valid lines,
+provided the function is a Lua function.
+If the function has no debug information,
+the table is empty.
<p>
@@ -11619,6 +11630,10 @@
In particular,
the values of <a href="#pdf-package.path"><code>package.path</code></a> and <a href="#pdf-package.cpath"><code>package.cpath</code></a>
are set with the default paths defined in <code>luaconf.h</code>.
+To signal to the libraries that this option is on,
+the stand-alone interpreter sets the field
+<code>"LUA_NOENV"</code> in the registry to a true value.
+Other libraries may consult this field for the same purpose.
<p>
@@ -12033,13 +12048,12 @@
-
<P CLASS="footer">
Last update:
-Tue May 2 20:09:38 UTC 2023
+Thu Jun 13 22:15:52 UTC 2024
</P>
<!--
-Last change: revised for Lua 5.4.6
+Last change: revised for Lua 5.4.7
-->
</body></html>
Only in lua-5.4.6/doc: osi-certified-72x60.png
doc/readme.html
@@ -29,7 +29,7 @@
<BODY>
<H1>
-<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
+<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Welcome to Lua 5.4
</H1>
@@ -49,29 +49,31 @@
<P>
Lua is a powerful, efficient, lightweight, embeddable scripting language
developed by a
-<A HREF="http://www.lua.org/authors.html">team</A>
+<A HREF="https://www.lua.org/authors.html">team</A>
at
-<A HREF="http://www.puc-rio.br/">PUC-Rio</A>,
+<A HREF="https://www.puc-rio.br/">PUC-Rio</A>,
the Pontifical Catholic University of Rio de Janeiro in Brazil.
Lua is
<A HREF="#license">free software</A>
used in
-<A HREF="http://www.lua.org/uses.html">many products and projects</A>
+<A HREF="https://www.lua.org/uses.html">many products and projects</A>
around the world.
<P>
Lua's
-<A HREF="http://www.lua.org/">official web site</A>
+<A HREF="https://www.lua.org/">official website</A>
provides complete information
about Lua,
including
an
-<A HREF="http://www.lua.org/about.html">executive summary</A>
+<A HREF="https://www.lua.org/about.html">executive summary</A>,
+tips on
+<A HREF="https://www.lua.org/start.html">getting started</A>,
and
updated
-<A HREF="http://www.lua.org/docs.html">documentation</A>,
+<A HREF="https://www.lua.org/docs.html">documentation</A>,
especially the
-<A HREF="http://www.lua.org/manual/5.4/">reference manual</A>,
+<A HREF="https://www.lua.org/manual/5.4/">reference manual</A>,
which may differ slightly from the
<A HREF="contents.html">local copy</A>
distributed in this package.
@@ -79,7 +81,7 @@
<H2><A NAME="install">Installing Lua</A></H2>
<P>
Lua is distributed in
-<A HREF="http://www.lua.org/ftp/">source</A>
+<A HREF="https://www.lua.org/ftp/">source</A>
form.
You need to build it before using it.
Building Lua should be straightforward
@@ -88,7 +90,7 @@
platforms that have an ANSI C compiler.
Lua also compiles unmodified as C++.
The instructions given below for building Lua are for Unix-like platforms,
-such as Linux and Mac OS X.
+such as Linux and macOS.
See also
<A HREF="#other">instructions for other systems</A>
and
@@ -97,7 +99,7 @@
<P>
If you don't have the time or the inclination to compile Lua yourself,
get a binary from
-<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>.
+<A HREF="https://luabinaries.sourceforge.net">LuaBinaries</A>.
<H3>Building Lua</H3>
<P>
@@ -107,7 +109,7 @@
<OL>
<LI>
Open a terminal window and move to
-the top-level directory, which is named <TT>lua-5.4.6</TT>.
+the top-level directory, which is named <TT>lua-5.4.7</TT>.
The <TT>Makefile</TT> there controls both the build process and the installation process.
<P>
<LI>
@@ -211,8 +213,8 @@
record the changes you've made.
<P>
- On the other hand, if you need to customize some Lua features, you'll need
- to edit <TT>src/luaconf.h</TT> before building and installing Lua.
+ On the other hand, if you need to customize some Lua features,
+ edit <TT>src/luaconf.h</TT> before building and installing Lua.
The edited file will be the one installed, and
it will be used by any Lua clients that you build, to ensure consistency.
Further customization is available to experts by editing the Lua sources.
@@ -241,7 +243,7 @@
</DL>
<P>
- To use Lua as a library in your own programs, you'll need to know how to
+ To use Lua as a library in your own programs, you need to know how to
create and use libraries with your compiler. Moreover, to dynamically load
C libraries for Lua, you'll need to know how to create dynamic libraries
and you'll need to make sure that the Lua API functions are accessible to
@@ -284,11 +286,11 @@
<H2><A NAME="license">License</A></H2>
<P>
-<A HREF="http://www.opensource.org/docs/definition.php">
-<IMG SRC="osi-certified-72x60.png" ALIGN="right" ALT="[osi certified]" STYLE="padding-left: 30px ;">
+<A HREF="https://opensource.org/osd">
+<IMG SRC="OSIApproved_100X125.png" ALIGN="right" ALT="[Open Source Initiative Approved License]" STYLE="padding-left: 1em" WIDTH=50>
</A>
Lua is free software distributed under the terms of the
-<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A>
+<A HREF="https://opensource.org/license/mit">MIT license</A>
reproduced below;
it may be used for any purpose, including commercial purposes,
at absolutely no cost without having to ask us.
@@ -296,11 +298,11 @@
The only requirement is that if you do use Lua,
then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation.
-For details, see
-<A HREF="http://www.lua.org/license.html">this</A>.
+For details, see the
+<A HREF="https://www.lua.org/license.html">license page</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em">
-Copyright © 1994–2023 Lua.org, PUC-Rio.
+Copyright © 1994–2024 Lua.org, PUC-Rio.
<P>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -327,10 +329,10 @@
<P CLASS="footer">
Last update:
-Tue May 2 20:08:55 UTC 2023
+Wed May 8 21:56:16 UTC 2024
</P>
<!--
-Last change: revised for Lua 5.4.6
+Last change: revised for Lua 5.4.7
-->
</BODY>
src/lapi.c
@@ -417,9 +417,9 @@
o = index2value(L, idx); /* previous call may reallocate the stack */
}
if (len != NULL)
- *len = vslen(o);
+ *len = tsslen(tsvalue(o));
lua_unlock(L);
- return svalue(o);
+ return getstr(tsvalue(o));
}
src/lauxlib.c
@@ -80,6 +80,7 @@
int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
+ luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */
if (findfield(L, top + 1, 2)) {
const char *name = lua_tostring(L, -1);
if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */
@@ -249,11 +250,13 @@
return 1;
}
else {
+ const char *msg;
luaL_pushfail(L);
+ msg = (en != 0) ? strerror(en) : "(no extra info)";
if (fname)
- lua_pushfstring(L, "%s: %s", fname, strerror(en));
+ lua_pushfstring(L, "%s: %s", fname, msg);
else
- lua_pushstring(L, strerror(en));
+ lua_pushstring(L, msg);
lua_pushinteger(L, en);
return 3;
}
@@ -732,9 +735,12 @@
static int errfile (lua_State *L, const char *what, int fnameindex) {
- const char *serr = strerror(errno);
+ int err = errno;
const char *filename = lua_tostring(L, fnameindex) + 1;
- lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
+ if (err != 0)
+ lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err));
+ else
+ lua_pushfstring(L, "cannot %s %s", what, filename);
lua_remove(L, fnameindex);
return LUA_ERRFILE;
}
@@ -787,6 +793,7 @@
}
else {
lua_pushfstring(L, "@%s", filename);
+ errno = 0;
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
@@ -796,6 +803,7 @@
if (c == LUA_SIGNATURE[0]) { /* binary file? */
lf.n = 0; /* remove possible newline */
if (filename) { /* "real" file? */
+ errno = 0;
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(lf.f, &c); /* re-read initial portion */
@@ -803,6 +811,7 @@
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
+ errno = 0;
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
readstatus = ferror(lf.f);
if (filename) fclose(lf.f); /* close file (even in case of errors) */
@@ -933,7 +942,7 @@
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkstack(L, nup, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */
- if (l->func == NULL) /* place holder? */
+ if (l->func == NULL) /* placeholder? */
lua_pushboolean(L, 0);
else {
int i;
@@ -1025,9 +1034,14 @@
}
+/*
+** Standard panic funcion just prints an error message. The test
+** with 'lua_type' avoids possible memory errors in 'lua_tostring'.
+*/
static int panic (lua_State *L) {
- const char *msg = lua_tostring(L, -1);
- if (msg == NULL) msg = "error object is not a string";
+ const char *msg = (lua_type(L, -1) == LUA_TSTRING)
+ ? lua_tostring(L, -1)
+ : "error object is not a string";
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
msg);
return 0; /* return to Lua to abort */
src/lcode.c
@@ -415,7 +415,7 @@
/*
** Format and emit an 'iAsBx' instruction.
*/
-int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
+static int codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
unsigned int b = bc + OFFSET_sBx;
lua_assert(getOpMode(o) == iAsBx);
lua_assert(a <= MAXARG_A && b <= MAXARG_Bx);
@@ -671,7 +671,7 @@
void luaK_int (FuncState *fs, int reg, lua_Integer i) {
if (fitsBx(i))
- luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i));
+ codeAsBx(fs, OP_LOADI, reg, cast_int(i));
else
luaK_codek(fs, reg, luaK_intK(fs, i));
}
@@ -680,7 +680,7 @@
static void luaK_float (FuncState *fs, int reg, lua_Number f) {
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi))
- luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
+ codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
else
luaK_codek(fs, reg, luaK_numberK(fs, f));
}
@@ -776,7 +776,8 @@
break;
}
case VLOCAL: { /* already in a register */
- e->u.info = e->u.var.ridx;
+ int temp = e->u.var.ridx;
+ e->u.info = temp; /* (can't do a direct assignment; values overlap) */
e->k = VNONRELOC; /* becomes a non-relocatable value */
break;
}
@@ -1025,7 +1026,7 @@
** in the range of R/K indices).
** Returns 1 iff expression is K.
*/
-int luaK_exp2RK (FuncState *fs, expdesc *e) {
+static int exp2RK (FuncState *fs, expdesc *e) {
if (luaK_exp2K(fs, e))
return 1;
else { /* not a constant in the right range: put it in a register */
@@ -1037,7 +1038,7 @@
static void codeABRK (FuncState *fs, OpCode o, int a, int b,
expdesc *ec) {
- int k = luaK_exp2RK(fs, ec);
+ int k = exp2RK(fs, ec);
luaK_codeABCk(fs, o, a, b, ec->u.info, k);
}
@@ -1215,7 +1216,7 @@
/*
-** Check whether expression 'e' is a small literal string
+** Check whether expression 'e' is a short literal string
*/
static int isKstr (FuncState *fs, expdesc *e) {
return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B &&
@@ -1225,7 +1226,7 @@
/*
** Check whether expression 'e' is a literal integer.
*/
-int luaK_isKint (expdesc *e) {
+static int isKint (expdesc *e) {
return (e->k == VKINT && !hasjumps(e));
}
@@ -1235,7 +1236,7 @@
** proper range to fit in register C
*/
static int isCint (expdesc *e) {
- return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C));
+ return isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C));
}
@@ -1244,7 +1245,7 @@
** proper range to fit in register sC
*/
static int isSCint (expdesc *e) {
- return luaK_isKint(e) && fitsC(e->u.ival);
+ return isKint(e) && fitsC(e->u.ival);
}
@@ -1283,15 +1284,17 @@
if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */
luaK_exp2anyreg(fs, t); /* put it in a register */
if (t->k == VUPVAL) {
- t->u.ind.t = t->u.info; /* upvalue index */
- t->u.ind.idx = k->u.info; /* literal string */
+ int temp = t->u.info; /* upvalue index */
+ lua_assert(isKstr(fs, k));
+ t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
+ t->u.ind.idx = k->u.info; /* literal short string */
t->k = VINDEXUP;
}
else {
/* register index of the table */
t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info;
if (isKstr(fs, k)) {
- t->u.ind.idx = k->u.info; /* literal string */
+ t->u.ind.idx = k->u.info; /* literal short string */
t->k = VINDEXSTR;
}
else if (isCint(k)) {
@@ -1459,7 +1462,7 @@
*/
static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2,
OpCode op, int line, TMS event) {
- if (!luaK_isKint(e2))
+ if (!isKint(e2))
return 0; /* not an integer constant */
else {
lua_Integer i2 = e2->u.ival;
@@ -1592,7 +1595,7 @@
op = OP_EQI;
r2 = im; /* immediate operand */
}
- else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
+ else if (exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK;
r2 = e2->u.info; /* constant index */
}
@@ -1658,7 +1661,7 @@
}
case OPR_EQ: case OPR_NE: {
if (!tonumeral(v, NULL))
- luaK_exp2RK(fs, v);
+ exp2RK(fs, v);
/* else keep numeral, which may be an immediate operand */
break;
}
src/lcode.h
@@ -61,10 +61,8 @@
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
-LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
int B, int C, int k);
-LUAI_FUNC int luaK_isKint (expdesc *e);
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
@@ -76,7 +74,6 @@
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
-LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
src/ldebug.c
@@ -31,7 +31,7 @@
-#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
+#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
@@ -254,7 +254,7 @@
static void funcinfo (lua_Debug *ar, Closure *cl) {
- if (noLuaClosure(cl)) {
+ if (!LuaClosure(cl)) {
ar->source = "=[C]";
ar->srclen = LL("=[C]");
ar->linedefined = -1;
@@ -288,29 +288,31 @@
static void collectvalidlines (lua_State *L, Closure *f) {
- if (noLuaClosure(f)) {
+ if (!LuaClosure(f)) {
setnilvalue(s2v(L->top.p));
api_incr_top(L);
}
else {
- int i;
- TValue v;
const Proto *p = f->l.p;
int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L);
- setbtvalue(&v); /* boolean 'true' to be the value of all indices */
- if (!p->is_vararg) /* regular function? */
- i = 0; /* consider all instructions */
- else { /* vararg function */
- lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
- currentline = nextline(p, currentline, 0);
- i = 1; /* skip first instruction (OP_VARARGPREP) */
- }
- for (; i < p->sizelineinfo; i++) { /* for each instruction */
- currentline = nextline(p, currentline, i); /* get its line */
- luaH_setint(L, t, currentline, &v); /* table[line] = true */
+ if (p->lineinfo != NULL) { /* proto with debug information? */
+ int i;
+ TValue v;
+ setbtvalue(&v); /* boolean 'true' to be the value of all indices */
+ if (!p->is_vararg) /* regular function? */
+ i = 0; /* consider all instructions */
+ else { /* vararg function */
+ lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
+ currentline = nextline(p, currentline, 0);
+ i = 1; /* skip first instruction (OP_VARARGPREP) */
+ }
+ for (; i < p->sizelineinfo; i++) { /* for each instruction */
+ currentline = nextline(p, currentline, i); /* get its line */
+ luaH_setint(L, t, currentline, &v); /* table[line] = true */
+ }
}
}
}
@@ -339,7 +341,7 @@
}
case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
- if (noLuaClosure(f)) {
+ if (!LuaClosure(f)) {
ar->isvararg = 1;
ar->nparams = 0;
}
@@ -417,40 +419,6 @@
** =======================================================
*/
-static const char *getobjname (const Proto *p, int lastpc, int reg,
- const char **name);
-
-
-/*
-** Find a "name" for the constant 'c'.
-*/
-static void kname (const Proto *p, int c, const char **name) {
- TValue *kvalue = &p->k[c];
- *name = (ttisstring(kvalue)) ? svalue(kvalue) : "?";
-}
-
-
-/*
-** Find a "name" for the register 'c'.
-*/
-static void rname (const Proto *p, int pc, int c, const char **name) {
- const char *what = getobjname(p, pc, c, name); /* search for 'c' */
- if (!(what && *what == 'c')) /* did not find a constant name? */
- *name = "?";
-}
-
-
-/*
-** Find a "name" for a 'C' value in an RK instruction.
-*/
-static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
- int c = GETARG_C(i); /* key index */
- if (GETARG_k(i)) /* is 'c' a constant? */
- kname(p, c, name);
- else /* 'c' is a register */
- rname(p, pc, c, name);
-}
-
static int filterpc (int pc, int jmptarget) {
if (pc < jmptarget) /* is code conditional (inside a jump)? */
@@ -509,28 +477,29 @@
/*
-** Check whether table being indexed by instruction 'i' is the
-** environment '_ENV'
+** Find a "name" for the constant 'c'.
*/
-static const char *gxf (const Proto *p, int pc, Instruction i, int isup) {
- int t = GETARG_B(i); /* table index */
- const char *name; /* name of indexed variable */
- if (isup) /* is an upvalue? */
- name = upvalname(p, t);
- else
- getobjname(p, pc, t, &name);
- return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
+static const char *kname (const Proto *p, int index, const char **name) {
+ TValue *kvalue = &p->k[index];
+ if (ttisstring(kvalue)) {
+ *name = getstr(tsvalue(kvalue));
+ return "constant";
+ }
+ else {
+ *name = "?";
+ return NULL;
+ }
}
-static const char *getobjname (const Proto *p, int lastpc, int reg,
- const char **name) {
- int pc;
- *name = luaF_getlocalname(p, reg + 1, lastpc);
+static const char *basicgetobjname (const Proto *p, int *ppc, int reg,
+ const char **name) {
+ int pc = *ppc;
+ *name = luaF_getlocalname(p, reg + 1, pc);
if (*name) /* is a local? */
return "local";
/* else try symbolic execution */
- pc = findsetreg(p, lastpc, reg);
+ *ppc = pc = findsetreg(p, pc, reg);
if (pc != -1) { /* could find instruction? */
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
@@ -538,18 +507,80 @@
case OP_MOVE: {
int b = GETARG_B(i); /* move from 'b' to 'a' */
if (b < GETARG_A(i))
- return getobjname(p, pc, b, name); /* get name for 'b' */
+ return basicgetobjname(p, ppc, b, name); /* get name for 'b' */
break;
}
+ case OP_GETUPVAL: {
+ *name = upvalname(p, GETARG_B(i));
+ return "upvalue";
+ }
+ case OP_LOADK: return kname(p, GETARG_Bx(i), name);
+ case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name);
+ default: break;
+ }
+ }
+ return NULL; /* could not find reasonable name */
+}
+
+
+/*
+** Find a "name" for the register 'c'.
+*/
+static void rname (const Proto *p, int pc, int c, const char **name) {
+ const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */
+ if (!(what && *what == 'c')) /* did not find a constant name? */
+ *name = "?";
+}
+
+
+/*
+** Find a "name" for a 'C' value in an RK instruction.
+*/
+static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
+ int c = GETARG_C(i); /* key index */
+ if (GETARG_k(i)) /* is 'c' a constant? */
+ kname(p, c, name);
+ else /* 'c' is a register */
+ rname(p, pc, c, name);
+}
+
+
+/*
+** Check whether table being indexed by instruction 'i' is the
+** environment '_ENV'
+*/
+static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) {
+ int t = GETARG_B(i); /* table index */
+ const char *name; /* name of indexed variable */
+ if (isup) /* is 't' an upvalue? */
+ name = upvalname(p, t);
+ else /* 't' is a register */
+ basicgetobjname(p, &pc, t, &name);
+ return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
+}
+
+
+/*
+** Extend 'basicgetobjname' to handle table accesses
+*/
+static const char *getobjname (const Proto *p, int lastpc, int reg,
+ const char **name) {
+ const char *kind = basicgetobjname(p, &lastpc, reg, name);
+ if (kind != NULL)
+ return kind;
+ else if (lastpc != -1) { /* could find instruction? */
+ Instruction i = p->code[lastpc];
+ OpCode op = GET_OPCODE(i);
+ switch (op) {
case OP_GETTABUP: {
int k = GETARG_C(i); /* key index */
kname(p, k, name);
- return gxf(p, pc, i, 1);
+ return isEnv(p, lastpc, i, 1);
}
case OP_GETTABLE: {
int k = GETARG_C(i); /* key index */
- rname(p, pc, k, name);
- return gxf(p, pc, i, 0);
+ rname(p, lastpc, k, name);
+ return isEnv(p, lastpc, i, 0);
}
case OP_GETI: {
*name = "integer index";
@@ -558,24 +589,10 @@
case OP_GETFIELD: {
int k = GETARG_C(i); /* key index */
kname(p, k, name);
- return gxf(p, pc, i, 0);
- }
- case OP_GETUPVAL: {
- *name = upvalname(p, GETARG_B(i));
- return "upvalue";
- }
- case OP_LOADK:
- case OP_LOADKX: {
- int b = (op == OP_LOADK) ? GETARG_Bx(i)
- : GETARG_Ax(p->code[pc + 1]);
- if (ttisstring(&p->k[b])) {
- *name = svalue(&p->k[b]);
- return "constant";
- }
- break;
+ return isEnv(p, lastpc, i, 0);
}
case OP_SELF: {
- rkname(p, pc, i, name);
+ rkname(p, lastpc, i, name);
return "method";
}
default: break; /* go through to return NULL */
@@ -627,7 +644,7 @@
default:
return NULL; /* cannot find a reasonable name */
}
- *name = getstr(G(L)->tmname[tm]) + 2;
+ *name = getshrstr(G(L)->tmname[tm]) + 2;
return "metamethod";
}
@@ -866,6 +883,28 @@
/*
+** Traces Lua calls. If code is running the first instruction of a function,
+** and function is not vararg, and it is not coming from an yield,
+** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall'
+** after adjusting its variable arguments; otherwise, they could call
+** a line/count hook before the call hook. Functions coming from
+** an yield already called 'luaD_hookcall' before yielding.)
+*/
+int luaG_tracecall (lua_State *L) {
+ CallInfo *ci = L->ci;
+ Proto *p = ci_func(ci)->p;
+ ci->u.l.trap = 1; /* ensure hooks will be checked */
+ if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
+ if (p->is_vararg)
+ return 0; /* hooks will start at VARARGPREP instruction */
+ else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */
+ luaD_hookcall(L, ci); /* check 'call' hook */
+ }
+ return 1; /* keep 'trap' on */
+}
+
+
+/*
** Traces the execution of a Lua function. Called before the execution
** of each opcode, when debug is on. 'L->oldpc' stores the last
** instruction traced, to detect line changes. When entering a new
@@ -888,12 +927,12 @@
}
pc++; /* reference is always next instruction */
ci->u.l.savedpc = pc; /* save 'pc' */
- counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
+ counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
if (counthook)
resethookcount(L); /* reset count */
else if (!(mask & LUA_MASKLINE))
return 1; /* no line hook and count != 0; nothing to be done now */
- if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
+ if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
@@ -915,7 +954,6 @@
if (L->status == LUA_YIELD) { /* did hook yield? */
if (counthook)
L->hookcount = 1; /* undo decrement to zero */
- ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
luaD_throw(L, LUA_YIELD);
}
src/ldebug.h
@@ -58,6 +58,7 @@
TString *src, int line);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
+LUAI_FUNC int luaG_tracecall (lua_State *L);
#endif
src/ldo.c
@@ -409,7 +409,7 @@
** stack, below original 'func', so that 'luaD_precall' can call it. Raise
** an error if there is no '__call' metafield.
*/
-StkId luaD_tryfuncTM (lua_State *L, StkId func) {
+static StkId tryfuncTM (lua_State *L, StkId func) {
const TValue *tm;
StkId p;
checkstackGCp(L, 1, func); /* space for metamethod */
@@ -568,7 +568,7 @@
return -1;
}
default: { /* not a function */
- func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
+ func = tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */
narg1++;
goto retry; /* try again */
@@ -609,7 +609,7 @@
return ci;
}
default: { /* not a function */
- func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
+ func = tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_precall(L, func, nresults); */
goto retry; /* try again with metamethod */
}
@@ -792,6 +792,10 @@
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */
+ /* undo increment made by 'luaG_traceexec': instruction was not
+ executed yet */
+ lua_assert(ci->callstatus & CIST_HOOKYIELD);
+ ci->u.l.savedpc--;
L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
}
src/ldo.h
@@ -71,7 +71,6 @@
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
-LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func);
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
src/lgc.c
@@ -542,10 +542,12 @@
static lu_mem traversetable (global_State *g, Table *h) {
const char *weakkey, *weakvalue;
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
+ TString *smode;
markobjectN(g, h->metatable);
- if (mode && ttisstring(mode) && /* is there a weak mode? */
- (cast_void(weakkey = strchr(svalue(mode), 'k')),
- cast_void(weakvalue = strchr(svalue(mode), 'v')),
+ if (mode && ttisshrstring(mode) && /* is there a weak mode? */
+ (cast_void(smode = tsvalue(mode)),
+ cast_void(weakkey = strchr(getshrstr(smode), 'k')),
+ cast_void(weakvalue = strchr(getshrstr(smode), 'v')),
(weakkey || weakvalue))) { /* is really weak? */
if (!weakkey) /* strong keys? */
traverseweakvalue(g, h);
@@ -638,7 +640,9 @@
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */
- for (; o < th->stack_last.p + EXTRA_STACK; o++)
+ 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 */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
@@ -646,8 +650,6 @@
g->twups = th;
}
}
- else if (!g->gcemergency)
- luaD_shrinkstack(th); /* do not change stack in emergency cycle */
return 1 + stacksize(th);
}
@@ -1409,7 +1411,7 @@
setminordebt(g);
}
else { /* another bad collection; stay in incremental mode */
- g->GCestimate = gettotalbytes(g); /* first estimate */;
+ g->GCestimate = gettotalbytes(g); /* first estimate */
entersweep(L);
luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
setpause(g);
@@ -1604,7 +1606,7 @@
case GCSenteratomic: {
work = atomic(L); /* work is what was traversed by 'atomic' */
entersweep(L);
- g->GCestimate = gettotalbytes(g); /* first estimate */;
+ g->GCestimate = gettotalbytes(g); /* first estimate */
break;
}
case GCSswpallgc: { /* sweep "regular" objects */
@@ -1710,6 +1712,8 @@
entersweep(L); /* sweep everything to turn them back to white */
/* finish any pending sweep phase to start a new cycle */
luaC_runtilstate(L, bitmask(GCSpause));
+ luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
+ g->gcstate = GCSenteratomic; /* go straight to atomic phase */
luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
/* estimate must be correct after a full GC cycle */
lua_assert(g->GCestimate == gettotalbytes(g));
src/liolib.c
@@ -245,8 +245,8 @@
*/
static int io_fclose (lua_State *L) {
LStream *p = tolstream(L);
- int res = fclose(p->f);
- return luaL_fileresult(L, (res == 0), NULL);
+ errno = 0;
+ return luaL_fileresult(L, (fclose(p->f) == 0), NULL);
}
@@ -272,6 +272,7 @@
LStream *p = newfile(L);
const char *md = mode; /* to traverse/check mode */
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
+ errno = 0;
p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
@@ -292,6 +293,7 @@
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L);
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
+ errno = 0;
p->f = l_popen(L, filename, mode);
p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
@@ -300,6 +302,7 @@
static int io_tmpfile (lua_State *L) {
LStream *p = newfile(L);
+ errno = 0;
p->f = tmpfile();
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
}
@@ -567,6 +570,7 @@
int nargs = lua_gettop(L) - 1;
int n, success;
clearerr(f);
+ errno = 0;
if (nargs == 0) { /* no arguments? */
success = read_line(L, f, 1);
n = first + 1; /* to return 1 result */
@@ -660,6 +664,7 @@
static int g_write (lua_State *L, FILE *f, int arg) {
int nargs = lua_gettop(L) - arg;
int status = 1;
+ errno = 0;
for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
@@ -678,7 +683,8 @@
}
if (l_likely(status))
return 1; /* file handle already on stack top */
- else return luaL_fileresult(L, status, NULL);
+ else
+ return luaL_fileresult(L, status, NULL);
}
@@ -703,6 +709,7 @@
l_seeknum offset = (l_seeknum)p3;
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
"not an integer in proper range");
+ errno = 0;
op = l_fseek(f, offset, mode[op]);
if (l_unlikely(op))
return luaL_fileresult(L, 0, NULL); /* error */
@@ -719,19 +726,25 @@
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
- int res = setvbuf(f, NULL, mode[op], (size_t)sz);
+ int res;
+ errno = 0;
+ res = setvbuf(f, NULL, mode[op], (size_t)sz);
return luaL_fileresult(L, res == 0, NULL);
}
static int io_flush (lua_State *L) {
- return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
+ FILE *f = getiofile(L, IO_OUTPUT);
+ errno = 0;
+ return luaL_fileresult(L, fflush(f) == 0, NULL);
}
static int f_flush (lua_State *L) {
- return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
+ FILE *f = tofile(L);
+ errno = 0;
+ return luaL_fileresult(L, fflush(f) == 0, NULL);
}
@@ -773,7 +786,7 @@
** metamethods for file handles
*/
static const luaL_Reg metameth[] = {
- {"__index", NULL}, /* place holder */
+ {"__index", NULL}, /* placeholder */
{"__gc", f_gc},
{"__close", f_gc},
{"__tostring", f_tostring},
src/lmathlib.c
@@ -249,6 +249,15 @@
** ===================================================================
*/
+/*
+** This code uses lots of shifts. ANSI C does not allow shifts greater
+** than or equal to the width of the type being shifted, so some shifts
+** are written in convoluted ways to match that restriction. For
+** preprocessor tests, it assumes a width of 32 bits, so the maximum
+** shift there is 31 bits.
+*/
+
+
/* number of binary digits in the mantissa of a float */
#define FIGS l_floatatt(MANT_DIG)
@@ -271,16 +280,19 @@
/* 'long' has at least 64 bits */
#define Rand64 unsigned long
+#define SRand64 long
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
/* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long
+#define SRand64 long long
#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
/* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned
+#define SRand64 lua_Integer
#endif
@@ -319,23 +331,30 @@
}
-/* must take care to not shift stuff by more than 63 slots */
-
-
/*
** Convert bits from a random integer into a float in the
** interval [0,1), getting the higher FIG bits from the
** random unsigned integer and converting that to a float.
+** Some old Microsoft compilers cannot cast an unsigned long
+** to a floating-point number, so we use a signed long as an
+** intermediary. When lua_Number is float or double, the shift ensures
+** that 'sx' is non negative; in that case, a good compiler will remove
+** the correction.
*/
/* must throw out the extra (64 - FIGS) bits */
#define shift64_FIG (64 - FIGS)
-/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */
+/* 2^(-FIGS) == 2^-1 / 2^(FIGS-1) */
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
static lua_Number I2d (Rand64 x) {
- return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG;
+ SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG);
+ lua_Number res = (lua_Number)(sx) * scaleFIG;
+ if (sx < 0)
+ res += l_mathop(1.0); /* correct the two's complement if negative */
+ lua_assert(0 <= res && res < 1);
+ return res;
}
/* convert a 'Rand64' to a 'lua_Unsigned' */
@@ -471,8 +490,6 @@
#else /* 32 < FIGS <= 64 */
-/* must take care to not shift stuff by more than 31 slots */
-
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
#define scaleFIG \
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
src/loadlib.c
@@ -25,15 +25,6 @@
/*
-** LUA_IGMARK is a mark to ignore all before it when building the
-** luaopen_ function name.
-*/
-#if !defined (LUA_IGMARK)
-#define LUA_IGMARK "-"
-#endif
-
-
-/*
** LUA_CSUBSEP is the character that replaces dots in submodule names
** when searching for a C loader.
** LUA_LSUBSEP is the character that replaces dots in submodule names
src/lobject.c
@@ -542,7 +542,7 @@
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1);
- return svalue(s2v(L->top.p - 1));
+ return getstr(tsvalue(s2v(L->top.p - 1)));
}
src/lobject.h
@@ -386,7 +386,7 @@
typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
- lu_byte shrlen; /* length for short strings */
+ lu_byte shrlen; /* length for short strings, 0xFF for long strings */
unsigned int hash;
union {
size_t lnglen; /* length for long strings */
@@ -398,19 +398,17 @@
/*
-** Get the actual string (array of bytes) from a 'TString'.
+** Get the actual string (array of bytes) from a 'TString'. (Generic
+** version and specialized versions for long and short strings.)
*/
-#define getstr(ts) ((ts)->contents)
+#define getstr(ts) ((ts)->contents)
+#define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents)
+#define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents)
-/* get the actual string (array of bytes) from a Lua value */
-#define svalue(o) getstr(tsvalue(o))
-
/* get string length from 'TString *s' */
-#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen)
-
-/* get string length from 'TValue *o' */
-#define vslen(o) tsslen(tsvalue(o))
+#define tsslen(s) \
+ ((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen)
/* }================================================================== */
src/lopcodes.h
@@ -210,15 +210,15 @@
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
OP_SETUPVAL,/* A B UpValue[B] := R[A] */
-OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */
+OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:shortstring] */
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
OP_GETI,/* A B C R[A] := R[B][C] */
-OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */
+OP_GETFIELD,/* A B C R[A] := R[B][K[C]:shortstring] */
-OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */
+OP_SETTABUP,/* A B C UpValue[A][K[B]:shortstring] := RK(C) */
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
OP_SETI,/* A B C R[A][B] := RK(C) */
-OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */
+OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */
OP_NEWTABLE,/* A B C k R[A] := {} */
src/loslib.c
@@ -155,6 +155,7 @@
static int os_remove (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
+ errno = 0;
return luaL_fileresult(L, remove(filename) == 0, filename);
}
@@ -162,6 +163,7 @@
static int os_rename (lua_State *L) {
const char *fromname = luaL_checkstring(L, 1);
const char *toname = luaL_checkstring(L, 2);
+ errno = 0;
return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
}
src/lparser.c
@@ -1022,10 +1022,11 @@
}
-static void funcargs (LexState *ls, expdesc *f, int line) {
+static void funcargs (LexState *ls, expdesc *f) {
FuncState *fs = ls->fs;
expdesc args;
int base, nparams;
+ int line = ls->linenumber;
switch (ls->t.token) {
case '(': { /* funcargs -> '(' [ explist ] ')' */
luaX_next(ls);
@@ -1063,8 +1064,8 @@
}
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
luaK_fixline(fs, line);
- fs->freereg = base+1; /* call remove function and arguments and leaves
- (unless changed) one result */
+ fs->freereg = base+1; /* call removes function and arguments and leaves
+ one result (unless changed later) */
}
@@ -1103,7 +1104,6 @@
/* suffixedexp ->
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
FuncState *fs = ls->fs;
- int line = ls->linenumber;
primaryexp(ls, v);
for (;;) {
switch (ls->t.token) {
@@ -1123,12 +1123,12 @@
luaX_next(ls);
codename(ls, &key);
luaK_self(fs, v, &key);
- funcargs(ls, v, line);
+ funcargs(ls, v);
break;
}
case '(': case TK_STRING: case '{': { /* funcargs */
luaK_exp2nextreg(fs, v);
- funcargs(ls, v, line);
+ funcargs(ls, v);
break;
}
default: return;
src/lstate.c
@@ -119,7 +119,7 @@
/*
** free all CallInfo structures not in use by a thread
*/
-void luaE_freeCI (lua_State *L) {
+static void freeCI (lua_State *L) {
CallInfo *ci = L->ci;
CallInfo *next = ci->next;
ci->next = NULL;
@@ -204,7 +204,7 @@
if (L->stack.p == NULL)
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
- luaE_freeCI(L);
+ freeCI(L);
lua_assert(L->nci == 0);
luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
}
@@ -433,7 +433,7 @@
void luaE_warnerror (lua_State *L, const char *where) {
TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj))
- ? svalue(errobj)
+ ? getstr(tsvalue(errobj))
: "error object is not a string";
/* produce warning "error in %s (%s)" (where, msg) */
luaE_warning(L, "error in ", 1);
src/lstate.h
@@ -181,7 +181,7 @@
union {
struct { /* only for Lua functions */
const Instruction *savedpc;
- volatile l_signalT trap;
+ volatile l_signalT trap; /* function is tracing lines/counts */
int nextraargs; /* # of extra arguments in vararg functions */
} l;
struct { /* only for C functions */
@@ -396,7 +396,6 @@
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
-LUAI_FUNC void luaE_freeCI (lua_State *L);
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
LUAI_FUNC void luaE_checkcstack (lua_State *L);
LUAI_FUNC void luaE_incCstack (lua_State *L);
src/lstring.c
@@ -36,7 +36,7 @@
lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
return (a == b) || /* same instance or... */
((len == b->u.lnglen) && /* equal length and ... */
- (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
+ (memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */
}
@@ -52,7 +52,7 @@
lua_assert(ts->tt == LUA_VLNGSTR);
if (ts->extra == 0) { /* no hash? */
size_t len = ts->u.lnglen;
- ts->hash = luaS_hash(getstr(ts), len, ts->hash);
+ ts->hash = luaS_hash(getlngstr(ts), len, ts->hash);
ts->extra = 1; /* now it has its hash */
}
return ts->hash;
@@ -157,6 +157,7 @@
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed);
ts->u.lnglen = l;
+ ts->shrlen = 0xFF; /* signals that it is a long string */
return ts;
}
@@ -193,7 +194,7 @@
TString **list = &tb->hash[lmod(h, tb->size)];
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
- if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
+ if (l == ts->shrlen && (memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) {
/* found! */
if (isdead(g, ts)) /* dead (but not collected yet)? */
changewhite(ts); /* resurrect it */
@@ -206,8 +207,8 @@
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
}
ts = createstrobj(L, l, LUA_VSHRSTR, h);
- memcpy(getstr(ts), str, l * sizeof(char));
ts->shrlen = cast_byte(l);
+ memcpy(getshrstr(ts), str, l * sizeof(char));
ts->u.hnext = *list;
*list = ts;
tb->nuse++;
@@ -223,10 +224,10 @@
return internshrstr(L, str, l);
else {
TString *ts;
- if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
+ if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString))))
luaM_toobig(L);
ts = luaS_createlngstrobj(L, l);
- memcpy(getstr(ts), str, l * sizeof(char));
+ memcpy(getlngstr(ts), str, l * sizeof(char));
return ts;
}
}
src/ltable.c
@@ -252,7 +252,7 @@
return t->alimit; /* this is the size */
else {
unsigned int size = t->alimit;
- /* compute the smallest power of 2 not smaller than 'n' */
+ /* compute the smallest power of 2 not smaller than 'size' */
size |= (size >> 1);
size |= (size >> 2);
size |= (size >> 4);
@@ -662,7 +662,8 @@
** put new key in its main position; otherwise (colliding node is in its main
** position), new key goes to an empty position.
*/
-void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
+static void luaH_newkey (lua_State *L, Table *t, const TValue *key,
+ TValue *value) {
Node *mp;
TValue aux;
if (l_unlikely(ttisnil(key)))
@@ -721,22 +722,36 @@
/*
** Search function for integers. If integer is inside 'alimit', get it
-** directly from the array part. Otherwise, if 'alimit' is not equal to
-** the real size of the array, key still can be in the array part. In
-** this case, try to avoid a call to 'luaH_realasize' when key is just
-** one more than the limit (so that it can be incremented without
-** changing the real size of the array).
+** directly from the array part. Otherwise, if 'alimit' is not
+** the real size of the array, the key still can be in the array part.
+** In this case, do the "Xmilia trick" to check whether 'key-1' is
+** smaller than the real size.
+** The trick works as follow: let 'p' be an integer such that
+** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'.
+** That is, 2^(p+1) is the real size of the array, and 'p' is the highest
+** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'.
+** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will
+** have the 'p' bit cleared. If the key is outside the array, that is,
+** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p',
+** therefore it will be larger or equal to 'alimit', and the check
+** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than
+** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller
+** than 2^p, therefore smaller than 'alimit', and the check succeeds.
+** As special cases, when 'alimit' is 0 the condition is trivially false,
+** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'.
+** If key is 0 or negative, 'res' will have its higher bit on, so that
+** if cannot be smaller than alimit.
*/
const TValue *luaH_getint (Table *t, lua_Integer key) {
- if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */
+ lua_Unsigned alimit = t->alimit;
+ if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */
return &t->array[key - 1];
- else if (!limitequalsasize(t) && /* key still may be in the array part? */
- (l_castS2U(key) == t->alimit + 1 ||
- l_castS2U(key) - 1u < luaH_realasize(t))) {
+ else if (!isrealasize(t) && /* key still may be in the array part? */
+ (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) {
t->alimit = cast_uint(key); /* probably '#t' is here now */
return &t->array[key - 1];
}
- else {
+ else { /* key is not in the array part; check the hash */
Node *n = hashint(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (keyisinteger(n) && keyival(n) == key)
src/ltable.h
@@ -41,8 +41,6 @@
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
-LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
- TValue *value);
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
TValue *value);
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
src/ltm.h
@@ -9,7 +9,6 @@
#include "lobject.h"
-#include "lstate.h"
/*
@@ -96,8 +95,8 @@
int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
- CallInfo *ci, const Proto *p);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
+ struct CallInfo *ci, const Proto *p);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
StkId where, int wanted);
src/lua.c
@@ -115,12 +115,13 @@
/*
** Check whether 'status' is not OK and, if so, prints the error
-** message on the top of the stack. It assumes that the error object
-** is a string, as it was either generated by Lua or by 'msghandler'.
+** message on the top of the stack.
*/
static int report (lua_State *L, int status) {
if (status != LUA_OK) {
const char *msg = lua_tostring(L, -1);
+ if (msg == NULL)
+ msg = "(error message not a string)";
l_message(progname, msg);
lua_pop(L, 1); /* remove message */
}
@@ -210,12 +211,17 @@
/*
** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
+** If there is no explicit modname and globname contains a '-', cut
+** the suffix after '-' (the "version") to make the global name.
*/
static int dolibrary (lua_State *L, char *globname) {
int status;
+ char *suffix = NULL;
char *modname = strchr(globname, '=');
- if (modname == NULL) /* no explicit name? */
+ if (modname == NULL) { /* no explicit name? */
modname = globname; /* module name is equal to global name */
+ suffix = strchr(modname, *LUA_IGMARK); /* look for a suffix mark */
+ }
else {
*modname = '\0'; /* global name ends here */
modname++; /* module name starts after the '=' */
@@ -223,8 +229,11 @@
lua_getglobal(L, "require");
lua_pushstring(L, modname);
status = docall(L, 1, 1); /* call 'require(modname)' */
- if (status == LUA_OK)
+ if (status == LUA_OK) {
+ if (suffix != NULL) /* is there a suffix mark? */
+ *suffix = '\0'; /* remove suffix from global name */
lua_setglobal(L, globname); /* globname = require(modname) */
+ }
return report(L, status);
}
src/lua.h
@@ -18,14 +18,14 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
-#define LUA_VERSION_RELEASE "6"
+#define LUA_VERSION_RELEASE "7"
#define LUA_VERSION_NUM 504
-#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
+#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 7)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2024 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -497,7 +497,7 @@
/******************************************************************************
-* Copyright (C) 1994-2023 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2024 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
src/luaconf.h
@@ -257,6 +257,15 @@
#endif
+
+/*
+** LUA_IGMARK is a mark to ignore all after it when building the
+** module name (e.g., used to build the luaopen_ function name).
+** Typically, the suffix after the mark is the module version,
+** as in "mod-v1.2.so".
+*/
+#define LUA_IGMARK "-"
+
/* }================================================================== */
src/lundump.c
@@ -81,7 +81,7 @@
static size_t loadSize (LoadState *S) {
- return loadUnsigned(S, ~(size_t)0);
+ return loadUnsigned(S, MAX_SIZET);
}
@@ -122,7 +122,7 @@
ts = luaS_createlngstrobj(L, size); /* create string */
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
- loadVector(S, getstr(ts), size); /* load directly in final place */
+ loadVector(S, getlngstr(ts), size); /* load directly in final place */
L->top.p--; /* pop string */
}
luaC_objbarrier(L, p, ts);
src/lundump.h
@@ -21,8 +21,7 @@
/*
** Encode major-minor version in one byte, one nibble for each
*/
-#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */
-#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
+#define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100)
#define LUAC_FORMAT 0 /* this is the official format */
src/lvm.c
@@ -91,8 +91,10 @@
lua_assert(obj != result);
if (!cvt2num(obj)) /* is object not a string? */
return 0;
- else
- return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1);
+ else {
+ TString *st = tsvalue(obj);
+ return (luaO_str2num(getstr(st), result) == tsslen(st) + 1);
+ }
}
@@ -366,30 +368,32 @@
/*
-** Compare two strings 'ls' x 'rs', returning an integer less-equal-
-** -greater than zero if 'ls' is less-equal-greater than 'rs'.
+** Compare two strings 'ts1' x 'ts2', returning an integer less-equal-
+** -greater than zero if 'ts1' is less-equal-greater than 'ts2'.
** The code is a little tricky because it allows '\0' in the strings
-** and it uses 'strcoll' (to respect locales) for each segments
-** of the strings.
-*/
-static int l_strcmp (const TString *ls, const TString *rs) {
- const char *l = getstr(ls);
- size_t ll = tsslen(ls);
- const char *r = getstr(rs);
- size_t lr = tsslen(rs);
+** and it uses 'strcoll' (to respect locales) for each segment
+** of the strings. Note that segments can compare equal but still
+** have different lengths.
+*/
+static int l_strcmp (const TString *ts1, const TString *ts2) {
+ const char *s1 = getstr(ts1);
+ size_t rl1 = tsslen(ts1); /* real length */
+ const char *s2 = getstr(ts2);
+ size_t rl2 = tsslen(ts2);
for (;;) { /* for each segment */
- int temp = strcoll(l, r);
+ int temp = strcoll(s1, s2);
if (temp != 0) /* not equal? */
return temp; /* done */
else { /* strings are equal up to a '\0' */
- size_t len = strlen(l); /* index of first '\0' in both strings */
- if (len == lr) /* 'rs' is finished? */
- return (len == ll) ? 0 : 1; /* check 'ls' */
- else if (len == ll) /* 'ls' is finished? */
- return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */
- /* both strings longer than 'len'; go on comparing after the '\0' */
- len++;
- l += len; ll -= len; r += len; lr -= len;
+ size_t zl1 = strlen(s1); /* index of first '\0' in 's1' */
+ size_t zl2 = strlen(s2); /* index of first '\0' in 's2' */
+ if (zl2 == rl2) /* 's2' is finished? */
+ return (zl1 == rl1) ? 0 : 1; /* check 's1' */
+ else if (zl1 == rl1) /* 's1' is finished? */
+ return -1; /* 's1' is less than 's2' ('s2' is not finished) */
+ /* both strings longer than 'zl'; go on comparing after the '\0' */
+ zl1++; zl2++;
+ s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2;
}
}
}
@@ -624,8 +628,9 @@
static void copy2buff (StkId top, int n, char *buff) {
size_t tl = 0; /* size already copied */
do {
- size_t l = vslen(s2v(top - n)); /* length of string being copied */
- memcpy(buff + tl, svalue(s2v(top - n)), l * sizeof(char));
+ TString *st = tsvalue(s2v(top - n));
+ size_t l = tsslen(st); /* length of string being copied */
+ memcpy(buff + tl, getstr(st), l * sizeof(char));
tl += l;
} while (--n > 0);
}
@@ -651,12 +656,12 @@
}
else {
/* at least two non-empty string values; get as many as possible */
- size_t tl = vslen(s2v(top - 1));
+ size_t tl = tsslen(tsvalue(s2v(top - 1)));
TString *ts;
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
- size_t l = vslen(s2v(top - n - 1));
- if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
+ size_t l = tsslen(tsvalue(s2v(top - n - 1)));
+ if (l_unlikely(l >= MAX_SIZE - sizeof(TString) - tl)) {
L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow");
}
@@ -669,7 +674,7 @@
}
else { /* long string; copy strings directly to final result */
ts = luaS_createlngstrobj(L, tl);
- copy2buff(top, n, getstr(ts));
+ copy2buff(top, n, getlngstr(ts));
}
setsvalue2s(L, top - n, ts); /* create result */
}
@@ -1155,18 +1160,11 @@
startfunc:
trap = L->hookmask;
returning: /* trap already set */
- cl = clLvalue(s2v(ci->func.p));
+ cl = ci_func(ci);
k = cl->p->k;
pc = ci->u.l.savedpc;
- if (l_unlikely(trap)) {
- if (pc == cl->p->code) { /* first instruction (not resuming)? */
- if (cl->p->is_vararg)
- trap = 0; /* hooks will start after VARARGPREP instruction */
- else /* check 'call' hook */
- luaD_hookcall(L, ci);
- }
- ci->u.l.trap = 1; /* assume trap is on, for now */
- }
+ if (l_unlikely(trap))
+ trap = luaG_tracecall(L);
base = ci->func.p + 1;
/* main loop of interpreter */
for (;;) {
@@ -1253,7 +1251,7 @@
const TValue *slot;
TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
- TString *key = tsvalue(rc); /* key must be a string */
+ TString *key = tsvalue(rc); /* key must be a short string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
setobj2s(L, ra, slot);
}
@@ -1296,7 +1294,7 @@
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = KC(i);
- TString *key = tsvalue(rc); /* key must be a string */
+ TString *key = tsvalue(rc); /* key must be a short string */
if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) {
setobj2s(L, ra, slot);
}
@@ -1309,7 +1307,7 @@
TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
- TString *key = tsvalue(rb); /* key must be a string */
+ TString *key = tsvalue(rb); /* key must be a short string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
luaV_finishfastset(L, upval, slot, rc);
}
@@ -1352,7 +1350,7 @@
const TValue *slot;
TValue *rb = KB(i);
TValue *rc = RKC(i);
- TString *key = tsvalue(rb); /* key must be a string */
+ TString *key = tsvalue(rb); /* key must be a short string */
if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) {
luaV_finishfastset(L, s2v(ra), slot, rc);
}