diff options
-rw-r--r-- | lfunc.c | 49 | ||||
-rw-r--r-- | ltests.c | 3 | ||||
-rw-r--r-- | lvm.c | 6 | ||||
-rw-r--r-- | manual/manual.of | 19 | ||||
-rw-r--r-- | testes/api.lua | 11 | ||||
-rw-r--r-- | testes/locals.lua | 23 |
6 files changed, 70 insertions, 41 deletions
@@ -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 | */ | ||
130 | static 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 | */ |
172 | static void trynewtbcupval (lua_State *L, void *ud) { | 180 | static 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 | */ |
184 | void luaF_newtbcupval (lua_State *L, StkId level) { | 190 | void 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 | ||
@@ -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) |
1577 | static struct X { int x; } x; | 1580 | static struct X { int x; } x; |
@@ -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 | ||
1535 | Here, to @emph{close} a value means | 1535 | Here, to @emph{close} a value means |
1536 | to call its @idx{__close} metamethod. | 1536 | to call its @idx{__close} metamethod. |
1537 | If the value is @nil, it is ignored; | ||
1538 | otherwise, | ||
1539 | if it does not have a @idx{__close} metamethod, | ||
1540 | an error is raised. | ||
1541 | When calling the metamethod, | 1537 | When calling the metamethod, |
1542 | the value itself is passed as the first argument | 1538 | the value itself is passed as the first argument |
1543 | and the error object (if any) is passed as a second argument; | 1539 | and the error object that caused the exit (if any) |
1540 | is passed as a second argument; | ||
1544 | if there was no error, the second argument is @nil. | 1541 | if there was no error, the second argument is @nil. |
1545 | 1542 | ||
1543 | The value assigned to a to-be-closed variable | ||
1544 | must have a @idx{__close} metamethod | ||
1545 | or be a false value. | ||
1546 | (@nil and @false are ignored as to-be-closed values.) | ||
1547 | |||
1546 | If several to-be-closed variables go out of scope at the same event, | 1548 | If several to-be-closed variables go out of scope at the same event, |
1547 | they are closed in the reverse order that they were declared. | 1549 | they 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 | ||
2920 | Destroys all objects in the given Lua state | 2922 | Close all active to-be-closed variables in the main thread, |
2921 | (calling the corresponding garbage-collection metamethods, if any) | 2923 | release all objects in the given Lua state |
2924 | (calling the corresponding garbage-collection metamethods, if any), | ||
2922 | and frees all dynamic memory used by this state. | 2925 | and frees all dynamic memory used by this state. |
2923 | 2926 | ||
2924 | On several platforms, you may not need to call this function, | 2927 | On 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 | |||
4186 | by any other function in the API except @Lid{lua_settop} or @Lid{lua_pop}. | 4189 | by any other function in the API except @Lid{lua_settop} or @Lid{lua_pop}. |
4187 | 4190 | ||
4188 | This function should not be called for an index | 4191 | This function should not be called for an index |
4189 | that is equal to or below an already marked to-be-closed index. | 4192 | that is equal to or below an active to-be-closed index. |
4190 | 4193 | ||
4191 | This function can raise an out-of-memory error. | 4194 | This function can raise an out-of-memory error. |
4192 | In that case, the value in the given index is immediately closed, | 4195 | In 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 | |||
215 | do | 215 | do |
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 | |||
325 | end | 327 | end |
326 | 328 | ||
327 | 329 | ||
328 | do | 330 | do -- 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'")) | |
346 | end | 346 | end |
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 |
520 | local co | 520 | local co |
521 | co = coroutine.wrap(function() | 521 | co = 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() |
525 | end) | 526 | end) |