From c23cc86c542449db47bdb21e9550203309bef045 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 7 Oct 2020 11:45:23 -0300 Subject: [PATCH] Details - After converting a generic GCObject to a specific type ('gco2*'), avoid using the original GCObject (to reduce aliasing). - Small corrections in comments in 'lopcodes.h' - Added tests about who calls __close metamethods --- lfunc.c | 2 +- lgc.c | 30 +++++++++++++++++++----------- lopcodes.h | 4 ++-- testes/locals.lua | 23 +++++++++++++++++++++++ 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/lfunc.c b/lfunc.c index 88d45328..c4360f09 100644 --- a/lfunc.c +++ b/lfunc.c @@ -53,7 +53,7 @@ void luaF_initupvals (lua_State *L, LClosure *cl) { uv->v = &uv->u.value; /* make it closed */ setnilvalue(uv->v); cl->upvals[i] = uv; - luaC_objbarrier(L, cl, o); + luaC_objbarrier(L, cl, uv); } } diff --git a/lgc.c b/lgc.c index 3b8d0ed6..03326df3 100644 --- a/lgc.c +++ b/lgc.c @@ -301,7 +301,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { if (upisopen(uv)) set2gray(uv); /* open upvalues are kept gray */ else - set2black(o); /* closed upvalues are visited here */ + set2black(uv); /* closed upvalues are visited here */ markvalue(g, uv->v); /* mark its content */ break; } @@ -309,7 +309,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { Udata *u = gco2u(o); if (u->nuvalue == 0) { /* no user values? */ markobjectN(g, u->metatable); /* mark its metatable */ - set2black(o); /* nothing else to mark */ + set2black(u); /* nothing else to mark */ break; } /* else... */ @@ -770,12 +770,16 @@ static void freeobj (lua_State *L, GCObject *o) { case LUA_VUPVAL: freeupval(L, gco2upv(o)); break; - case LUA_VLCL: - luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); + case LUA_VLCL: { + LClosure *cl = gco2lcl(o); + luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); break; - case LUA_VCCL: - luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); + } + case LUA_VCCL: { + CClosure *cl = gco2ccl(o); + luaM_freemem(L, cl, sizeCclosure(cl->nupvalues)); break; + } case LUA_VTABLE: luaH_free(L, gco2t(o)); break; @@ -787,13 +791,17 @@ static void freeobj (lua_State *L, GCObject *o) { luaM_freemem(L, o, sizeudata(u->nuvalue, u->len)); break; } - case LUA_VSHRSTR: - luaS_remove(L, gco2ts(o)); /* remove it from hash table */ - luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); + case LUA_VSHRSTR: { + TString *ts = gco2ts(o); + luaS_remove(L, ts); /* remove it from hash table */ + luaM_freemem(L, ts, sizelstring(ts->shrlen)); break; - case LUA_VLNGSTR: - luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); + } + case LUA_VLNGSTR: { + TString *ts = gco2ts(o); + luaM_freemem(L, ts, sizelstring(ts->u.lnglen)); break; + } default: lua_assert(0); } } diff --git a/lopcodes.h b/lopcodes.h index 122e5d21..120cdd94 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -261,7 +261,7 @@ OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */ OP_UNM,/* A B R[A] := -R[B] */ OP_BNOT,/* A B R[A] := ~R[B] */ OP_NOT,/* A B R[A] := not R[B] */ -OP_LEN,/* A B R[A] := length of R[B] */ +OP_LEN,/* A B R[A] := #R[B] (length operator) */ OP_CONCAT,/* A B R[A] := R[A].. ... ..R[A + B - 1] */ @@ -297,7 +297,7 @@ OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */ OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */ OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */ -OP_SETLIST,/* A B C k R[A][(C-1)*FPF+i] := R[A+i], 1 <= i <= B */ +OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */ OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */ diff --git a/testes/locals.lua b/testes/locals.lua index f5e96244..df44b86f 100644 --- a/testes/locals.lua +++ b/testes/locals.lua @@ -246,6 +246,11 @@ do X = false foo = function (x) + local _ = func2close(function () + -- without errors, enclosing function should be still active when + -- __close is called + assert(debug.getinfo(2).name == "foo") + end) local _ = closescope local y = 15 return y @@ -343,6 +348,18 @@ local function endwarn () end +-- errors inside __close can generate a warning instead of an +-- error. This new 'assert' force them to appear. +local function assert(cond, msg) + if not cond then + local line = debug.getinfo(2).currentline or "?" + msg = string.format("assertion failed! line %d (%s)\n", line, msg or "") + io.stderr:write(msg) + os.exit(1) + end +end + + local function checkwarn (msg) if T then assert(string.find(_WARN, msg)) @@ -406,11 +423,15 @@ do print("testing errors in __close") local x = func2close(function (self, msg) + -- after error, 'foo' was discarded, so caller now + -- must be 'pcall' + assert(debug.getinfo(2).name == "pcall") assert(msg == 4) end) local x1 = func2close(function (self, msg) + assert(debug.getinfo(2).name == "pcall") checkwarn("@y") assert(msg == 4) error("@x1") @@ -420,6 +441,7 @@ do print("testing errors in __close") local y = func2close(function (self, msg) + assert(debug.getinfo(2).name == "pcall") assert(msg == 4) -- error in body checkwarn("@z") error("@y") @@ -428,6 +450,7 @@ do print("testing errors in __close") local first = true local z = func2close(function (self, msg) + assert(debug.getinfo(2).name == "pcall") -- 'z' close is called once assert(first and msg == 4) first = false