aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ldo.c1
-rw-r--r--lfunc.c24
-rw-r--r--ltests.c18
-rw-r--r--manual/manual.of34
-rw-r--r--testes/api.lua19
-rw-r--r--testes/coroutine.lua13
-rw-r--r--testes/goto.lua2
-rw-r--r--testes/locals.lua54
8 files changed, 97 insertions, 68 deletions
diff --git a/ldo.c b/ldo.c
index f8d8f11c..077109c4 100644
--- a/ldo.c
+++ b/ldo.c
@@ -118,6 +118,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
118 } 118 }
119 else { /* thread has no error handler */ 119 else { /* thread has no error handler */
120 global_State *g = G(L); 120 global_State *g = G(L);
121 errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */
121 L->status = cast_byte(errcode); /* mark it as dead */ 122 L->status = cast_byte(errcode); /* mark it as dead */
122 if (g->mainthread->errorJmp) { /* main thread has a handler? */ 123 if (g->mainthread->errorJmp) { /* main thread has a handler? */
123 setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ 124 setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
diff --git a/lfunc.c b/lfunc.c
index bdf3cd25..362b798c 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -100,28 +100,23 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
100 100
101static void callclose (lua_State *L, void *ud) { 101static void callclose (lua_State *L, void *ud) {
102 UNUSED(ud); 102 UNUSED(ud);
103 luaD_callnoyield(L, L->top - 2, 0); 103 luaD_callnoyield(L, L->top - 3, 0);
104} 104}
105 105
106 106
107/* 107/*
108** Prepare closing method plus its argument for object 'obj' with 108** Prepare closing method plus its arguments for object 'obj' with
109** error message 'err'. (This function assumes EXTRA_STACK.) 109** error message 'err'. (This function assumes EXTRA_STACK.)
110*/ 110*/
111static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { 111static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) {
112 StkId top = L->top; 112 StkId top = L->top;
113 if (ttisfunction(obj)) { /* object to-be-closed is a function? */ 113 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
114 setobj2s(L, top, obj); /* push function */ 114 if (ttisnil(tm)) /* no metamethod? */
115 setobj2s(L, top + 1, err); /* push error msg. as argument */ 115 return 0; /* nothing to call */
116 } 116 setobj2s(L, top, tm); /* will call metamethod... */
117 else { /* try '__close' metamethod */ 117 setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
118 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); 118 setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
119 if (ttisnil(tm)) /* no metamethod? */ 119 L->top = top + 3; /* add function and arguments */
120 return 0; /* nothing to call */
121 setobj2s(L, top, tm); /* will call metamethod... */
122 setobj2s(L, top + 1, obj); /* with 'self' as the argument */
123 }
124 L->top = top + 2; /* add function and argument */
125 return 1; 120 return 1;
126} 121}
127 122
@@ -156,6 +151,7 @@ static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) {
156 if (newstatus != LUA_OK) /* another error when closing? */ 151 if (newstatus != LUA_OK) /* another error when closing? */
157 status = newstatus; /* this will be the new error */ 152 status = newstatus; /* this will be the new error */
158 } 153 }
154 /* else no metamethod; ignore this case and keep original error */
159 } 155 }
160 return status; 156 return status;
161} 157}
diff --git a/ltests.c b/ltests.c
index 0cb6d3a7..36a974ae 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1201,8 +1201,8 @@ static const char *const delimits = " \t\n,;";
1201static void skip (const char **pc) { 1201static void skip (const char **pc) {
1202 for (;;) { 1202 for (;;) {
1203 if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; 1203 if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++;
1204 else if (**pc == '#') { 1204 else if (**pc == '#') { /* comment? */
1205 while (**pc != '\n' && **pc != '\0') (*pc)++; 1205 while (**pc != '\n' && **pc != '\0') (*pc)++; /* until end-of-line */
1206 } 1206 }
1207 else break; 1207 else break;
1208 } 1208 }
@@ -1544,18 +1544,22 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
1544 } 1544 }
1545 else if EQ("setfield") { 1545 else if EQ("setfield") {
1546 int t = getindex; 1546 int t = getindex;
1547 lua_setfield(L1, t, getstring); 1547 const char *s = getstring;
1548 lua_setfield(L1, t, s);
1548 } 1549 }
1549 else if EQ("setglobal") { 1550 else if EQ("setglobal") {
1550 lua_setglobal(L1, getstring); 1551 const char *s = getstring;
1552 lua_setglobal(L1, s);
1551 } 1553 }
1552 else if EQ("sethook") { 1554 else if EQ("sethook") {
1553 int mask = getnum; 1555 int mask = getnum;
1554 int count = getnum; 1556 int count = getnum;
1555 sethookaux(L1, mask, count, getstring); 1557 const char *s = getstring;
1558 sethookaux(L1, mask, count, s);
1556 } 1559 }
1557 else if EQ("setmetatable") { 1560 else if EQ("setmetatable") {
1558 lua_setmetatable(L1, getindex); 1561 int idx = getindex;
1562 lua_setmetatable(L1, idx);
1559 } 1563 }
1560 else if EQ("settable") { 1564 else if EQ("settable") {
1561 lua_settable(L1, getindex); 1565 lua_settable(L1, getindex);
@@ -1620,7 +1624,7 @@ static struct X { int x; } x;
1620 return lua_yieldk(L1, nres, i, Cfunck); 1624 return lua_yieldk(L1, nres, i, Cfunck);
1621 } 1625 }
1622 else if EQ("toclose") { 1626 else if EQ("toclose") {
1623 lua_toclose(L, getnum); 1627 lua_toclose(L1, getnum);
1624 } 1628 }
1625 else luaL_error(L, "unknown instruction %s", buff); 1629 else luaL_error(L, "unknown instruction %s", buff);
1626 } 1630 }
diff --git a/manual/manual.of b/manual/manual.of
index d64f0f1a..b9ab1ebe 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -1536,33 +1536,29 @@ goes out of scope, including normal block termination,
1536exiting its block by @Rw{break}/@Rw{goto}/@Rw{return}, 1536exiting its block by @Rw{break}/@Rw{goto}/@Rw{return},
1537or exiting by an error. 1537or exiting by an error.
1538 1538
1539To \emph{close} a value has the following meaning here: 1539Here, to \emph{close} a value means
1540If the value of the variable when it goes out of scope is a function, 1540to call its @idx{__close} metamethod.
1541that function is called; 1541If the value is @nil, it is ignored;
1542otherwise, if the value has a @idx{__close} metamethod, 1542otherwise,
1543that metamethod is called; 1543if it does not have a @idx{__close} metamethod,
1544otherwise, if the value is @nil, nothing is done; 1544an error is raised.
1545otherwise, an error is raised. 1545When calling the metamethod,
1546In the function case, 1546the value itself is passed as the first argument
1547if the scope is being closed by an error, 1547and the error object (if any) is passed as a second argument;
1548the error object is passed as an argument to the function; 1548if there was no error, the second argument is @nil.
1549if there is no error, the function gets @nil.
1550In the metamethod case,
1551the value itself always is passed as an argument to the metamethod.
1552 1549
1553If several to-be-closed variables go out of scope at the same event, 1550If several to-be-closed variables go out of scope at the same event,
1554they are closed in the reverse order that they were declared. 1551they are closed in the reverse order that they were declared.
1555If there is any error while running a closing function, 1552If there is any error while running a closing method,
1556that error is handled like an error in the regular code 1553that error is handled like an error in the regular code
1557where the variable was defined; 1554where the variable was defined;
1558in particular, 1555in particular,
1559the other pending closing functions will still be called. 1556the other pending closing methods will still be called.
1560 1557
1561If a coroutine yields inside a block and is never resumed again, 1558If a coroutine yields inside a block and is never resumed again,
1562the variables visible at that block will never go out of scope, 1559the variables visible at that block will never go out of scope,
1563and therefore they will not be closed. 1560and therefore they will not be closed.
1564Similarly, if a script is interrupted by an unprotected error, 1561(You should use finalizers to handle this case.)
1565its to-be-closed variables will not be closed.
1566 1562
1567} 1563}
1568 1564
@@ -3002,7 +2998,7 @@ and therefore never returns
3002} 2998}
3003 2999
3004@APIEntry{int lua_gc (lua_State *L, int what, int data);| 3000@APIEntry{int lua_gc (lua_State *L, int what, int data);|
3005@apii{0,0,v} 3001@apii{0,0,-}
3006 3002
3007Controls the garbage collector. 3003Controls the garbage collector.
3008 3004
@@ -3056,8 +3052,6 @@ returns a boolean that tells whether the collector is running
3056For more details about these options, 3052For more details about these options,
3057see @Lid{collectgarbage}. 3053see @Lid{collectgarbage}.
3058 3054
3059This function may raise errors when calling finalizers.
3060
3061} 3055}
3062 3056
3063@APIEntry{lua_Alloc lua_getallocf (lua_State *L, void **ud);| 3057@APIEntry{lua_Alloc lua_getallocf (lua_State *L, void **ud);|
diff --git a/testes/api.lua b/testes/api.lua
index 893a36cb..9904dadf 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -396,6 +396,23 @@ do
396 assert(string.find(msg, "stack overflow")) 396 assert(string.find(msg, "stack overflow"))
397 end 397 end
398 398
399 -- exit in panic still close to-be-closed variables
400 assert(T.checkpanic([[
401 pushstring "return {__close = function () Y = 'ho'; end}"
402 newtable
403 loadstring -2
404 call 0 1
405 setmetatable -2
406 toclose -1
407 pushstring "hi"
408 error
409 ]],
410 [[
411 getglobal Y
412 concat 2 # concat original error with global Y
413 ]]) == "hiho")
414
415
399end 416end
400 417
401-- testing deep C stack 418-- testing deep C stack
@@ -1115,7 +1132,7 @@ end)
1115testamem("to-be-closed variables", function() 1132testamem("to-be-closed variables", function()
1116 local flag 1133 local flag
1117 do 1134 do
1118 local *toclose x = function () flag = true end 1135 local *toclose x = setmetatable({}, {__close = function () flag = true end})
1119 flag = false 1136 flag = false
1120 local x = {} 1137 local x = {}
1121 end 1138 end
diff --git a/testes/coroutine.lua b/testes/coroutine.lua
index ca30011f..a4321bed 100644
--- a/testes/coroutine.lua
+++ b/testes/coroutine.lua
@@ -142,8 +142,15 @@ do
142 142
143 -- to-be-closed variables in coroutines 143 -- to-be-closed variables in coroutines
144 local X 144 local X
145
146 local function func2close (f)
147 return setmetatable({}, {__close = f})
148 end
149
145 co = coroutine.create(function () 150 co = coroutine.create(function ()
146 local *toclose x = function (err) assert(err == nil); X = false end 151 local *toclose x = func2close(function (self, err)
152 assert(err == nil); X = false
153 end)
147 X = true 154 X = true
148 coroutine.yield() 155 coroutine.yield()
149 end) 156 end)
@@ -154,7 +161,9 @@ do
154 161
155 -- error killing a coroutine 162 -- error killing a coroutine
156 co = coroutine.create(function() 163 co = coroutine.create(function()
157 local *toclose x = function (err) assert(err == nil); error(111) end 164 local *toclose x = func2close(function (self, err)
165 assert(err == nil); error(111)
166 end)
158 coroutine.yield() 167 coroutine.yield()
159 end) 168 end)
160 coroutine.resume(co) 169 coroutine.resume(co)
diff --git a/testes/goto.lua b/testes/goto.lua
index 5d863a42..f3dcfd4a 100644
--- a/testes/goto.lua
+++ b/testes/goto.lua
@@ -258,7 +258,7 @@ do
258 ::L2:: goto L3 258 ::L2:: goto L3
259 259
260 ::L1:: do 260 ::L1:: do
261 local *toclose a = function () X = true end 261 local *toclose a = setmetatable({}, {__close = function () X = true end})
262 assert(X == nil) 262 assert(X == nil)
263 if a then goto L2 end -- jumping back out of scope of 'a' 263 if a then goto L2 end -- jumping back out of scope of 'a'
264 end 264 end
diff --git a/testes/locals.lua b/testes/locals.lua
index 340af61c..de47ae31 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -177,13 +177,19 @@ print"testing to-be-closed variables"
177 177
178local function stack(n) n = ((n == 0) or stack(n - 1)) end 178local function stack(n) n = ((n == 0) or stack(n - 1)) end
179 179
180local function func2close (f)
181 return setmetatable({}, {__close = f})
182end
183
180 184
181do 185do
182 local a = {} 186 local a = {}
183 do 187 do
184 local *toclose x = setmetatable({"x"}, {__close = function (self) 188 local *toclose x = setmetatable({"x"}, {__close = function (self)
185 a[#a + 1] = self[1] end}) 189 a[#a + 1] = self[1] end})
186 local *toclose y = function (x) assert(x == nil); a[#a + 1] = "y" end 190 local *toclose y = func2close(function (self, err)
191 assert(err == nil); a[#a + 1] = "y"
192 end)
187 a[#a + 1] = "in" 193 a[#a + 1] = "in"
188 end 194 end
189 a[#a + 1] = "out" 195 a[#a + 1] = "out"
@@ -193,7 +199,7 @@ end
193do 199do
194 local X = false 200 local X = false
195 201
196 local function closescope () stack(10); X = true end 202 local closescope = func2close(function () stack(10); X = true end)
197 203
198 -- closing functions do not corrupt returning values 204 -- closing functions do not corrupt returning values
199 local function foo (x) 205 local function foo (x)
@@ -228,13 +234,13 @@ do
228 -- calls cannot be tail in the scope of to-be-closed variables 234 -- calls cannot be tail in the scope of to-be-closed variables
229 local X, Y 235 local X, Y
230 local function foo () 236 local function foo ()
231 local *toclose _ = function () Y = 10 end 237 local *toclose _ = func2close(function () Y = 10 end)
232 assert(X == true and Y == nil) -- 'X' not closed yet 238 assert(X == true and Y == nil) -- 'X' not closed yet
233 return 1,2,3 239 return 1,2,3
234 end 240 end
235 241
236 local function bar () 242 local function bar ()
237 local *toclose _ = function () X = false end 243 local *toclose _ = func2close(function () X = false end)
238 X = true 244 X = true
239 do 245 do
240 return foo() -- not a tail call! 246 return foo() -- not a tail call!
@@ -249,11 +255,15 @@ end
249do -- errors in __close 255do -- errors in __close
250 local log = {} 256 local log = {}
251 local function foo (err) 257 local function foo (err)
252 local *toclose x = function (msg) log[#log + 1] = msg; error(1) end 258 local *toclose x =
253 local *toclose x1 = function (msg) log[#log + 1] = msg; end 259 func2close(function (self, msg) log[#log + 1] = msg; error(1) end)
254 local *toclose gc = function () collectgarbage() end 260 local *toclose x1 =
255 local *toclose y = function (msg) log[#log + 1] = msg; error(2) end 261 func2close(function (self, msg) log[#log + 1] = msg; end)
256 local *toclose z = function (msg) log[#log + 1] = msg or 10; error(3) end 262 local *toclose gc = func2close(function () collectgarbage() end)
263 local *toclose y =
264 func2close(function (self, msg) log[#log + 1] = msg; error(2) end)
265 local *toclose z =
266 func2close(function (self, msg) log[#log + 1] = msg or 10; error(3) end)
257 if err then error(4) end 267 if err then error(4) end
258 end 268 end
259 local stat, msg = pcall(foo, false) 269 local stat, msg = pcall(foo, false)
@@ -282,7 +292,7 @@ do
282 -- with other errors, non-closable values are ignored 292 -- with other errors, non-closable values are ignored
283 local function foo () 293 local function foo ()
284 local *toclose x = 34 294 local *toclose x = 34
285 local *toclose y = function () error(32) end 295 local *toclose y = func2close(function () error(32) end)
286 end 296 end
287 local stat, msg = pcall(foo) 297 local stat, msg = pcall(foo)
288 assert(not stat and msg == 32) 298 assert(not stat and msg == 32)
@@ -294,7 +304,7 @@ if rawget(_G, "T") then
294 304
295 -- memory error inside closing function 305 -- memory error inside closing function
296 local function foo () 306 local function foo ()
297 local *toclose y = function () T.alloccount() end 307 local *toclose y = func2close(function () T.alloccount() end)
298 local *toclose x = setmetatable({}, {__close = function () 308 local *toclose x = setmetatable({}, {__close = function ()
299 T.alloccount(0); local x = {} -- force a memory error 309 T.alloccount(0); local x = {} -- force a memory error
300 end}) 310 end})
@@ -308,12 +318,12 @@ if rawget(_G, "T") then
308 local _, msg = pcall(foo) 318 local _, msg = pcall(foo)
309 assert(msg == "not enough memory") 319 assert(msg == "not enough memory")
310 320
311 local function close (msg) 321 local close = func2close(function (self, msg)
312 T.alloccount() 322 T.alloccount()
313 assert(msg == "not enough memory") 323 assert(msg == "not enough memory")
314 end 324 end)
315 325
316 -- set a memory limit and return a closing function to remove the limit 326 -- set a memory limit and return a closing object to remove the limit
317 local function enter (count) 327 local function enter (count)
318 stack(10) -- reserve some stack space 328 stack(10) -- reserve some stack space
319 T.alloccount(count) 329 T.alloccount(count)
@@ -336,13 +346,13 @@ if rawget(_G, "T") then
336 346
337 -- repeat test with extra closing upvalues 347 -- repeat test with extra closing upvalues
338 local function test () 348 local function test ()
339 local *toclose xxx = function (msg) 349 local *toclose xxx = func2close(function (self, msg)
340 assert(msg == "not enough memory"); 350 assert(msg == "not enough memory");
341 error(1000) -- raise another error 351 error(1000) -- raise another error
342 end 352 end)
343 local *toclose xx = function (msg) 353 local *toclose xx = func2close(function (self, msg)
344 assert(msg == "not enough memory"); 354 assert(msg == "not enough memory");
345 end 355 end)
346 local *toclose x = enter(0) -- set a memory limit 356 local *toclose x = enter(0) -- set a memory limit
347 -- creation of previous upvalue will raise a memory error 357 -- creation of previous upvalue will raise a memory error
348 os.exit(false) -- should not run 358 os.exit(false) -- should not run
@@ -413,9 +423,9 @@ do
413 local x = false 423 local x = false
414 local y = false 424 local y = false
415 local co = coroutine.create(function () 425 local co = coroutine.create(function ()
416 local *toclose xv = function () x = true end 426 local *toclose xv = func2close(function () x = true end)
417 do 427 do
418 local *toclose yv = function () y = true end 428 local *toclose yv = func2close(function () y = true end)
419 coroutine.yield(100) -- yield doesn't close variable 429 coroutine.yield(100) -- yield doesn't close variable
420 end 430 end
421 coroutine.yield(200) -- yield doesn't close variable 431 coroutine.yield(200) -- yield doesn't close variable
@@ -453,9 +463,7 @@ do
453 end, 463 end,
454 nil, -- state 464 nil, -- state
455 nil, -- control variable 465 nil, -- control variable
456 function () -- closing function 466 func2close(function () numopen = numopen - 1 end) -- closing function
457 numopen = numopen - 1
458 end
459 end 467 end
460 468
461 local s = 0 469 local s = 0