diff options
| author | Roberto I <roberto@inf.puc-rio.br> | 2026-07-12 14:57:55 -0300 |
|---|---|---|
| committer | Roberto I <roberto@inf.puc-rio.br> | 2026-07-12 14:57:55 -0300 |
| commit | b996f8fd1be7fb711cc6f754a31a1c87d2c2fd9b (patch) | |
| tree | 575dd4819e9fbf7e7696908cf779b6f55825f181 /lvm.c | |
| parent | bc4bbcef651ba2870d6c68db16dc7d6ce6f68636 (diff) | |
| download | lua-b996f8fd1be7fb711cc6f754a31a1c87d2c2fd9b.tar.gz lua-b996f8fd1be7fb711cc6f754a31a1c87d2c2fd9b.tar.bz2 lua-b996f8fd1be7fb711cc6f754a31a1c87d2c2fd9b.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 (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.
Diffstat (limited to 'lvm.c')
| -rw-r--r-- | lvm.c | 18 |
1 files changed, 12 insertions, 6 deletions
| @@ -360,13 +360,19 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
| 360 | luaT_callTM(L, tm, t, key, val); | 360 | luaT_callTM(L, tm, t, key, val); |
| 361 | return; | 361 | return; |
| 362 | } | 362 | } |
| 363 | t = tm; /* else repeat assignment over 'tm' */ | 363 | t = tm; /* else must repeat assignment over 'tm' */ |
| 364 | luaV_fastset(t, key, val, hres, luaH_pset); | 364 | /* do the equivalent to 'luaV_fastset', but saving 'h' */ |
| 365 | if (hres == HOK) { | 365 | if (!ttistable(t)) |
| 366 | luaV_finishfastset(L, t, val); | 366 | hres = HNOTATABLE; |
| 367 | return; /* done */ | 367 | else { |
| 368 | Table *h = hvalue(t); /* next call can change the value at 't' */ | ||
| 369 | hres = luaH_pset(h, key, val); | ||
| 370 | if (hres == HOK) { | ||
| 371 | luaC_barrierback(L, obj2gco(h), val); /* luaV_finishfastset */ | ||
| 372 | return; /* done */ | ||
| 373 | } | ||
| 368 | } | 374 | } |
| 369 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ | 375 | /* else 'return luaV_finishset(L, t, key, val, hres)' (loop) */ |
| 370 | } | 376 | } |
| 371 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); | 377 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); |
| 372 | } | 378 | } |
