Browse Source

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.
Roberto Ierusalimschy 5 months ago
parent
commit
ee99452158
4 changed files with 23 additions and 8 deletions
  1. 3 1
      ldebug.c
  2. 7 3
      ldo.c
  3. 10 1
      manual/manual.of
  4. 3 3
      testes/errors.lua

+ 3 - 1
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' */

+ 7 - 3
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 */
 }
 
 

+ 10 - 1
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.
+}
+
 }
 
 }

+ 3 - 3
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)