Compare commits

...

11 Commits

Author SHA1 Message Date
Roberto Ierusalimschy
1ab3208a1f 'lua.h' back to redundancy in version definitions
Several tools inspect 'lua.h' to extract version information, and
they assume the file will have some specific format.
2024-06-13 15:13:52 -03:00
Roberto Ierusalimschy
21ff8de33a Bug: Tricky _PROMPT may trigger undefined behavior 2024-06-05 13:37:16 -03:00
Roberto Ierusalimschy
7eb1ed21b7 More permissive use of 'errno'
Assume that no function will put garbage on errno (although ISO C allows
that). If any function during an operation set errno, and the operation
result in an error, assume that errno has something to say.
2024-06-05 11:50:42 -03:00
Roberto Ierusalimschy
2db966fcbf Bug: luaL_traceback may need more than 5 stack slots 2024-06-04 16:40:53 -03:00
Roberto Ierusalimschy
ae9a0cbbb4 Bug: overlapping assignments
ISO C forbids assignment of a union field to another field of the same
union.
2024-06-04 12:52:52 -03:00
Roberto Ierusalimschy
d5212c13b0 More disciplined use of 'errno'
Set errno to zero before calling any function where we may use its
errno, and check errno for zero before using it (as functions may
not set it even in error).
2024-06-04 12:48:29 -03:00
Roberto Ierusalimschy
e0efebdbe4 Detail in the manual
Function 'lua_toclose' can raise a non-memory error (but not a
memory error).
2024-05-14 17:59:54 -03:00
Roberto Ierusalimschy
e84f7bf198 Details
Typos in comments.
2024-05-13 13:23:45 -03:00
Roberto Ierusalimschy
dfbde4c7d5 Bug: Active-lines for stripped vararg functions
Lua seg. faults when asked to create the 'activelines' table for a
vararg function with no debug information.
2024-05-13 13:10:35 -03:00
Roberto Ierusalimschy
de794a6527 Towards release 5.4.7 2024-04-26 14:55:18 -03:00
Roberto Ierusalimschy
8b83417de9 Avoids a warning when lua_Number is 'float' 2024-02-07 14:17:03 -03:00
18 changed files with 130 additions and 80 deletions

View File

@@ -80,6 +80,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
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 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
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 const char *getF (lua_State *L, void *ud, size_t *size) {
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 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
}
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 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
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 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
}
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 const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
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;

View File

@@ -776,7 +776,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
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;
}
@@ -1283,8 +1284,9 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
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) {
int temp = t->u.info; /* upvalue index */
lua_assert(isKstr(fs, k));
t->u.ind.t = t->u.info; /* upvalue index */
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;
}

View File

@@ -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 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
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 int nextline (const Proto *p, int currentline, int pc) {
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 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
}
case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
if (noLuaClosure(f)) {
if (!LuaClosure(f)) {
ar->isvararg = 1;
ar->nparams = 0;
}

2
lgc.c
View File

@@ -1713,7 +1713,7 @@ static void fullinc (lua_State *L, global_State *g) {
/* 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 ??? */
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));

View File

