mirror of https://github.com/rusefi/lua.git
Supressed errors in '__close' generate warnings
This commit is contained in:
parent
a1d8eb2743
commit
ca13be9af7
|
@ -1010,9 +1010,9 @@ static int panic (lua_State *L) {
|
||||||
static void warnf (void *ud, const char *message, int tocont) {
|
static void warnf (void *ud, const char *message, int tocont) {
|
||||||
int *warnstate = (int *)ud;
|
int *warnstate = (int *)ud;
|
||||||
if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */
|
if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */
|
||||||
if (strcmp(message + 1, "off") == 0)
|
if (strcmp(message, "@off") == 0)
|
||||||
*warnstate = 0;
|
*warnstate = 0;
|
||||||
else if (strcmp(message + 1, "on") == 0)
|
else if (strcmp(message, "@on") == 0)
|
||||||
*warnstate = 1;
|
*warnstate = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
6
lfunc.c
6
lfunc.c
|
@ -164,8 +164,12 @@ static int callclosemth (lua_State *L, StkId level, int status) {
|
||||||
int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
|
int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
|
||||||
if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
|
if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
|
||||||
status = newstatus; /* this will be the new error */
|
status = newstatus; /* this will be the new error */
|
||||||
else /* leave original error (or nil) on top */
|
else {
|
||||||
|
if (newstatus != LUA_OK) /* supressed error? */
|
||||||
|
luaE_warnerror(L, "__close metamethod");
|
||||||
|
/* leave original error (or nil) on top */
|
||||||
L->top = restorestack(L, oldtop);
|
L->top = restorestack(L, oldtop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* else no metamethod; ignore this case and keep original error */
|
/* else no metamethod; ignore this case and keep original error */
|
||||||
}
|
}
|
||||||
|
|
7
lgc.c
7
lgc.c
|
@ -854,12 +854,7 @@ static void GCTM (lua_State *L) {
|
||||||
L->allowhook = oldah; /* restore hooks */
|
L->allowhook = oldah; /* restore hooks */
|
||||||
g->gcrunning = running; /* restore state */
|
g->gcrunning = running; /* restore state */
|
||||||
if (unlikely(status != LUA_OK)) { /* error while running __gc? */
|
if (unlikely(status != LUA_OK)) { /* error while running __gc? */
|
||||||
const char *msg = (ttisstring(s2v(L->top - 1)))
|
luaE_warnerror(L, "__gc metamethod");
|
||||||
? svalue(s2v(L->top - 1))
|
|
||||||
: "error object is not a string";
|
|
||||||
luaE_warning(L, "error in __gc metamethod (", 1);
|
|
||||||
luaE_warning(L, msg, 1);
|
|
||||||
luaE_warning(L, ")", 0);
|
|
||||||
L->top--; /* pops error object */
|
L->top--; /* pops error object */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
lstate.c
16
lstate.c
|
@ -443,3 +443,19 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Generate a warning from an error message
|
||||||
|
*/
|
||||||
|
void luaE_warnerror (lua_State *L, const char *where) {
|
||||||
|
TValue *errobj = s2v(L->top - 1); /* error object */
|
||||||
|
const char *msg = (ttisstring(errobj))
|
||||||
|
? svalue(errobj)
|
||||||
|
: "error object is not a string";
|
||||||
|
/* produce warning "error in %s (%s)" (where, msg) */
|
||||||
|
luaE_warning(L, "error in ", 1);
|
||||||
|
luaE_warning(L, where, 1);
|
||||||
|
luaE_warning(L, " (", 1);
|
||||||
|
luaE_warning(L, msg, 1);
|
||||||
|
luaE_warning(L, ")", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
1
lstate.h
1
lstate.h
|
@ -355,6 +355,7 @@ LUAI_FUNC void luaE_freeCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_enterCcall (lua_State *L);
|
LUAI_FUNC void luaE_enterCcall (lua_State *L);
|
||||||
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
||||||
|
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
|
||||||
|
|
||||||
|
|
||||||
#define luaE_exitCcall(L) ((L)->nCcalls++)
|
#define luaE_exitCcall(L) ((L)->nCcalls++)
|
||||||
|
|
10
ltests.c
10
ltests.c
|
@ -95,15 +95,15 @@ static void warnf (void *ud, const char *msg, int tocont) {
|
||||||
if (!lasttocont && !tocont && *msg == '@') { /* control message? */
|
if (!lasttocont && !tocont && *msg == '@') { /* control message? */
|
||||||
if (buff[0] != '\0')
|
if (buff[0] != '\0')
|
||||||
badexit("Control warning during warning: %s\naborting...\n", msg);
|
badexit("Control warning during warning: %s\naborting...\n", msg);
|
||||||
if (strcmp(msg + 1, "off") == 0)
|
if (strcmp(msg, "@off") == 0)
|
||||||
onoff = 0;
|
onoff = 0;
|
||||||
else if (strcmp(msg + 1, "on") == 0)
|
else if (strcmp(msg, "@on") == 0)
|
||||||
onoff = 1;
|
onoff = 1;
|
||||||
else if (strcmp(msg + 1, "normal") == 0)
|
else if (strcmp(msg, "@normal") == 0)
|
||||||
mode = 0;
|
mode = 0;
|
||||||
else if (strcmp(msg + 1, "allow") == 0)
|
else if (strcmp(msg, "@allow") == 0)
|
||||||
mode = 1;
|
mode = 1;
|
||||||
else if (strcmp(msg + 1, "store") == 0)
|
else if (strcmp(msg, "@store") == 0)
|
||||||
mode = 2;
|
mode = 2;
|
||||||
else
|
else
|
||||||
badexit("Invalid control warning in test mode: %s\naborting...\n", msg);
|
badexit("Invalid control warning in test mode: %s\naborting...\n", msg);
|
||||||
|
|
|
@ -1556,7 +1556,7 @@ However, Lua may call the method one more time.
|
||||||
After an error,
|
After an error,
|
||||||
the other pending closing methods will still be called.
|
the other pending closing methods will still be called.
|
||||||
Errors in these methods
|
Errors in these methods
|
||||||
interrupt the respective method,
|
interrupt the respective method and generate a warning,
|
||||||
but are otherwise ignored;
|
but are otherwise ignored;
|
||||||
the error reported is only the original one.
|
the error reported is only the original one.
|
||||||
|
|
||||||
|
|
|
@ -209,12 +209,12 @@ if #msgs > 0 then
|
||||||
warn("#tests not performed:\n ", m, "\n")
|
warn("#tests not performed:\n ", m, "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
print("(there should be two warnings now)")
|
||||||
|
warn("#This is ", "an expected", " warning")
|
||||||
warn("@off")
|
warn("@off")
|
||||||
warn("******** THIS WARNING SHOULD NOT APPEAR **********")
|
warn("******** THIS WARNING SHOULD NOT APPEAR **********")
|
||||||
warn("******** THIS WARNING ALSO SHOULD NOT APPEAR **********")
|
warn("******** THIS WARNING ALSO SHOULD NOT APPEAR **********")
|
||||||
warn("@on")
|
warn("@on")
|
||||||
print("(there should be two warnings now)")
|
|
||||||
warn("#This is ", "an expected", " warning")
|
|
||||||
warn("#This is", " another one")
|
warn("#This is", " another one")
|
||||||
|
|
||||||
-- no test module should define 'debug'
|
-- no test module should define 'debug'
|
||||||
|
|
|
@ -168,7 +168,7 @@ do
|
||||||
local y <close> = func2close(function (self,err)
|
local y <close> = func2close(function (self,err)
|
||||||
if (err ~= 111) then os.exit(false) end -- should not happen
|
if (err ~= 111) then os.exit(false) end -- should not happen
|
||||||
x = 200
|
x = 200
|
||||||
error(200)
|
error("200")
|
||||||
end)
|
end)
|
||||||
local x <close> = func2close(function (self, err)
|
local x <close> = func2close(function (self, err)
|
||||||
assert(err == nil); error(111)
|
assert(err == nil); error(111)
|
||||||
|
@ -177,7 +177,10 @@ do
|
||||||
end)
|
end)
|
||||||
coroutine.resume(co)
|
coroutine.resume(co)
|
||||||
assert(x == 0)
|
assert(x == 0)
|
||||||
|
_WARN = nil; warn("@off"); warn("@store")
|
||||||
local st, msg = coroutine.close(co)
|
local st, msg = coroutine.close(co)
|
||||||
|
warn("@on"); warn("@normal")
|
||||||
|
assert(_WARN == nil or string.find(_WARN, "200"))
|
||||||
assert(st == false and coroutine.status(co) == "dead" and msg == 111)
|
assert(st == false and coroutine.status(co) == "dead" and msg == 111)
|
||||||
assert(x == 200)
|
assert(x == 200)
|
||||||
|
|
||||||
|
|
|
@ -286,57 +286,149 @@ do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
do -- errors in __close
|
-- auxiliary functions for testing warnings in '__close'
|
||||||
local log = {}
|
local function prepwarn ()
|
||||||
local function foo (err)
|
warn("@off") -- do not show (lots of) warnings
|
||||||
|
if not T then
|
||||||
|
_WARN = "OFF" -- signal that warnings are not being captured
|
||||||
|
else
|
||||||
|
warn("@store") -- to test the warnings
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function endwarn ()
|
||||||
|
assert(T or _WARN == "OFF")
|
||||||
|
warn("@on") -- back to normal
|
||||||
|
warn("@normal")
|
||||||
|
_WARN = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function checkwarn (msg)
|
||||||
|
assert(_WARN == "OFF" or string.find(_WARN, msg))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do print("testing errors in __close")
|
||||||
|
|
||||||
|
prepwarn()
|
||||||
|
|
||||||
|
-- original error is in __close
|
||||||
|
local function foo ()
|
||||||
|
|
||||||
local x <close> =
|
local x <close> =
|
||||||
func2close(function (self, msg) log[#log + 1] = msg; error(1) end)
|
func2close(function (self, msg)
|
||||||
|
assert(string.find(msg, "@z"))
|
||||||
|
error("@x")
|
||||||
|
end)
|
||||||
|
|
||||||
local x1 <close> =
|
local x1 <close> =
|
||||||
func2close(function (self, msg) log[#log + 1] = msg; end)
|
func2close(function (self, msg)
|
||||||
|
checkwarn("@y")
|
||||||
|
assert(string.find(msg, "@z"))
|
||||||
|
end)
|
||||||
|
|
||||||
local gc <close> = func2close(function () collectgarbage() end)
|
local gc <close> = func2close(function () collectgarbage() end)
|
||||||
|
|
||||||
local y <close> =
|
local y <close> =
|
||||||
func2close(function (self, msg) log[#log + 1] = msg; error(2) end)
|
func2close(function (self, msg)
|
||||||
|
assert(string.find(msg, "@z")) -- error in 'z'
|
||||||
|
error("@y")
|
||||||
|
end)
|
||||||
|
|
||||||
|
local first = true
|
||||||
|
local z <close> =
|
||||||
|
-- 'z' close is called twice
|
||||||
|
func2close(function (self, msg)
|
||||||
|
if first then
|
||||||
|
assert(msg == nil)
|
||||||
|
first = false
|
||||||
|
else
|
||||||
|
assert(string.find(msg, "@z")) -- own error
|
||||||
|
end
|
||||||
|
error("@z")
|
||||||
|
end)
|
||||||
|
|
||||||
|
return 200
|
||||||
|
end
|
||||||
|
|
||||||
|
local stat, msg = pcall(foo, false)
|
||||||
|
assert(string.find(msg, "@z"))
|
||||||
|
checkwarn("@x")
|
||||||
|
|
||||||
|
|
||||||
|
-- original error not in __close
|
||||||
|
local function foo ()
|
||||||
|
|
||||||
|
local x <close> =
|
||||||
|
func2close(function (self, msg)
|
||||||
|
assert(msg == 4)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local x1 <close> =
|
||||||
|
func2close(function (self, msg)
|
||||||
|
checkwarn("@y")
|
||||||
|
assert(msg == 4)
|
||||||
|
error("@x1")
|
||||||
|
end)
|
||||||
|
|
||||||
|
local gc <close> = func2close(function () collectgarbage() end)
|
||||||
|
|
||||||
|
local y <close> =
|
||||||
|
func2close(function (self, msg)
|
||||||
|
assert(msg == 4) -- error in body
|
||||||
|
error("@y")
|
||||||
|
end)
|
||||||
|
|
||||||
|
local first = true
|
||||||
local z <close> =
|
local z <close> =
|
||||||
func2close(function (self, msg)
|
func2close(function (self, msg)
|
||||||
log[#log + 1] = (msg or 10) + 1;
|
checkwarn("@z")
|
||||||
error(3)
|
-- 'z' close is called once
|
||||||
|
assert(first and msg == 4)
|
||||||
|
first = false
|
||||||
|
error("@z")
|
||||||
end)
|
end)
|
||||||
if err then error(4) end
|
|
||||||
end
|
|
||||||
local stat, msg = pcall(foo, false)
|
|
||||||
assert(msg == 3)
|
|
||||||
-- 'z' close is called twice
|
|
||||||
assert(log[1] == 11 and log[2] == 4 and log[3] == 3 and log[4] == 3
|
|
||||||
and log[5] == 3 and #log == 5)
|
|
||||||
|
|
||||||
log = {}
|
error(4) -- original error
|
||||||
|
end
|
||||||
|
|
||||||
local stat, msg = pcall(foo, true)
|
local stat, msg = pcall(foo, true)
|
||||||
assert(msg == 4)
|
assert(msg == 4)
|
||||||
-- 'z' close is called once
|
checkwarn("@x1") -- last error
|
||||||
assert(log[1] == 5 and log[2] == 4 and log[3] == 4 and log[4] == 4
|
|
||||||
and #log == 4)
|
|
||||||
|
|
||||||
-- error leaving a block
|
-- error leaving a block
|
||||||
local function foo (...)
|
local function foo (...)
|
||||||
do
|
do
|
||||||
local x1 <close> = func2close(function () error("Y") end)
|
local x1 <close> =
|
||||||
local x123 <close> = func2close(function () error("X") end)
|
func2close(function ()
|
||||||
|
checkwarn("@X")
|
||||||
|
error("@Y")
|
||||||
|
end)
|
||||||
|
|
||||||
|
local x123 <close> =
|
||||||
|
func2close(function ()
|
||||||
|
error("@X")
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
os.exit(false) -- should not run
|
||||||
end
|
end
|
||||||
|
|
||||||
local st, msg = xpcall(foo, debug.traceback)
|
local st, msg = xpcall(foo, debug.traceback)
|
||||||
assert(string.match(msg, "^[^ ]* X"))
|
assert(string.match(msg, "^[^ ]* @X"))
|
||||||
assert(string.find(msg, "in metamethod 'close'"))
|
assert(string.find(msg, "in metamethod 'close'"))
|
||||||
|
|
||||||
-- error in toclose in vararg function
|
-- error in toclose in vararg function
|
||||||
local function foo (...)
|
local function foo (...)
|
||||||
local x123 <close> = func2close(function () error("X") end)
|
local x123 <close> = func2close(function () error("@X") end)
|
||||||
end
|
end
|
||||||
|
|
||||||
local st, msg = xpcall(foo, debug.traceback)
|
local st, msg = xpcall(foo, debug.traceback)
|
||||||
assert(string.match(msg, "^[^ ]* X"))
|
assert(string.match(msg, "^[^ ]* @X"))
|
||||||
|
|
||||||
assert(string.find(msg, "in metamethod 'close'"))
|
assert(string.find(msg, "in metamethod 'close'"))
|
||||||
|
endwarn()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -361,6 +453,8 @@ end
|
||||||
|
|
||||||
if rawget(_G, "T") then
|
if rawget(_G, "T") then
|
||||||
|
|
||||||
|
warn("@off")
|
||||||
|
|
||||||
-- memory error inside closing function
|
-- memory error inside closing function
|
||||||
local function foo ()
|
local function foo ()
|
||||||
local y <close> = func2close(function () T.alloccount() end)
|
local y <close> = func2close(function () T.alloccount() end)
|
||||||
|
@ -437,7 +531,7 @@ if rawget(_G, "T") then
|
||||||
|
|
||||||
local s = string.rep("a", lim)
|
local s = string.rep("a", lim)
|
||||||
|
|
||||||
-- concat this table needs two buffer resizes (one for each 's')
|
-- concat this table needs two buffer resizes (one for each 's')
|
||||||
local a = {s, s}
|
local a = {s, s}
|
||||||
|
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
|
@ -472,6 +566,8 @@ if rawget(_G, "T") then
|
||||||
|
|
||||||
print'+'
|
print'+'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
warn("@on")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -501,17 +597,20 @@ end
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
|
prepwarn()
|
||||||
|
|
||||||
-- error in a wrapped coroutine raising errors when closing a variable
|
-- error in a wrapped coroutine raising errors when closing a variable
|
||||||
local x = 0
|
local x = 0
|
||||||
local co = coroutine.wrap(function ()
|
local co = coroutine.wrap(function ()
|
||||||
local xx <close> = func2close(function () x = x + 1; error("YYY") end)
|
local xx <close> = func2close(function () x = x + 1; error("@YYY") end)
|
||||||
local xv <close> = func2close(function () x = x + 1; error("XXX") end)
|
local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
|
||||||
coroutine.yield(100)
|
coroutine.yield(100)
|
||||||
error(200)
|
error(200)
|
||||||
end)
|
end)
|
||||||
assert(co() == 100); assert(x == 0)
|
assert(co() == 100); assert(x == 0)
|
||||||
local st, msg = pcall(co); assert(x == 2)
|
local st, msg = pcall(co); assert(x == 2)
|
||||||
assert(not st and msg == 200) -- should get first error raised
|
assert(not st and msg == 200) -- should get first error raised
|
||||||
|
checkwarn("@YYY")
|
||||||
|
|
||||||
local x = 0
|
local x = 0
|
||||||
local y = 0
|
local y = 0
|
||||||
|
@ -526,6 +625,9 @@ do
|
||||||
assert(x == 2 and y == 1) -- first close is called twice
|
assert(x == 2 and y == 1) -- first close is called twice
|
||||||
-- should get first error raised
|
-- should get first error raised
|
||||||
assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
|
assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
|
||||||
|
checkwarn("YYY")
|
||||||
|
|
||||||
|
endwarn()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue