aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lfunc.c49
-rw-r--r--ltests.c3
-rw-r--r--lvm.c6
-rw-r--r--manual/manual.of19
-rw-r--r--testes/api.lua11
-rw-r--r--testes/locals.lua23
6 files changed, 70 insertions, 41 deletions
diff --git a/lfunc.c b/lfunc.c
index 6f2f897f..8f39f6b0 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -124,11 +124,23 @@ static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) {
124 124
125 125
126/* 126/*
127** Raise an error with message 'msg', inserting the name of the
128** local variable at position 'level' in the stack.
129*/
130static void varerror (lua_State *L, StkId level, const char *msg) {
131 int idx = cast_int(level - L->ci->func);
132 const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
133 if (vname == NULL) vname = "?";
134 luaG_runerror(L, msg, vname);
135}
136
137
138/*
127** Prepare and call a closing method. If status is OK, code is still 139** Prepare and call a closing method. If status is OK, code is still
128** inside the original protected call, and so any error will be handled 140** inside the original protected call, and so any error will be handled
129** there. Otherwise, a previous error already activated original 141** there. Otherwise, a previous error already activated the original
130** protected call, and so the call to the closing method must be 142** protected call, and so the call to the closing method must be
131** protected here. (A status = CLOSEPROTECT behaves like a previous 143** protected here. (A status == CLOSEPROTECT behaves like a previous
132** error, to also run the closing method in protected mode). 144** error, to also run the closing method in protected mode).
133** If status is OK, the call to the closing method will be pushed 145** If status is OK, the call to the closing method will be pushed
134** at the top of the stack. Otherwise, values are pushed after 146** at the top of the stack. Otherwise, values are pushed after
@@ -140,12 +152,8 @@ static int callclosemth (lua_State *L, StkId level, int status) {
140 if (likely(status == LUA_OK)) { 152 if (likely(status == LUA_OK)) {
141 if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ 153 if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */
142 callclose(L, NULL); /* call closing method */ 154 callclose(L, NULL); /* call closing method */
143 else if (!ttisnil(uv)) { /* non-closable non-nil value? */ 155 else if (!l_isfalse(uv)) /* non-closable non-false value? */
144 int idx = cast_int(level - L->ci->func); 156 varerror(L, level, "attempt to close non-closable variable '%s'");
145 const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
146 if (vname == NULL) vname = "?";
147 luaG_runerror(L, "attempt to close non-closable variable '%s'", vname);
148 }
149 } 157 }
150 else { /* must close the object in protected mode */ 158 else { /* must close the object in protected mode */
151 ptrdiff_t oldtop; 159 ptrdiff_t oldtop;
@@ -170,9 +178,7 @@ static int callclosemth (lua_State *L, StkId level, int status) {
170** (can raise a memory-allocation error) 178** (can raise a memory-allocation error)
171*/ 179*/
172static void trynewtbcupval (lua_State *L, void *ud) { 180static void trynewtbcupval (lua_State *L, void *ud) {
173 StkId level = cast(StkId, ud); 181 newupval(L, 1, cast(StkId, ud), &L->openupval);
174 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
175 newupval(L, 1, level, &L->openupval);
176} 182}
177 183
178 184
@@ -182,13 +188,22 @@ static void trynewtbcupval (lua_State *L, void *ud) {
182** as there is no upvalue to call it later. 188** as there is no upvalue to call it later.
183*/ 189*/
184void luaF_newtbcupval (lua_State *L, StkId level) { 190void luaF_newtbcupval (lua_State *L, StkId level) {
185 int status = luaD_rawrunprotected(L, trynewtbcupval, level); 191 TValue *obj = s2v(level);
186 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ 192 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
187 lua_assert(status == LUA_ERRMEM); 193 if (!l_isfalse(obj)) { /* false doesn't need to be closed */
188 luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ 194 int status;
189 if (prepclosingmethod(L, s2v(level), s2v(level + 1))) 195 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
196 if (ttisnil(tm)) /* no metamethod? */
197 varerror(L, level, "variable '%s' got a non-closable value");
198 status = luaD_rawrunprotected(L, trynewtbcupval, level);
199 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */
200 lua_assert(status == LUA_ERRMEM);
201 luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */
202 /* next call must succeed, as object is closable */
203 prepclosingmethod(L, s2v(level), s2v(level + 1));
190 callclose(L, NULL); /* call closing method */ 204 callclose(L, NULL); /* call closing method */
191 luaD_throw(L, LUA_ERRMEM); /* throw memory error */ 205 luaD_throw(L, LUA_ERRMEM); /* throw memory error */
206 }
192 } 207 }
193} 208}
194 209
diff --git a/ltests.c b/ltests.c
index 09876ee7..21273ea9 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1572,6 +1572,9 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
1572 else if EQ("error") { 1572 else if EQ("error") {
1573 lua_error(L1); 1573 lua_error(L1);
1574 } 1574 }
1575 else if EQ("abort") {
1576 abort();
1577 }
1575 else if EQ("throw") { 1578 else if EQ("throw") {
1576#if defined(__cplusplus) 1579#if defined(__cplusplus)
1577static struct X { int x; } x; 1580static struct X { int x; } x;
diff --git a/lvm.c b/lvm.c
index f177ce6a..1cfc1035 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1739,10 +1739,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1739 vmbreak; 1739 vmbreak;
1740 } 1740 }
1741 vmcase(OP_TFORPREP) { 1741 vmcase(OP_TFORPREP) {
1742 if (!ttisnil(s2v(ra + 3))) { /* is 'toclose' not nil? */ 1742 /* create to-be-closed upvalue (if needed) */
1743 /* create to-be-closed upvalue for it */ 1743 halfProtect(luaF_newtbcupval(L, ra + 3));
1744 halfProtect(luaF_newtbcupval(L, ra + 3));
1745 }
1746 pc += GETARG_Bx(i); 1744 pc += GETARG_Bx(i);
1747 i = *(pc++); /* go to next instruction */ 1745 i = *(pc++); /* go to next instruction */
1748 lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); 1746 lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i));
diff --git a/manual/manual.of b/manual/manual.of
index 1646f113..8eebe9cb 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -1534,15 +1534,17 @@ or exiting by an error.
1534 1534
1535Here, to @emph{close} a value means 1535Here, to @emph{close} a value means
1536to call its @idx{__close} metamethod. 1536to call its @idx{__close} metamethod.
1537If the value is @nil, it is ignored;
1538otherwise,
1539if it does not have a @idx{__close} metamethod,
1540an error is raised.
1541When calling the metamethod, 1537When calling the metamethod,
1542the value itself is passed as the first argument 1538the value itself is passed as the first argument
1543and the error object (if any) is passed as a second argument; 1539and the error object that caused the exit (if any)
1540is passed as a second argument;
1544if there was no error, the second argument is @nil. 1541if there was no error, the second argument is @nil.
1545 1542
1543The value assigned to a to-be-closed variable
1544must have a @idx{__close} metamethod
1545or be a false value.
1546(@nil and @false are ignored as to-be-closed values.)
1547
1546If several to-be-closed variables go out of scope at the same event, 1548If several to-be-closed variables go out of scope at the same event,
1547they are closed in the reverse order that they were declared. 1549they are closed in the reverse order that they were declared.
1548 1550
@@ -2917,8 +2919,9 @@ it is left unchanged.
2917@APIEntry{void lua_close (lua_State *L);| 2919@APIEntry{void lua_close (lua_State *L);|
2918@apii{0,0,-} 2920@apii{0,0,-}
2919 2921
2920Destroys all objects in the given Lua state 2922Close all active to-be-closed variables in the main thread,
2921(calling the corresponding garbage-collection metamethods, if any) 2923release all objects in the given Lua state
2924(calling the corresponding garbage-collection metamethods, if any),
2922and frees all dynamic memory used by this state. 2925and frees all dynamic memory used by this state.
2923 2926
2924On several platforms, you may not need to call this function, 2927On several platforms, you may not need to call this function,
@@ -4186,7 +4189,7 @@ An index marked as to-be-closed should not be removed from the stack
4186by any other function in the API except @Lid{lua_settop} or @Lid{lua_pop}. 4189by any other function in the API except @Lid{lua_settop} or @Lid{lua_pop}.
4187 4190
4188This function should not be called for an index 4191This function should not be called for an index
4189that is equal to or below an already marked to-be-closed index. 4192that is equal to or below an active to-be-closed index.
4190 4193
4191This function can raise an out-of-memory error. 4194This function can raise an out-of-memory error.
4192In that case, the value in the given index is immediately closed, 4195In that case, the value in the given index is immediately closed,
diff --git a/testes/api.lua b/testes/api.lua
index 3f7f7596..f6915c3e 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -1096,7 +1096,7 @@ do
1096 assert(type(a[1]) == "string" and a[2][1] == 11) 1096 assert(type(a[1]) == "string" and a[2][1] == 11)
1097 assert(#openresource == 0) -- was closed 1097 assert(#openresource == 0) -- was closed
1098 1098
1099 -- error 1099 -- closing by error
1100 local a, b = pcall(T.makeCfunc[[ 1100 local a, b = pcall(T.makeCfunc[[
1101 call 0 1 # create resource 1101 call 0 1 # create resource
1102 toclose -1 # mark it to be closed 1102 toclose -1 # mark it to be closed
@@ -1105,6 +1105,15 @@ do
1105 assert(a == false and b[1] == 11) 1105 assert(a == false and b[1] == 11)
1106 assert(#openresource == 0) -- was closed 1106 assert(#openresource == 0) -- was closed
1107 1107
1108 -- non-closable value
1109 local a, b = pcall(T.makeCfunc[[
1110 newtable # create non-closable object
1111 toclose -1 # mark it to be closed (shoud raise an error)
1112 abort # will not be executed
1113 ]])
1114 assert(a == false and
1115 string.find(b, "non%-closable value"))
1116
1108 local function check (n) 1117 local function check (n)
1109 assert(#openresource == n) 1118 assert(#openresource == n)
1110 end 1119 end
diff --git a/testes/locals.lua b/testes/locals.lua
index 3b145ca3..6eb1ba0e 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -215,11 +215,13 @@ end
215do 215do
216 local a = {} 216 local a = {}
217 do 217 do
218 local b <close> = false -- not to be closed
218 local x <close> = setmetatable({"x"}, {__close = function (self) 219 local x <close> = setmetatable({"x"}, {__close = function (self)
219 a[#a + 1] = self[1] end}) 220 a[#a + 1] = self[1] end})
220 local w, y <close>, z = func2close(function (self, err) 221 local w, y <close>, z = func2close(function (self, err)
221 assert(err == nil); a[#a + 1] = "y" 222 assert(err == nil); a[#a + 1] = "y"
222 end, 10, 20) 223 end, 10, 20)
224 local c <close> = nil -- not to be closed
223 a[#a + 1] = "in" 225 a[#a + 1] = "in"
224 assert(w == 10 and z == 20) 226 assert(w == 10 and z == 20)
225 end 227 end
@@ -325,24 +327,22 @@ do -- errors in __close
325end 327end
326 328
327 329
328do 330do -- errors due to non-closable values
329
330 -- errors due to non-closable values
331 local function foo () 331 local function foo ()
332 local x <close> = {} 332 local x <close> = {}
333 os.exit(false) -- should not run
333 end 334 end
334 local stat, msg = pcall(foo) 335 local stat, msg = pcall(foo)
335 assert(not stat and string.find(msg, "variable 'x'")) 336 assert(not stat and
337 string.find(msg, "variable 'x' got a non%-closable value"))
336 338
337
338 -- with other errors, non-closable values are ignored
339 local function foo () 339 local function foo ()
340 local x <close> = 34 340 local xyz <close> = setmetatable({}, {__close = print})
341 local y <close> = func2close(function () error(32) end) 341 getmetatable(xyz).__close = nil -- remove metamethod
342 end 342 end
343 local stat, msg = pcall(foo) 343 local stat, msg = pcall(foo)
344 assert(not stat and msg == 32) 344 assert(not stat and
345 345 string.find(msg, "attempt to close non%-closable variable 'xyz'"))
346end 346end
347 347
348 348
@@ -519,7 +519,8 @@ end
519-- a suspended coroutine should not close its variables when collected 519-- a suspended coroutine should not close its variables when collected
520local co 520local co
521co = coroutine.wrap(function() 521co = coroutine.wrap(function()
522 local x <close> = function () os.exit(false) end -- should not run 522 -- should not run
523 local x <close> = func2close(function () os.exit(false) end)
523 co = nil 524 co = nil
524 coroutine.yield() 525 coroutine.yield()
525end) 526end)