LibGC: Prune weak containers in stop-the-world phase of GC

Move weak container cleanup (remove_dead_cells) out of both
sweep_dead_cells() and start_incremental_sweep() to the place
where it is actually safe to inspect cell state: collect_garbage().

Previously, remove_dead_cells could access cells that had already
been swept and poisoned by ASAN, causing use-after-poison crashes
when a new GC triggered while an incremental sweep was in progress.
This commit is contained in:
Andreas Kling
2026-01-29 01:37:18 +01:00
committed by Andreas Kling
parent fb4095ae50
commit 245b7d74a7
Notes: github-actions[bot] 2026-05-10 09:00:20 +00:00
12 changed files with 27 additions and 18 deletions

View File

@@ -341,13 +341,16 @@ StaticPropertyLookupCache::StaticPropertyLookupCache()
static void clear_cache_entry_if_dead(PropertyLookupCache::Entry& entry)
{
if (entry.from_shape && entry.from_shape->state() != Cell::State::Live)
auto cell_is_dead = [](Cell const* cell) {
return cell->state() != Cell::State::Live || !cell->is_marked();
};
if (entry.from_shape && cell_is_dead(entry.from_shape))
entry.from_shape = nullptr;
if (entry.shape && entry.shape->state() != Cell::State::Live)
if (entry.shape && cell_is_dead(entry.shape))
entry.shape = nullptr;
if (entry.prototype && entry.prototype->state() != Cell::State::Live)
if (entry.prototype && cell_is_dead(entry.prototype))
entry.prototype = nullptr;
if (entry.prototype_chain_validity && entry.prototype_chain_validity->state() != Cell::State::Live)
if (entry.prototype_chain_validity && cell_is_dead(entry.prototype_chain_validity))
entry.prototype_chain_validity = nullptr;
}
@@ -370,7 +373,7 @@ void Executable::remove_dead_cells(Badge<GC::Heap>)
clear_cache_entry_if_dead(entry);
}
for (auto& cache : object_shape_caches) {
if (cache.shape && cache.shape->state() != Cell::State::Live)
if (cache.shape && (cache.shape->state() != Cell::State::Live || !cache.shape->is_marked()))
cache.shape = nullptr;
}
}