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