@@ -245,8 +245,8 @@ static int f_gc (lua_State *L) {
*/
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 @@ static int io_open (lua_State *L) {
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 @@ static int io_popen (lua_State *L) {
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_popen (lua_State *L) {
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 @@ static int g_read (lua_State *L, FILE *f, int first) {
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 io_readline (lua_State *L) {
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 @@ static int g_write (lua_State *L, FILE *f, int arg) {
}
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 @@ static int f_seek (lua_State *L) {
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 @@ static int f_setvbuf (lua_State *L) {
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 @@ static const luaL_Reg meth[] = {
** 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},

View File

@@ -352,7 +352,7 @@ static lua_Number I2d (Rand64 x) {
SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG);
lua_Number res = (lua_Number)(sx) * scaleFIG;
if (sx < 0)
res += 1.0; /* correct the two's complement if negative */
res += l_mathop(1.0); /* correct the two's complement if negative */
lua_assert(0 <= res && res < 1);
return res;
}

View File

@@ -155,6 +155,7 @@ static int os_execute (lua_State *L) {
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_remove (lua_State *L) {
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);
}

View File

@@ -1650,6 +1650,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
int nres;
status = lua_resume(lua_tothread(L1, i), L, getnum, &nres);
}
else if EQ("traceback") {
const char *msg = getstring;
int level = getnum;
luaL_traceback(L1, L1, msg, level);
}
else if EQ("return") {
int n = getnum;
if (L1 != L) {

9
lua.c
View File

@@ -115,12 +115,13 @@ static void l_message (const char *pname, const char *msg) {
/*
** 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 */
}
@@ -211,7 +212,7 @@ static int dostring (lua_State *L, const char *s, const char *name) {
/*
** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
** If there is no explicit modname and globname contains a '-', cut
** the sufix after '-' (the "version") to make the global name.
** the suffix after '-' (the "version") to make the global name.
*/
static int dolibrary (lua_State *L, char *globname) {
int status;
@@ -230,7 +231,7 @@ static int dolibrary (lua_State *L, char *globname) {
status = docall(L, 1, 1); /* call 'require(modname)' */
if (status == LUA_OK) {
if (suffix != NULL) /* is there a suffix mark? */
*suffix = '\0'; /* remove sufix from global name */
*suffix = '\0'; /* remove suffix from global name */
lua_setglobal(L, globname); /* globname = require(modname) */
}
return report(L, status);

40
lua.h
View File

@@ -1,7 +1,7 @@
/*
** $Id: lua.h $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (www.lua.org)
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
@@ -13,21 +13,22 @@
#include <stddef.h>
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
#define LUA_VERSION_MAJOR_N 5
#define LUA_VERSION_MINOR_N 4
#define LUA_VERSION_RELEASE_N 6
#define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N)
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N)
#include "luaconf.h"
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "7"
#define LUA_VERSION_NUM 504
#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-2024 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
/* mark for precompiled code ('<esc>Lua') */
#define LUA_SIGNATURE "\x1bLua"
@@ -495,19 +496,8 @@ struct lua_Debug {
/* }====================================================================== */
#define LUAI_TOSTRAUX(x) #x
#define LUAI_TOSTR(x) LUAI_TOSTRAUX(x)
#define LUA_VERSION_MAJOR LUAI_TOSTR(LUA_VERSION_MAJOR_N)
#define LUA_VERSION_MINOR LUAI_TOSTR(LUA_VERSION_MINOR_N)
#define LUA_VERSION_RELEASE LUAI_TOSTR(LUA_VERSION_RELEASE_N)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
/******************************************************************************
* 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

View File

@@ -261,7 +261,7 @@
/*
** 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 sufix after the mark is the module version,
** Typically, the suffix after the mark is the module version,
** as in "mod-v1.2.so".
*/
#define LUA_IGMARK "-"

View File

@@ -21,7 +21,7 @@
/*
** Encode major-minor version in one byte, one nibble for each
*/
#define LUAC_VERSION (LUA_VERSION_MAJOR_N*16+LUA_VERSION_MINOR_N)
#define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100)
#define LUAC_FORMAT 0 /* this is the official format */

2
lvm.c
View File

@@ -92,7 +92,7 @@ static int l_strton (const TValue *obj, TValue *result) {
if (!cvt2num(obj)) /* is object not a string? */
return 0;
else {
TString *st = tsvalue(obj);
TString *st = tsvalue(obj);
return (luaO_str2num(getstr(st), result) == tsslen(st) + 1);
}
}

View File

@@ -30,7 +30,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p>
<small>
<a href="http://www.lua.org/copyright.html">Copyright</a>
&copy; 2023 Lua.org, PUC-Rio. All rights reserved.
&copy; 2024 Lua.org, PUC-Rio. All rights reserved.
</small>
<hr>

View File

@@ -289,7 +289,7 @@ Whenever there is an error,
an @def{error object}
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,
@@ -298,7 +298,7 @@ even though it does not have to be a string.
When you use @Lid{xpcall} (or @Lid{lua_pcall}, in C)
you may give a @def{message handler}
you can give a @def{message handler}
to be called in case of errors.
This function is called with the original error object
and returns a new error object.
@@ -343,7 +343,7 @@ which is then called a @def{metamethod}.
In the previous example, the key is the string @St{__add}
and the metamethod is the function that performs the addition.
Unless stated otherwise,
a metamethod may in fact be any @x{callable value},
a metamethod can in fact be any @x{callable value},
which is either a function or a value with a @idx{__call} metamethod.
You can query the metatable of any value
@@ -1417,7 +1417,7 @@ labels in Lua are considered statements too:
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,
@@ -4416,7 +4416,7 @@ otherwise, returns @id{NULL}.
}
@APIEntry{void lua_toclose (lua_State *L, int index);|
@apii{0,0,m}
@apii{0,0,v}
Marks the given index in the stack as a
to-be-closed slot @see{to-be-closed}.
@@ -4433,6 +4433,9 @@ A slot marked as to-be-closed should not be removed from the stack
by any other function in the API except @Lid{lua_settop} or @Lid{lua_pop},
unless previously deactivated by @Lid{lua_closeslot}.
This function raises an error if the value at the given slot
neither has a @idx{__close} metamethod nor is a false value.
This function should not be called for an index
that is equal to or below an active to-be-closed slot.
@@ -4488,7 +4491,7 @@ but can contain other zeros in its body.
This function can raise memory errors only
when converting a number to a string
(as then it has to create a new string).
(as then it may create a new string).
}
@@ -8773,13 +8776,13 @@ The returned table can contain all the fields returned by @Lid{lua_getinfo},
with the string @id{what} describing which fields to fill in.
The default for @id{what} is to get all information available,
except the table of valid lines.
If present,
the option @Char{f}
The option @Char{f}
adds a field named @id{func} with the function itself.
If present,
the option @Char{L}
adds a field named @id{activelines} with the table of
valid lines.
The option @Char{L} adds a field named @id{activelines}
with the table of valid lines,
provided the function is a Lua function.
If the function has no debug information,
the table is empty.
For instance, the expression @T{debug.getinfo(1,"n").name} returns
a name for the current function,

View File

@@ -49,6 +49,15 @@ do
end
-- bug in 5.4.4-5.4.6: activelines in vararg functions
-- without debug information
do
local func = load(string.dump(load("print(10)"), true))
local actl = debug.getinfo(func, "L").activelines
assert(#actl == 0) -- no line info
end
-- test file and string names truncation
local a = "function f () end"
local function dostring (s, x) return load(s, x)() end

View File

@@ -91,7 +91,7 @@ end
if not T then
(Message or print)
('\n >>> testC not active: skipping memory message test <<<\n')
('\n >>> testC not active: skipping tests for messages in C <<<\n')
else
print "testing memory error message"
local a = {}
@@ -104,6 +104,19 @@ else
end)
T.totalmem(0)
assert(not st and msg == "not enough" .. " memory")
-- stack space for luaL_traceback (bug in 5.4.6)
local res = T.testC[[
# push 16 elements on the stack
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
pushnum 1;
# traceback should work with 4 remaining slots
traceback xuxu 1;
return 1
]]
assert(string.find(res, "xuxu.-main chunk"))
end

View File

@@ -56,7 +56,8 @@ assert(f(" \n\r*&\n\r xuxu \n\n", "%g%g%g+") == "xuxu")
-- Adapt a pattern to UTF-8
local function PU (p)
-- break '?' into each individual byte of a character
-- reapply '?' into each individual byte of a character.
-- (For instance, "á?" becomes "\195?\161?".)
p = string.gsub(p, "(" .. utf8.charpattern .. ")%?", function (c)
return string.gsub(c, ".", "%0?")
end)