Skip to content

Commit ca13be9

Browse files
committed
Supressed errors in '__close' generate warnings
1 parent a1d8eb2 commit ca13be9

10 files changed

Lines changed: 164 additions & 43 deletions

File tree

lauxlib.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,9 +1010,9 @@ static int panic (lua_State *L) {
10101010
static void warnf (void *ud, const char *message, int tocont) {
10111011
int *warnstate = (int *)ud;
10121012
if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */
1013-
if (strcmp(message + 1, "off") == 0)
1013+
if (strcmp(message, "@off") == 0)
10141014
*warnstate = 0;
1015-
else if (strcmp(message + 1, "on") == 0)
1015+
else if (strcmp(message, "@on") == 0)
10161016
*warnstate = 1;
10171017
return;
10181018
}

lfunc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,12 @@ static int callclosemth (lua_State *L, StkId level, int status) {
164164
int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
165165
if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
166166
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 */
168171
L->top = restorestack(L, oldtop);
172+
}
169173
}
170174
/* else no metamethod; ignore this case and keep original error */
171175
}

lgc.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -854,12 +854,7 @@ static void GCTM (lua_State *L) {
854854
L->allowhook = oldah; /* restore hooks */
855855
g->gcrunning = running; /* restore state */
856856
if (unlikely(status != LUA_OK)) { /* error while running __gc? */
857-
const char *msg = (ttisstring(s2v(L->top - 1)))
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);
857+
luaE_warnerror(L, "__gc metamethod");
863858
L->top--; /* pops error object */
864859
}
865860
}

lstate.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,3 +443,19 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
443443
}
444444

445445

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+

lstate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ LUAI_FUNC void luaE_freeCI (lua_State *L);
355355
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
356356
LUAI_FUNC void luaE_enterCcall (lua_State *L);
357357
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);
358359

359360

360361
#define luaE_exitCcall(L) ((L)->nCcalls++)

