diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-02-28 14:53:58 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-02-28 14:53:58 -0300 |
commit | ee99452158de5e2fa804bd10de7669848f3b3952 (patch) | |
tree | a68b8834ef0f61f9a7a2ce297ab3963cec8e56d9 | |
parent | 127a8e80fe0d74efd26994b3877cdc77b712ea56 (diff) | |
download | lua-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.c | 4 | ||||
-rw-r--r-- | ldo.c | 10 | ||||
-rw-r--r-- | manual/manual.of | 11 | ||||
-rw-r--r-- | testes/errors.lua | 6 |
4 files changed, 23 insertions, 8 deletions
@@ -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' */ |
@@ -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} | |||
290 | is propagated with information about the error. | 290 | is propagated with information about the error. |
291 | Lua itself only generates errors whose error object is a string, | 291 | Lua itself only generates errors whose error object is a string, |
292 | but programs can generate errors with | 292 | but programs can generate errors with |
293 | any value as the error object. | 293 | any value as the error object, |
294 | except @nil. | ||
295 | (Lua will change a @nil as error object to a string message.) | ||
294 | It is up to the Lua program or its host to handle such error objects. | 296 | It is up to the Lua program or its host to handle such error objects. |
295 | For historical reasons, | 297 | For historical reasons, |
296 | an error object is often called an @def{error message}, | 298 | an error object is often called an @def{error message}, |
@@ -8082,6 +8084,8 @@ multiple assignment: | |||
8082 | The default for @id{a2} is @id{a1}. | 8084 | The default for @id{a2} is @id{a1}. |
8083 | The destination range can overlap with the source range. | 8085 | The destination range can overlap with the source range. |
8084 | The number of elements to be moved must fit in a Lua integer. | 8086 | The number of elements to be moved must fit in a Lua integer. |
8087 | If @id{f} is larger than @id{e}, | ||
8088 | nothing is moved. | ||
8085 | 8089 | ||
8086 | Returns the destination table @id{a2}. | 8090 | Returns the destination table @id{a2}. |
8087 | 8091 | ||
@@ -9402,6 +9406,11 @@ declare a local variable with the same name in the loop body. | |||
9402 | A chain of @id{__call} metamethods can have at most 15 objects. | 9406 | A chain of @id{__call} metamethods can have at most 15 objects. |
9403 | } | 9407 | } |
9404 | 9408 | ||
9409 | @item{ | ||
9410 | In an error, a @nil as the error object is replaced by a | ||
9411 | string 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 | |||
46 | assert(doit("error('hi', 0)") == 'hi') | 46 | assert(doit("error('hi', 0)") == 'hi') |
47 | 47 | ||
48 | -- test nil error message | 48 | -- test nil error message |
49 | assert(doit("error()") == nil) | 49 | assert(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) |