diff options
| author | Roberto I <roberto@inf.puc-rio.br> | 2026-07-13 15:55:36 -0300 |
|---|---|---|
| committer | Roberto I <roberto@inf.puc-rio.br> | 2026-07-13 15:55:36 -0300 |
| commit | 0f781f836ab348716eb9232d3831a871b9821a3c (patch) | |
| tree | 2bdc431f9d920ae418c5ce6fb1569fb984234ed4 | |
| parent | 934fdd481ced3a9d4a7aaace4479ce889ab23582 (diff) | |
| download | lua-0f781f836ab348716eb9232d3831a871b9821a3c.tar.gz lua-0f781f836ab348716eb9232d3831a871b9821a3c.tar.bz2 lua-0f781f836ab348716eb9232d3831a871b9821a3c.zip | |
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.
| -rw-r--r-- | lvm.c | 7 | ||||
| -rw-r--r-- | testes/events.lua | 10 |
2 files changed, 16 insertions, 1 deletions
| @@ -361,7 +361,12 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
| 361 | } | 361 | } |
| 362 | t = tm; /* else repeat assignment over 'tm' */ | 362 | t = tm; /* else repeat assignment over 'tm' */ |
| 363 | if (luaV_fastget(L, t, key, slot, luaH_get)) { | 363 | if (luaV_fastget(L, t, key, slot, luaH_get)) { |
| 364 | luaV_finishfastset(L, t, slot, val); | 364 | /* execute 'luaV_finishfastset', but preserving the original 't' |
| 365 | for the barrier. 't' and 'slot' can point to the same value, | ||
| 366 | and so the assignment can change 't' value */ | ||
| 367 | GCObject *h = gcvalue(t); | ||
| 368 | setobj2t(L, cast(TValue *,slot), val); | ||
| 369 | luaC_barrierback(L, h, val); | ||
| 365 | return; /* done */ | 370 | return; /* done */ |
| 366 | } | 371 | } |
| 367 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ | 372 | /* 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 | |||
| 382 | end | 382 | end |
| 383 | 383 | ||
| 384 | 384 | ||
| 385 | do -- bug in 5.4 | ||
| 386 | local parent = {} | ||
| 387 | parent.__newindex = parent | ||
| 388 | collectgarbage() | ||
| 389 | local child = setmetatable({}, parent) | ||
| 390 | child.__newindex = {x = "hello"} | ||
| 391 | collectgarbage("step") | ||
| 392 | assert(parent.__newindex.x == "hello") | ||
| 393 | end | ||
| 394 | |||
| 385 | 395 | ||
| 386 | -- concat metamethod x numbers (bug in 5.1.1) | 396 | -- concat metamethod x numbers (bug in 5.1.1) |
| 387 | c = {} | 397 | c = {} |
