summaryrefslogtreecommitdiff
path: root/testes
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-05-09 11:13:45 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-05-09 11:13:45 -0300
commit389116d8abcc96db3cfe2f3cc25789c089fe12d6 (patch)
treef3d07b50c17f28ba09cf547d5a67519ffe3271a4 /testes
parent01bded3d8cd88a2d7f472b45f706565f1a9ef3b1 (diff)
downloadlua-github-389116d8abcc96db3cfe2f3cc25789c089fe12d6.tar.gz
Coroutines do not unwind the stack in case of errors
Back to how it was, a coroutine does not unwind its stack in case of errors (and therefore do not close its to-be-closed variables). This allows the stack to be examined after the error. The program can use 'coroutine.kill' to close the variables. The function created by 'coroutine.wrap', however, closes the coroutine's variables in case of errors, as it is impossible to examine the stack any way.
Diffstat (limited to 'testes')
-rw-r--r--testes/coroutine.lua8
-rw-r--r--testes/db.lua14
-rw-r--r--testes/locals.lua35
3 files changed, 43 insertions, 14 deletions
diff --git a/testes/coroutine.lua b/testes/coroutine.lua
index 35ff27fb..9dd501e7 100644
--- a/testes/coroutine.lua
+++ b/testes/coroutine.lua
@@ -346,9 +346,13 @@ do
local st, res = coroutine.resume(B)
assert(st == true and res == false)
- A = coroutine.wrap(function() return pcall(A, 1) end)
+ local X = false
+ A = coroutine.wrap(function()
+ local *toclose _ = setmetatable({}, {__close = function () X = true end})
+ return pcall(A, 1)
+ end)
st, res = A()
- assert(not st and string.find(res, "non%-suspended"))
+ assert(not st and string.find(res, "non%-suspended") and X == true)
end
diff --git a/testes/db.lua b/testes/db.lua
index 95275fb4..3d94f776 100644
--- a/testes/db.lua
+++ b/testes/db.lua
@@ -734,18 +734,24 @@ a, b = coroutine.resume(co, 100)
assert(a and b == 30)
--- check traceback of suspended coroutines
+-- check traceback of suspended (or dead with error) coroutines
+
+function f(i)
+ if i == 0 then error(i)
+ else coroutine.yield(); f(i-1)
+ end
+end
-function f(i) coroutine.yield(i == 0); f(i - 1) end
co = coroutine.create(function (x) f(x) end)
a, b = coroutine.resume(co, 3)
t = {"'coroutine.yield'", "'f'", "in function <"}
-repeat
+while coroutine.status(co) == "suspended" do
checktraceback(co, t)
a, b = coroutine.resume(co)
table.insert(t, 2, "'f'") -- one more recursive call to 'f'
-until b
+end
+t[1] = "'error'"
checktraceback(co, t)
diff --git a/testes/locals.lua b/testes/locals.lua
index de47ae31..814d1b16 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -417,12 +417,13 @@ if rawget(_G, "T") then
end
--- to-be-closed variables in coroutines
+print "to-be-closed variables in coroutines"
+
do
- -- an error in a coroutine closes variables
+ -- an error in a wrapped coroutine closes variables
local x = false
local y = false
- local co = coroutine.create(function ()
+ local co = coroutine.wrap(function ()
local *toclose xv = func2close(function () x = true end)
do
local *toclose yv = func2close(function () y = true end)
@@ -432,14 +433,31 @@ do
error(23) -- error does
end)
- local a, b = coroutine.resume(co)
- assert(a and b == 100 and not x and not y)
- a, b = coroutine.resume(co)
- assert(a and b == 200 and not x and y)
- a, b = coroutine.resume(co)
+ local b = co()
+ assert(b == 100 and not x and not y)
+ b = co()
+ assert(b == 200 and not x and y)
+ local a, b = pcall(co)
assert(not a and b == 23 and x and y)
end
+
+do
+ -- error in a wrapped coroutine raising errors when closing a variable
+ local x = false
+ local co = coroutine.wrap(function ()
+ local *toclose xv = func2close(function () error("XXX") end)
+ coroutine.yield(100)
+ error(200)
+ end)
+ assert(co() == 100)
+ local st, msg = pcall(co)
+print(msg)
+ -- should get last error raised
+ assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
+end
+
+
-- a suspended coroutine should not close its variables when collected
local co
co = coroutine.wrap(function()
@@ -449,6 +467,7 @@ co = coroutine.wrap(function()
end)
co() -- start coroutine
assert(co == nil) -- eventually it will be collected
+collectgarbage()
-- to-be-closed variables in generic for loops