diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-06-16 16:29:32 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-06-16 16:29:32 -0300 |
| commit | 9386e49a3173b68e8b5a7ba882c4c2faf557b61e (patch) | |
| tree | 01de173acfac35de39aec9d4398dc0395a080ce5 | |
| parent | 8cd7ae7da06f54b97f95d6994d6bf47086e4e7eb (diff) | |
| download | lua-9386e49a3173b68e8b5a7ba882c4c2faf557b61e.tar.gz lua-9386e49a3173b68e8b5a7ba882c4c2faf557b61e.tar.bz2 lua-9386e49a3173b68e8b5a7ba882c4c2faf557b61e.zip | |
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.
| -rw-r--r-- | lgc.c | 7 | ||||
| -rw-r--r-- | testes/gc.lua | 10 |
2 files changed, 15 insertions, 2 deletions
| @@ -617,8 +617,11 @@ static l_mem traversetable (global_State *g, Table *h) { | |||
| 617 | case 2: /* weak keys */ | 617 | case 2: /* weak keys */ |
| 618 | traverseephemeron(g, h, 0); | 618 | traverseephemeron(g, h, 0); |
| 619 | break; | 619 | break; |
| 620 | case 3: /* all weak */ | 620 | case 3: /* all weak; nothing to traverse */ |
| 621 | linkgclist(h, g->allweak); /* nothing to traverse now */ | 621 | if (g->gcstate == GCSpropagate) |
| 622 | linkgclist(h, g->grayagain); /* must visit again its metatable */ | ||
| 623 | else | ||
| 624 | linkgclist(h, g->allweak); /* must clear collected entries */ | ||
| 622 | break; | 625 | break; |
| 623 | } | 626 | } |
| 624 | return 1 + 2*sizenode(h) + h->asize; | 627 | return 1 + 2*sizenode(h) + h->asize; |
diff --git a/testes/gc.lua b/testes/gc.lua index 5d2b3085..62713dac 100644 --- a/testes/gc.lua +++ b/testes/gc.lua | |||
| @@ -294,6 +294,16 @@ do -- invalid mode | |||
| 294 | end | 294 | end |
| 295 | 295 | ||
| 296 | 296 | ||
| 297 | if T then -- bug since 5.3: all-weak tables are not being revisited | ||
| 298 | T.gcstate("propagate") | ||
| 299 | local t = setmetatable({}, {__mode = "kv"}) | ||
| 300 | T.gcstate("enteratomic") -- 't' was visited | ||
| 301 | setmetatable(t, {__mode = "kv"}) | ||
| 302 | T.gcstate("pause") -- its new metatable is not being visited | ||
| 303 | assert(getmetatable(t).__mode == "kv") | ||
| 304 | end | ||
| 305 | |||
| 306 | |||
| 297 | -- 'bug' in 5.1 | 307 | -- 'bug' in 5.1 |
| 298 | a = {} | 308 | a = {} |
| 299 | local t = {x = 10} | 309 | local t = {x = 10} |
