aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-02-28 14:53:58 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-02-28 14:53:58 -0300
commitee99452158de5e2fa804bd10de7669848f3b3952 (patch)
treea68b8834ef0f61f9a7a2ce297ab3963cec8e56d9
parent127a8e80fe0d74efd26994b3877cdc77b712ea56 (diff)
downloadlua-ee99452158de5e2fa804bd10de7669848f3b3952.tar.gz
lua-ee99452158de5e2fa804bd10de7669848f3b3952.tar.bz2
lua-ee99452158de5e2fa804bd10de7669848f3b3952.zip
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.
-rw-r--r--ldebug.c4
-rw-r--r--ldo.c10
-rw-r--r--manual/manual.of11
-rw-r--r--testes/errors.lua6
4 files changed, 23 insertions, 8 deletions
diff --git a/ldebug.c b/ldebug.c
index af3b7583..18bdc595 100644
--- a/ldebug.c
+++ b/ldebug.c
@@ -844,7 +844,9 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
844 va_start(argp, fmt); 844 va_start(argp, fmt);
845 msg = luaO_pushvfstring(L, fmt, argp); /* format message */ 845 msg = luaO_pushvfstring(L, fmt, argp); /* format message */
846 va_end(argp); 846 va_end(argp);
847 if (msg != NULL && isLua(ci)) { /* Lua function? (and no error) */ 847 if (msg == NULL) /* no memory to format message? */
848 luaD_throw(L, LUA_ERRMEM);
849 else if (isLua(ci)) { /* Lua function? */
848 /* add source:line information */ 850 /* add source:line information */
849 luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); 851 luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
850 setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */ 852 setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
diff --git a/ldo.c b/ldo.c
index 3ddc5a4c..84f7bbb2 100644
--- a/ldo.c
+++ b/ldo.c
@@ -112,12 +112,16 @@ void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop) {
112 break; 112 break;
113 } 113 }
114 default: { 114 default: {
115 lua_assert(errorstatus(errcode)); /* real error */ 115 lua_assert(errorstatus(errcode)); /* must be a real error */
116 setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */ 116 if (!ttisnil(s2v(L->top.p - 1))) { /* error object is not nil? */
117 setobjs2s(L, oldtop, L->top.p - 1); /* move it to 'oldtop' */
118 }
119 else /* change it to a proper message */
120 setsvalue2s(L, oldtop, luaS_newliteral(L, "<error object is nil>"));
117 break; 121 break;
118 } 122 }
119 } 123 }
120 L->top.p = oldtop + 1; 124 L->top.p = oldtop + 1; /* top goes back to old top plus error object */
121} 125}
122 126
123 127
diff --git a/manual/manual.of b/manual/manual.of
index ff4e79fe..b34e1e9c 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -290,7 +290,9 @@ an @def{error object}
290is propagated with information about the error. 290is propagated with information about the error.
291Lua itself only generates errors whose error object is a string, 291Lua itself only generates errors whose error object is a string,
292but programs can generate errors with 292but programs can generate errors with
293any value as the error object. 293any value as the error object,
294except @nil.
295(Lua will change a @nil as error object to a string message.)
294It is up to the Lua program or its host to handle such error objects. 296It is up to the Lua program or its host to handle such error objects.
295For historical reasons, 297For historical reasons,
296an error object is often called an @def{error message}, 298an error object is often called an @def{error message},
@@ -8082,6 +8084,8 @@ multiple assignment:
8082The default for @id{a2} is @id{a1}. 8084The default for @id{a2} is @id{a1}.
8083The destination range can overlap with the source range. 8085The destination range can overlap with the source range.
8084The number of elements to be moved must fit in a Lua integer. 8086The number of elements to be moved must fit in a Lua integer.
8087If @id{f} is larger than @id{e},
8088nothing is moved.
8085 8089
8086Returns the destination table @id{a2}. 8090Returns the destination table @id{a2}.
8087 8091
@@ -9402,6 +9406,11 @@ declare a local variable with the same name in the loop body.
9402A chain of @id{__call} metamethods can have at most 15 objects. 9406A chain of @id{__call} metamethods can have at most 15 objects.
9403} 9407}
9404 9408
9409@item{
9410In an error, a @nil as the error object is replaced by a
9411string message.
9412}
9413
9405} 9414}
9406 9415
9407} 9416}
diff --git a/testes/errors.lua b/testes/errors.lua
index adc111fd..5fdb7722 100644
--- a/testes/errors.lua
+++ b/testes/errors.lua
@@ -46,7 +46,7 @@ end
46assert(doit("error('hi', 0)") == 'hi') 46assert(doit("error('hi', 0)") == 'hi')
47 47
48-- test nil error message 48-- test nil error message
49assert(doit("error()") == nil) 49assert(doit("error()") == "<error object is nil>")
50 50
51 51
52-- test common errors/errors that crashed in the past 52-- test common errors/errors that crashed in the past
@@ -614,7 +614,7 @@ do
614 assert(not res and msg == t) 614 assert(not res and msg == t)
615 615
616 res, msg = pcall(function () error(nil) end) 616 res, msg = pcall(function () error(nil) end)
617 assert(not res and msg == nil) 617 assert(not res and msg == "<error object is nil>")
618 618
619 local function f() error{msg='x'} end 619 local function f() error{msg='x'} end
620 res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end) 620 res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
@@ -634,7 +634,7 @@ do
634 assert(not res and msg == t) 634 assert(not res and msg == t)
635 635
636 res, msg = pcall(assert, nil, nil) 636 res, msg = pcall(assert, nil, nil)
637 assert(not res and msg == nil) 637 assert(not res and type(msg) == "string")
638 638
639 -- 'assert' without arguments 639 -- 'assert' without arguments
640 res, msg = pcall(assert) 640 res, msg = pcall(assert)