ltests.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ static void warnf (void *ud, const char *msg, int tocont) {
9595
if (!lasttocont && !tocont && *msg == '@') { /* control message? */
9696
if (buff[0] != '\0')
9797
badexit("Control warning during warning: %s\naborting...\n", msg);
98-
if (strcmp(msg + 1, "off") == 0)
98+
if (strcmp(msg, "@off") == 0)
9999
onoff = 0;
100-
else if (strcmp(msg + 1, "on") == 0)
100+
else if (strcmp(msg, "@on") == 0)
101101
onoff = 1;
102-
else if (strcmp(msg + 1, "normal") == 0)
102+
else if (strcmp(msg, "@normal") == 0)
103103
mode = 0;
104-
else if (strcmp(msg + 1, "allow") == 0)
104+
else if (strcmp(msg, "@allow") == 0)
105105
mode = 1;
106-
else if (strcmp(msg + 1, "store") == 0)
106+
else if (strcmp(msg, "@store") == 0)
107107
mode = 2;
108108
else
109109
badexit("Invalid control warning in test mode: %s\naborting...\n", msg);

manual/manual.of

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1556,7 +1556,7 @@ However, Lua may call the method one more time.
15561556
After an error,
15571557
the other pending closing methods will still be called.
15581558
Errors in these methods
1559-
interrupt the respective method,
1559+
interrupt the respective method and generate a warning,
15601560
but are otherwise ignored;
15611561
the error reported is only the original one.
15621562

testes/all.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,12 @@ if #msgs > 0 then
209209
warn("#tests not performed:\n ", m, "\n")
210210
end
211211

212+
print("(there should be two warnings now)")
213+
warn("#This is ", "an expected", " warning")
212214
warn("@off")
213215
warn("******** THIS WARNING SHOULD NOT APPEAR **********")
214216
warn("******** THIS WARNING ALSO SHOULD NOT APPEAR **********")
215217
warn("@on")
216-
print("(there should be two warnings now)")
217-
warn("#This is ", "an expected", " warning")
218218
warn("#This is", " another one")
219219

220220
-- no test module should define 'debug'

testes/coroutine.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ do
168168
local y <close> = func2close(function (self,err)
169169
if (err ~= 111) then os.exit(false) end -- should not happen
170170
x = 200
171-
error(200)
171+
error("200")
172172
end)
173173
local x <close> = func2close(function (self, err)
174174
assert(err == nil); error(111)
@@ -177,7 +177,10 @@ do
177177
end)
178178
coroutine.resume(co)
179179
assert(x == 0)
180+
_WARN = nil; warn("@off"); warn("@store")
180181
local st, msg = coroutine.close(co)
182+
warn("@on"); warn("@normal")
183+
assert(_WARN == nil or string.find(_WARN, "200"))
181184
assert(st == false and coroutine.status(co) == "dead" and msg == 111)
182185
assert(x == 200)
183186

testes/locals.lua

Lines changed: 127 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -286,57 +286,149 @@ do
286286
end
287287

288288

289-
do -- errors in __close
290-
local log = {}
291-
local function foo (err)
289+
-- auxiliary functions for testing warnings in '__close'
290+
local function prepwarn ()
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+
292320
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+
294326
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+
296332
local gc <close> = func2close(function () collectgarbage() end)
333+
297334
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
299341
local z <close> =
342+
-- 'z' close is called twice
300343
func2close(function (self, msg)
301-
log[#log + 1] = (msg or 10) + 1;
302-
error(3)
344+
if first then
345+
assert(msg == nil)
346+
first = false
347+
else
348+
assert(string.find(msg, "@z")) -- own error
349+
end
350+
error("@z")
303351
end)
304-
if err then error(4) end
352+
353+
return 200
305354
end
355+
306356
local stat, msg = pcall(foo, false)
307-
assert(msg == 3)
308-
-- 'z' close is called twice
309-
assert(log[1] == 11 and log[2] == 4 and log[3] == 3 and log[4] == 3
310-
and log[5] == 3 and #log == 5)
357+
assert(string.find(msg, "@z"))
358+
checkwarn("@x")
359+
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
311396

312-
log = {}
313397
local stat, msg = pcall(foo, true)
314398
assert(msg == 4)
315-
-- 'z' close is called once
316-
assert(log[1] == 5 and log[2] == 4 and log[3] == 4 and log[4] == 4
317-
and #log == 4)
399+
checkwarn("@x1") -- last error
318400

319401
-- error leaving a block
320402
local function foo (...)
321403
do
322-
local x1 <close> = func2close(function () error("Y") end)
323-
local x123 <close> = func2close(function () error("X") end)
404+
local x1 <close> =
405+
func2close(function ()
406+
checkwarn("@X")
407+
error("@Y")
408+
end)
409+
410+
local x123 <close> =
411+
func2close(function ()
412+
error("@X")
413+
end)
324414
end
415+
os.exit(false) -- should not run
325416
end
326417

327418
local st, msg = xpcall(foo, debug.traceback)
328-
assert(string.match(msg, "^[^ ]* X"))
419+
assert(string.match(msg, "^[^ ]* @X"))
329420
assert(string.find(msg, "in metamethod 'close'"))
330421

331422
-- error in toclose in vararg function
332423
local function foo (...)
333-
local x123 <close> = func2close(function () error("X") end)
424+
local x123 <close> = func2close(function () error("@X") end)
334425
end
335426

336427
local st, msg = xpcall(foo, debug.traceback)
337-
assert(string.match(msg, "^[^ ]* X"))
428+
assert(string.match(msg, "^[^ ]* @X"))
338429

339430
assert(string.find(msg, "in metamethod 'close'"))
431+
endwarn()
340432
end
341433

342434

@@ -361,6 +453,8 @@ end
361453

362454
if rawget(_G, "T") then
363455

456+
warn("@off")
457+
364458
-- memory error inside closing function
365459
local function foo ()
366460
local y <close> = func2close(function () T.alloccount() end)
@@ -437,7 +531,7 @@ if rawget(_G, "T") then
437531

438532
local s = string.rep("a", lim)
439533

440-
-- concat this table needs two buffer resizes (one for each 's')
534+
-- concat this table needs two buffer resizes (one for each 's')
441535
local a = {s, s}
442536

443537
collectgarbage()
@@ -472,6 +566,8 @@ if rawget(_G, "T") then
472566

473567
print'+'
474568
end
569+
570+
warn("@on")
475571
end
476572

477573

@@ -501,17 +597,20 @@ end
501597

502598

503599
do
600+
prepwarn()
601+
504602
-- error in a wrapped coroutine raising errors when closing a variable
505603
local x = 0
506604
local co = coroutine.wrap(function ()
507-
local xx <close> = func2close(function () x = x + 1; error("YYY") end)
508-
local xv <close> = func2close(function () x = x + 1; error("XXX") end)
605+
local xx <close> = func2close(function () x = x + 1; error("@YYY") end)
606+
local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
509607
coroutine.yield(100)
510608
error(200)
511609
end)
512610
assert(co() == 100); assert(x == 0)
513611
local st, msg = pcall(co); assert(x == 2)
514612
assert(not st and msg == 200) -- should get first error raised
613+
checkwarn("@YYY")
515614

516615
local x = 0
517616
local y = 0
@@ -526,6 +625,9 @@ do
526625
assert(x == 2 and y == 1) -- first close is called twice
527626
-- should get first error raised
528627
assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
628+
checkwarn("YYY")
629+
630+
endwarn()
529631
end
530632

531633

0 commit comments

Comments
 (0)