diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-08-16 09:51:54 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-08-16 09:51:54 -0300 |
commit | ca13be9af784b7288d3a07d9b5bccb329086e885 (patch) | |
tree | c027419f98064d681518a4130439920a13a11b06 | |
parent | a1d8eb27431c02c4529be1efd92143ad65434f3a (diff) | |
download | lua-ca13be9af784b7288d3a07d9b5bccb329086e885.tar.gz lua-ca13be9af784b7288d3a07d9b5bccb329086e885.tar.bz2 lua-ca13be9af784b7288d3a07d9b5bccb329086e885.zip |
Supressed errors in '__close' generate warnings
-rw-r--r-- | lauxlib.c | 4 | ||||
-rw-r--r-- | lfunc.c | 6 | ||||
-rw-r--r-- | lgc.c | 7 | ||||
-rw-r--r-- | lstate.c | 16 | ||||
-rw-r--r-- | lstate.h | 1 | ||||
-rw-r--r-- | ltests.c | 10 | ||||
-rw-r--r-- | manual/manual.of | 2 | ||||
-rw-r--r-- | testes/all.lua | 4 | ||||
-rw-r--r-- | testes/coroutine.lua | 5 | ||||
-rw-r--r-- | testes/locals.lua | 152 |
10 files changed, 164 insertions, 43 deletions
@@ -1010,9 +1010,9 @@ static int panic (lua_State *L) { | |||
1010 | static void warnf (void *ud, const char *message, int tocont) { | 1010 | static void warnf (void *ud, const char *message, int tocont) { |
1011 | int *warnstate = (int *)ud; | 1011 | int *warnstate = (int *)ud; |
1012 | if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */ | 1012 | if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */ |
1013 | if (strcmp(message + 1, "off") == 0) | 1013 | if (strcmp(message, "@off") == 0) |
1014 | *warnstate = 0; | 1014 | *warnstate = 0; |
1015 | else if (strcmp(message + 1, "on") == 0) | 1015 | else if (strcmp(message, "@on") == 0) |
1016 | *warnstate = 1; | 1016 | *warnstate = 1; |
1017 | return; | 1017 | return; |
1018 | } | 1018 | } |
@@ -164,8 +164,12 @@ static int callclosemth (lua_State *L, StkId level, int status) { | |||
164 | int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0); | 164 | int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0); |
165 | if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */ | 165 | if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */ |
166 | status = newstatus; /* this will be the new error */ | 166 | status = newstatus; /* this will be the new error */ |
167 | else /* leave original error (or nil) on top */ | 167 | else { |
168 | if (newstatus != LUA_OK) /* supressed error? */ | ||
169 | luaE_warnerror(L, "__close metamethod"); | ||
170 | /* leave original error (or nil) on top */ | ||
168 | L->top = restorestack(L, oldtop); | 171 | L->top = restorestack(L, oldtop); |
172 | } | ||
169 | } | 173 | } |
170 | /* else no metamethod; ignore this case and keep original error */ | 174 | /* else no metamethod; ignore this case and keep original error */ |
171 | } | 175 | } |
@@ -854,12 +854,7 @@ static void GCTM (lua_State *L) { | |||
854 | L->allowhook = oldah; /* restore hooks */ | 854 | L->allowhook = oldah; /* restore hooks */ |
855 | g->gcrunning = running; /* restore state */ | 855 | g->gcrunning = running; /* restore state */ |
856 | if (unlikely(status != LUA_OK)) { /* error while running __gc? */ | 856 | if (unlikely(status != LUA_OK)) { /* error while running __gc? */ |
857 | const char *msg = (ttisstring(s2v(L->top - 1))) | 857 | luaE_warnerror(L, "__gc metamethod"); |
858 | ? svalue(s2v(L->top - 1)) | ||
859 | : "error object is not a string"; | ||
860 | luaE_warning(L, "error in __gc metamethod (", 1); | ||
861 | luaE_warning(L, msg, 1); | ||
862 | luaE_warning(L, ")", 0); | ||
863 | L->top--; /* pops error object */ | 858 | L->top--; /* pops error object */ |
864 | } | 859 | } |
865 | } | 860 | } |
@@ -443,3 +443,19 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) { | |||
443 | } | 443 | } |
444 | 444 | ||
445 | 445 | ||
446 | /* | ||
447 | ** Generate a warning from an error message | ||
448 | */ | ||
449 | void luaE_warnerror (lua_State *L, const char *where) { | ||
450 | TValue *errobj = s2v(L->top - 1); /* error object */ | ||
451 | const char *msg = (ttisstring(errobj)) | ||
452 | ? svalue(errobj) | ||
453 | : "error object is not a string"; | ||
454 | /* produce warning "error in %s (%s)" (where, msg) */ | ||
455 | luaE_warning(L, "error in ", 1); | ||
456 | luaE_warning(L, where, 1); | ||
457 | luaE_warning(L, " (", 1); | ||
458 | luaE_warning(L, msg, 1); | ||
459 | luaE_warning(L, ")", 0); | ||
460 | } | ||
461 | |||
@@ -355,6 +355,7 @@ LUAI_FUNC void luaE_freeCI (lua_State *L); | |||
355 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); | 355 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); |
356 | LUAI_FUNC void luaE_enterCcall (lua_State *L); | 356 | LUAI_FUNC void luaE_enterCcall (lua_State *L); |
357 | LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); | 357 | LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); |
358 | LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); | ||
358 | 359 | ||
359 | 360 | ||
360 | #define luaE_exitCcall(L) ((L)->nCcalls++) | 361 | #define luaE_exitCcall(L) ((L)->nCcalls++) |
@@ -95,15 +95,15 @@ static void warnf (void *ud, const char *msg, int tocont) { | |||
95 | if (!lasttocont && !tocont && *msg == '@') { /* control message? */ | 95 | if (!lasttocont && !tocont && *msg == '@') { /* control message? */ |
96 | if (buff[0] != '\0') | 96 | if (buff[0] != '\0') |
97 | badexit("Control warning during warning: %s\naborting...\n", msg); | 97 | badexit("Control warning during warning: %s\naborting...\n", msg); |
98 | if (strcmp(msg + 1, "off") == 0) | 98 | if (strcmp(msg, "@off") == 0) |
99 | onoff = 0; | 99 | onoff = 0; |
100 | else if (strcmp(msg + 1, "on") == 0) | 100 | else if (strcmp(msg, "@on") == 0) |
101 | onoff = 1; | 101 | onoff = 1; |
102 | else if (strcmp(msg + 1, "normal") == 0) | 102 | else if (strcmp(msg, "@normal") == 0) |
103 | mode = 0; | 103 | mode = 0; |
104 | else if (strcmp(msg + 1, "allow") == 0) | 104 | else if (strcmp(msg, "@allow") == 0) |
105 | mode = 1; | 105 | mode = 1; |
106 | else if (strcmp(msg + 1, "store") == 0) | 106 | else if (strcmp(msg, "@store") == 0) |
107 | mode = 2; | 107 | mode = 2; |
108 | else | 108 | else |
109 | badexit("Invalid control warning in test mode: %s\naborting...\n", msg); | 109 | badexit("Invalid control warning in test mode: %s\naborting...\n", msg); |
diff --git a/manual/manual.of b/manual/manual.of index 8c71c613..bb6ae884 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -1556,7 +1556,7 @@ However, Lua may call the method one more time. | |||
1556 | After an error, | 1556 | After an error, |
1557 | the other pending closing methods will still be called. | 1557 | the other pending closing methods will still be called. |
1558 | Errors in these methods | 1558 | Errors in these methods |
1559 | interrupt the respective method, | 1559 | interrupt the respective method and generate a warning, |
1560 | but are otherwise ignored; | 1560 | but are otherwise ignored; |
1561 | the error reported is only the original one. | 1561 | the error reported is only the original one. |
1562 | 1562 | ||
diff --git a/testes/all.lua b/testes/all.lua index 5d698d4b..42809b9a 100644 --- a/testes/all.lua +++ b/testes/all.lua | |||
@@ -209,12 +209,12 @@ if #msgs > 0 then | |||
209 | warn("#tests not performed:\n ", m, "\n") | 209 | warn("#tests not performed:\n ", m, "\n") |
210 | end | 210 | end |
211 | 211 | ||
212 | print("(there should be two warnings now)") | ||
213 | warn("#This is ", "an expected", " warning") | ||
212 | warn("@off") | 214 | warn("@off") |
213 | warn("******** THIS WARNING SHOULD NOT APPEAR **********") | 215 | warn("******** THIS WARNING SHOULD NOT APPEAR **********") |
214 | warn("******** THIS WARNING ALSO SHOULD NOT APPEAR **********") | 216 | warn("******** THIS WARNING ALSO SHOULD NOT APPEAR **********") |
215 | warn("@on") | 217 | warn("@on") |
216 | print("(there should be two warnings now)") | ||
217 | warn("#This is ", "an expected", " warning") | ||
218 | warn("#This is", " another one") | 218 | warn("#This is", " another one") |
219 | 219 | ||
220 | -- no test module should define 'debug' | 220 | -- no test module should define 'debug' |
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 457374ca..79c72a9d 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
@@ -168,7 +168,7 @@ do | |||
168 | local y <close> = func2close(function (self,err) | 168 | local y <close> = func2close(function (self,err) |
169 | if (err ~= 111) then os.exit(false) end -- should not happen | 169 | if (err ~= 111) then os.exit(false) end -- should not happen |
170 | x = 200 | 170 | x = 200 |
171 | error(200) | 171 | error("200") |
172 | end) | 172 | end) |
173 | local x <close> = func2close(function (self, err) | 173 | local x <close> = func2close(function (self, err) |
174 | assert(err == nil); error(111) | 174 | assert(err == nil); error(111) |
@@ -177,7 +177,10 @@ do | |||
177 | end) | 177 | end) |
178 | coroutine.resume(co) | 178 | coroutine.resume(co) |
179 | assert(x == 0) | 179 | assert(x == 0) |
180 | _WARN = nil; warn("@off"); warn("@store") | ||
180 | local st, msg = coroutine.close(co) | 181 | local st, msg = coroutine.close(co) |
182 | warn("@on"); warn("@normal") | ||
183 | assert(_WARN == nil or string.find(_WARN, "200")) | ||
181 | assert(st == false and coroutine.status(co) == "dead" and msg == 111) | 184 | assert(st == false and coroutine.status(co) == "dead" and msg == 111) |
182 | assert(x == 200) | 185 | assert(x == 200) |
183 | 186 | ||
diff --git a/testes/locals.lua b/testes/locals.lua index 99fa79cd..595e107a 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -286,57 +286,149 @@ do | |||
286 | end | 286 | end |
287 | 287 | ||
288 | 288 | ||
289 | do -- errors in __close | 289 | -- auxiliary functions for testing warnings in '__close' |
290 | local log = {} | 290 | local function prepwarn () |
291 | local function foo (err) | 291 | warn("@off") -- do not show (lots of) warnings |
292 | if not T then | ||
293 | _WARN = "OFF" -- signal that warnings are not being captured | ||
294 | else | ||
295 | warn("@store") -- to test the warnings | ||
296 | end | ||
297 | end | ||
298 | |||
299 | |||
300 | local function endwarn () | ||
301 | assert(T or _WARN == "OFF") | ||
302 | warn("@on") -- back to normal | ||
303 | warn("@normal") | ||
304 | _WARN = nil | ||
305 | end | ||
306 | |||
307 | |||
308 | local function checkwarn (msg) | ||
309 | assert(_WARN == "OFF" or string.find(_WARN, msg)) | ||
310 | end | ||
311 | |||
312 | |||
313 | do print("testing errors in __close") | ||
314 | |||
315 | prepwarn() | ||
316 | |||
317 | -- original error is in __close | ||
318 | local function foo () | ||
319 | |||
292 | local x <close> = | 320 | local x <close> = |
293 | func2close(function (self, msg) log[#log + 1] = msg; error(1) end) | 321 | func2close(function (self, msg) |
322 | assert(string.find(msg, "@z")) | ||
323 | error("@x") | ||
324 | end) | ||
325 | |||
294 | local x1 <close> = | 326 | local x1 <close> = |
295 | func2close(function (self, msg) log[#log + 1] = msg; end) | 327 | func2close(function (self, msg) |
328 | checkwarn("@y") | ||
329 | assert(string.find(msg, "@z")) | ||
330 | end) | ||
331 | |||
296 | local gc <close> = func2close(function () collectgarbage() end) | 332 | local gc <close> = func2close(function () collectgarbage() end) |
333 | |||
297 | local y <close> = | 334 | local y <close> = |
298 | func2close(function (self, msg) log[#log + 1] = msg; error(2) end) | 335 | func2close(function (self, msg) |
336 | assert(string.find(msg, "@z")) -- error in 'z' | ||
337 | error("@y") | ||
338 | end) | ||
339 | |||
340 | local first = true | ||
299 | local z <close> = | 341 | local z <close> = |
342 | -- 'z' close is called twice | ||
300 | func2close(function (self, msg) | 343 | func2close(function (self, msg) |
301 | log[#log + 1] = (msg or 10) + 1; | 344 | if first then |
302 | error(3) | 345 | assert(msg == nil) |
346 | first = false | ||
347 | else | ||
348 | assert(string.find(msg, "@z")) -- own error | ||
349 | end | ||
350 | error("@z") | ||
303 | end) | 351 | end) |
304 | if err then error(4) end | 352 | |
353 | return 200 | ||
305 | end | 354 | end |
355 | |||
306 | local stat, msg = pcall(foo, false) | 356 | local stat, msg = pcall(foo, false) |
307 | assert(msg == 3) | 357 | assert(string.find(msg, "@z")) |
308 | -- 'z' close is called twice | 358 | checkwarn("@x") |
309 | assert(log[1] == 11 and log[2] == 4 and log[3] == 3 and log[4] == 3 | 359 | |
310 | and log[5] == 3 and #log == 5) | 360 | |
361 | -- original error not in __close | ||
362 | local function foo () | ||
363 | |||
364 | local x <close> = | ||
365 | func2close(function (self, msg) | ||
366 | assert(msg == 4) | ||
367 | end) | ||
368 | |||
369 | local x1 <close> = | ||
370 | func2close(function (self, msg) | ||
371 | checkwarn("@y") | ||
372 | assert(msg == 4) | ||
373 | error("@x1") | ||
374 | end) | ||
375 | |||
376 | local gc <close> = func2close(function () collectgarbage() end) | ||
377 | |||
378 | local y <close> = | ||
379 | func2close(function (self, msg) | ||
380 | assert(msg == 4) -- error in body | ||
381 | error("@y") | ||
382 | end) | ||
383 | |||
384 | local first = true | ||
385 | local z <close> = | ||
386 | func2close(function (self, msg) | ||
387 | checkwarn("@z") | ||
388 | -- 'z' close is called once | ||
389 | assert(first and msg == 4) | ||
390 | first = false | ||
391 | error("@z") | ||
392 | end) | ||
393 | |||
394 | error(4) -- original error | ||
395 | end | ||
311 | 396 | ||
312 | log = {} | ||
313 | local stat, msg = pcall(foo, true) | 397 | local stat, msg = pcall(foo, true) |
314 | assert(msg == 4) | 398 | assert(msg == 4) |
315 | -- 'z' close is called once | 399 | checkwarn("@x1") -- last error |
316 | assert(log[1] == 5 and log[2] == 4 and log[3] == 4 and log[4] == 4 | ||
317 | and #log == 4) | ||
318 | 400 | ||
319 | -- error leaving a block | 401 | -- error leaving a block |
320 | local function foo (...) | 402 | local function foo (...) |
321 | do | 403 | do |
322 | local x1 <close> = func2close(function () error("Y") end) | 404 | local x1 <close> = |
323 | local x123 <close> = func2close(function () error("X") end) | 405 | func2close(function () |
406 | checkwarn("@X") | ||
407 | error("@Y") | ||
408 | end) | ||
409 | |||
410 | local x123 <close> = | ||
411 | func2close(function () | ||
412 | error("@X") | ||
413 | end) | ||
324 | end | 414 | end |
415 | os.exit(false) -- should not run | ||
325 | end | 416 | end |
326 | 417 | ||
327 | local st, msg = xpcall(foo, debug.traceback) | 418 | local st, msg = xpcall(foo, debug.traceback) |
328 | assert(string.match(msg, "^[^ ]* X")) | 419 | assert(string.match(msg, "^[^ ]* @X")) |
329 | assert(string.find(msg, "in metamethod 'close'")) | 420 | assert(string.find(msg, "in metamethod 'close'")) |
330 | 421 | ||
331 | -- error in toclose in vararg function | 422 | -- error in toclose in vararg function |
332 | local function foo (...) | 423 | local function foo (...) |
333 | local x123 <close> = func2close(function () error("X") end) | 424 | local x123 <close> = func2close(function () error("@X") end) |
334 | end | 425 | end |
335 | 426 | ||
336 | local st, msg = xpcall(foo, debug.traceback) | 427 | local st, msg = xpcall(foo, debug.traceback) |
337 | assert(string.match(msg, "^[^ ]* X")) | 428 | assert(string.match(msg, "^[^ ]* @X")) |
338 | 429 | ||
339 | assert(string.find(msg, "in metamethod 'close'")) | 430 | assert(string.find(msg, "in metamethod 'close'")) |
431 | endwarn() | ||
340 | end | 432 | end |
341 | 433 | ||
342 | 434 | ||
@@ -361,6 +453,8 @@ end | |||
361 | 453 | ||
362 | if rawget(_G, "T") then | 454 | if rawget(_G, "T") then |
363 | 455 | ||
456 | warn("@off") | ||
457 | |||
364 | -- memory error inside closing function | 458 | -- memory error inside closing function |
365 | local function foo () | 459 | local function foo () |
366 | local y <close> = func2close(function () T.alloccount() end) | 460 | local y <close> = func2close(function () T.alloccount() end) |
@@ -437,7 +531,7 @@ if rawget(_G, "T") then | |||
437 | 531 | ||
438 | local s = string.rep("a", lim) | 532 | local s = string.rep("a", lim) |
439 | 533 | ||
440 | -- concat this table needs two buffer resizes (one for each 's') | 534 | -- concat this table needs two buffer resizes (one for each 's') |
441 | local a = {s, s} | 535 | local a = {s, s} |
442 | 536 | ||
443 | collectgarbage() | 537 | collectgarbage() |
@@ -472,6 +566,8 @@ if rawget(_G, "T") then | |||
472 | 566 | ||
473 | print'+' | 567 | print'+' |
474 | end | 568 | end |
569 | |||
570 | warn("@on") | ||
475 | end | 571 | end |
476 | 572 | ||
477 | 573 | ||
@@ -501,17 +597,20 @@ end | |||
501 | 597 | ||
502 | 598 | ||
503 | do | 599 | do |
600 | prepwarn() | ||
601 | |||
504 | -- error in a wrapped coroutine raising errors when closing a variable | 602 | -- error in a wrapped coroutine raising errors when closing a variable |
505 | local x = 0 | 603 | local x = 0 |
506 | local co = coroutine.wrap(function () | 604 | local co = coroutine.wrap(function () |
507 | local xx <close> = func2close(function () x = x + 1; error("YYY") end) | 605 | local xx <close> = func2close(function () x = x + 1; error("@YYY") end) |
508 | local xv <close> = func2close(function () x = x + 1; error("XXX") end) | 606 | local xv <close> = func2close(function () x = x + 1; error("@XXX") end) |
509 | coroutine.yield(100) | 607 | coroutine.yield(100) |
510 | error(200) | 608 | error(200) |
511 | end) | 609 | end) |
512 | assert(co() == 100); assert(x == 0) | 610 | assert(co() == 100); assert(x == 0) |
513 | local st, msg = pcall(co); assert(x == 2) | 611 | local st, msg = pcall(co); assert(x == 2) |
514 | assert(not st and msg == 200) -- should get first error raised | 612 | assert(not st and msg == 200) -- should get first error raised |
613 | checkwarn("@YYY") | ||
515 | 614 | ||
516 | local x = 0 | 615 | local x = 0 |
517 | local y = 0 | 616 | local y = 0 |
@@ -526,6 +625,9 @@ do | |||
526 | assert(x == 2 and y == 1) -- first close is called twice | 625 | assert(x == 2 and y == 1) -- first close is called twice |
527 | -- should get first error raised | 626 | -- should get first error raised |
528 | assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX")) | 627 | assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX")) |
628 | checkwarn("YYY") | ||
629 | |||
630 | endwarn() | ||
529 | end | 631 | end |
530 | 632 | ||
531 | 633 | ||