New metatable in an all-weak table can fool the GC
All-weak tables are not being revisited after being visited during propagation; if it gets a new metatable after that, the new metatable may not be marked.
This commit is contained in:
7
lgc.c
7
lgc.c
@@ -617,8 +617,11 @@ static l_mem traversetable (global_State *g, Table *h) {
|
|||||||
case 2: /* weak keys */
|
case 2: /* weak keys */
|
||||||
traverseephemeron(g, h, 0);
|
traverseephemeron(g, h, 0);
|
||||||
break;
|
break;
|
||||||
case 3: /* all weak */
|
case 3: /* all weak; nothing to traverse */
|
||||||
linkgclist(h, g->allweak); /* nothing to traverse now */
|
if (g->gcstate == GCSpropagate)
|
||||||
|
linkgclist(h, g->grayagain); /* must visit again its metatable */
|
||||||
|
else
|
||||||
|
linkgclist(h, g->allweak); /* must clear collected entries */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1 + 2*sizenode(h) + h->asize;
|
return 1 + 2*sizenode(h) + h->asize;
|
||||||
|
|||||||
@@ -294,6 +294,16 @@ do -- invalid mode
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if T then -- bug since 5.3: all-weak tables are not being revisited
|
||||||
|
T.gcstate("propagate")
|
||||||
|
local t = setmetatable({}, {__mode = "kv"})
|
||||||
|
T.gcstate("enteratomic") -- 't' was visited
|
||||||
|
setmetatable(t, {__mode = "kv"})
|
||||||
|
T.gcstate("pause") -- its new metatable is not being visited
|
||||||
|
assert(getmetatable(t).__mode == "kv")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- 'bug' in 5.1
|
-- 'bug' in 5.1
|
||||||
a = {}
|
a = {}
|
||||||
local t = {x = 10}
|
local t = {x = 10}
|
||||||
|
|||||||
Reference in New Issue
Block a user