From 0f781f836ab348716eb9232d3831a871b9821a3c Mon Sep 17 00:00:00 2001 From: Roberto I Date: Mon, 13 Jul 2026 15:55:36 -0300 Subject: 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 (if 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. --- lvm.c | 7 ++++++- testes/events.lua | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lvm.c b/lvm.c index 7023a04d..bbadf0a6 100644 --- a/lvm.c +++ b/lvm.c @@ -361,7 +361,12 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, } t = tm; /* else repeat assignment over 'tm' */ if (luaV_fastget(L, t, key, slot, luaH_get)) { - luaV_finishfastset(L, t, slot, val); + /* execute 'luaV_finishfastset', but preserving the original 't' + for the barrier. 't' and 'slot' can point to the same value, + and so the assignment can change 't' value */ + GCObject *h = gcvalue(t); + setobj2t(L, cast(TValue *,slot), val); + luaC_barrierback(L, h, val); return; /* done */ } /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ diff --git a/testes/events.lua b/testes/events.lua index def13dc8..d0a48c66 100644 --- a/testes/events.lua +++ b/testes/events.lua @@ -382,6 +382,16 @@ do end +do -- bug in 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 = {} -- cgit v1.2.3-55-g6feb