mirror of
https://github.com/lua/lua.git
synced 2026-07-25 07:29:05 +00:00
Bug: Issues with write barrier for __newindex
In 'luaV_finishset', there is an update on a table that is a field on another table. If the first table is the same as the one with the field (e.g., after 't.__newindex = t'), the update can change the value on that field (e.g., there may be a collision and the field is moved, or the field being updated is '__newindex' itself). After that, the barrier is called with the table stored in that field, which is not the correct table anymore.
This commit is contained in:
18
lvm.c
18
lvm.c
@@ -360,13 +360,19 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
||||
luaT_callTM(L, tm, t, key, val);
|
||||
return;
|
||||
}
|
||||
t = tm; /* else repeat assignment over 'tm' */
|
||||
luaV_fastset(t, key, val, hres, luaH_pset);
|
||||
if (hres == HOK) {
|
||||
luaV_finishfastset(L, t, val);
|
||||
return; /* done */
|
||||
t = tm; /* else must repeat assignment over 'tm' */
|
||||
/* do the equivalent to 'luaV_fastset', but saving 'h' */
|
||||
if (!ttistable(t))
|
||||
hres = HNOTATABLE;
|
||||
else {
|
||||
Table *h = hvalue(t); /* next call can change the value at 't' */
|
||||
hres = luaH_pset(h, key, val);
|
||||
if (hres == HOK) {
|
||||
luaC_barrierback(L, obj2gco(h), val); /* luaV_finishfastset */
|
||||
return; /* done */
|
||||
}
|
||||
}
|
||||
/* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */
|
||||
/* else 'return luaV_finishset(L, t, key, val, hres)' (loop) */
|
||||
}
|
||||
luaG_runerror(L, "'__newindex' chain too long; possible loop");
|
||||
}
|
||||
|
||||
@@ -390,6 +390,18 @@ do
|
||||
for i=1, 10 do t[i] = 1 end
|
||||
end
|
||||
|
||||
|
||||
do -- bug since 5.4
|
||||
local parent = {}
|
||||
parent.__newindex = parent
|
||||
collectgarbage()
|
||||
local child = setmetatable({}, parent)
|
||||
child.__newindex = {x = "hello"}
|
||||
collectgarbage("step")
|
||||
assert(parent.__newindex.x == "hello")
|
||||
end
|
||||
|
||||
|
||||
-- concat metamethod x numbers (bug in 5.1.1)
|
||||
c = {}
|
||||
local x
|
||||
|
||||
Reference in New Issue
Block a user