A to-be-closed variable must have a closable value (or be nil)

It is an error for a to-be-closed variable to have a non-closable
non-nil value when it is being closed. This situation does not seem to
be useful and often hints to an error. (Particularly in the C API, it is
easy to change a to-be-closed index by mistake.)
This commit is contained in:
Roberto Ierusalimschy
2018-11-29 16:02:44 -02:00
parent 7696c6474f
commit 6d04537ea6
9 changed files with 83 additions and 39 deletions

View File

@@ -366,7 +366,7 @@ do
-- "argerror" without frames
assert(T.checkpanic("loadstring 4") ==
"bad argument #4 (string expected, got no value)")
-- memory error
T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k)
@@ -987,12 +987,12 @@ do
local a, b = T.testC([[
call 0 1 # create resource
pushint 34
pushnil
toclose -2 # mark call result to be closed
toclose -1 # mark number to be closed (will be ignored)
toclose -1 # mark nil to be closed (will be ignored)
return 2
]], newresource)
assert(a[1] == 11 and b == 34)
assert(a[1] == 11 and b == nil)
assert(#openresource == 0) -- was closed
-- repeat the test, but calling function in a 'multret' context
@@ -1005,7 +1005,7 @@ do
assert(#openresource == 0) -- was closed
-- error
local a, b = pcall(T.testC, [[
local a, b = pcall(T.makeCfunc[[
call 0 1 # create resource
toclose -1 # mark it to be closed
error # resource is the error object
@@ -1038,6 +1038,13 @@ do
]], newresource, check)
assert(a == 3) -- no extra items left in the stack
-- non-closable value
local a, b = pcall(T.makeCfunc[[
pushint 32
toclose -1
]])
assert(not a and string.find(b, "(C temporary)"))
end
@@ -1249,9 +1256,9 @@ do -- closing state with no extra memory
T.closestate(L)
T.alloccount()
end
do -- garbage collection with no extra memory
local L = T.newstate()
local L = T.newstate()
T.loadlib(L)
local res = (T.doremote(L, [[
_ENV = require"_G"

View File

@@ -214,14 +214,14 @@ local function foo (a, ...)
local t = table.pack(...)
for i = 1, t.n do
local n, v = debug.getlocal(1, -i)
assert(n == "(*vararg)" and v == t[i])
assert(n == "(vararg)" and v == t[i])
end
assert(not debug.getlocal(1, -(t.n + 1)))
assert(not debug.setlocal(1, -(t.n + 1), 30))
if t.n > 0 then
(function (x)
assert(debug.setlocal(2, -1, x) == "(*vararg)")
assert(debug.setlocal(2, -t.n, x) == "(*vararg)")
assert(debug.setlocal(2, -1, x) == "(vararg)")
assert(debug.setlocal(2, -t.n, x) == "(vararg)")
end)(430)
assert(... == 430)
end
@@ -328,9 +328,9 @@ assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print])
-- tests for manipulating non-registered locals (C and Lua temporaries)
local n, v = debug.getlocal(0, 1)
assert(v == 0 and n == "(*temporary)")
assert(v == 0 and n == "(C temporary)")
local n, v = debug.getlocal(0, 2)
assert(v == 2 and n == "(*temporary)")
assert(v == 2 and n == "(C temporary)")
assert(not debug.getlocal(0, 3))
assert(not debug.getlocal(0, 0))
@@ -607,7 +607,7 @@ co = load[[
local a = 0
-- 'A' should be visible to debugger only after its complete definition
debug.sethook(function (e, l)
if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == "(*temporary)")
if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == "(temporary)")
elseif l == 4 then a = a + 1; assert(debug.getlocal(2, 1) == "A")
end
end, "l")
@@ -875,15 +875,15 @@ local debug = require'debug'
local a = 12 -- a local variable
local n, v = debug.getlocal(1, 1)
assert(n == "(*temporary)" and v == debug) -- unkown name but known value
assert(n == "(temporary)" and v == debug) -- unkown name but known value
n, v = debug.getlocal(1, 2)
assert(n == "(*temporary)" and v == 12) -- unkown name but known value
assert(n == "(temporary)" and v == 12) -- unkown name but known value
-- a function with an upvalue
local f = function () local x; return a end
n, v = debug.getupvalue(f, 1)
assert(n == "(*no name)" and v == 12)
assert(debug.setupvalue(f, 1, 13) == "(*no name)")
assert(n == "(no name)" and v == 12)
assert(debug.setupvalue(f, 1, 13) == "(no name)")
assert(a == 13)
local t = debug.getinfo(f)

View File

@@ -266,6 +266,27 @@ do -- errors in __close
end
do
-- errors due to non-closable values
local function foo ()
local *toclose x = 34
end
local stat, msg = pcall(foo)
assert(not stat and string.find(msg, "variable 'x'"))
-- with other errors, non-closable values are ignored
local function foo ()
local *toclose x = 34
local *toclose y = function () error(32) end
end
local stat, msg = pcall(foo)
assert(not stat and msg == 32)
end
if rawget(_G, "T") then
-- memory error inside closing function