lua

A copy of the Lua development repository
Log | Files | Refs | README

commit ee99452158de5e2fa804bd10de7669848f3b3952
parent 127a8e80fe0d74efd26994b3877cdc77b712ea56
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Fri, 28 Feb 2025 14:53:31 -0300

Error object cannot be nil

Lua will change a nil as error object to a string message, so that it
never reports an error with nil as the error object.

Diffstat:
Mldebug.c | 4+++-
Mldo.c | 10+++++++---
Mmanual/manual.of | 11++++++++++-
Mtestes/errors.lua | 6+++---
4 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/ldebug.c b/ldebug.c @@ -844,7 +844,9 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); /* format message */ va_end(argp); - if (msg != NULL && isLua(ci)) { /* Lua function? (and no error) */ + if (msg == NULL) /* no memory to format message? */ + luaD_throw(L, LUA_ERRMEM); + else if (isLua(ci)) { /* Lua function? */ /* add source:line information */ luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */ diff --git a/ldo.c b/ldo.c @@ -112,12 +112,16 @@ void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop) { break; } default: { - lua_assert(errorstatus(errcode)); /* real error */ - setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */ + lua_assert(errorstatus(errcode)); /* must be a real error */ + if (!ttisnil(s2v(L->top.p - 1))) { /* error object is not nil? */ + setobjs2s(L, oldtop, L->top.p - 1); /* move it to 'oldtop' */ + } + else /* change it to a proper message */ + setsvalue2s(L, oldtop, luaS_newliteral(L, "<error object is nil>")); break; } } - L->top.p = oldtop + 1; + L->top.p = oldtop + 1; /* top goes back to old top plus error object */ } diff --git a/manual/manual.of b/manual/manual.of @@ -290,7 +290,9 @@ an @def{error object} is propagated with information about the error. Lua itself only generates errors whose error object is a string, but programs can generate errors with -any value as the error object. +any value as the error object, +except @nil. +(Lua will change a @nil as error object to a string message.) It is up to the Lua program or its host to handle such error objects. For historical reasons, an error object is often called an @def{error message}, @@ -8082,6 +8084,8 @@ multiple assignment: The default for @id{a2} is @id{a1}. The destination range can overlap with the source range. The number of elements to be moved must fit in a Lua integer. +If @id{f} is larger than @id{e}, +nothing is moved. Returns the destination table @id{a2}. @@ -9402,6 +9406,11 @@ declare a local variable with the same name in the loop body. A chain of @id{__call} metamethods can have at most 15 objects. } +@item{ +In an error, a @nil as the error object is replaced by a +string message. +} + } } diff --git a/testes/errors.lua b/testes/errors.lua @@ -46,7 +46,7 @@ end assert(doit("error('hi', 0)") == 'hi') -- test nil error message -assert(doit("error()") == nil) +assert(doit("error()") == "<error object is nil>") -- test common errors/errors that crashed in the past @@ -614,7 +614,7 @@ do assert(not res and msg == t) res, msg = pcall(function () error(nil) end) - assert(not res and msg == nil) + assert(not res and msg == "<error object is nil>") local function f() error{msg='x'} end res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end) @@ -634,7 +634,7 @@ do assert(not res and msg == t) res, msg = pcall(assert, nil, nil) - assert(not res and msg == nil) + assert(not res and type(msg) == "string") -- 'assert' without arguments res, msg = pcall(assert)