Skip to content

Commit 737e8bd

Browse files
committed
fix(patch): mark ephemeron values reached from resurrected finalizer keys
* The resurrection closure drained via `MarkTransitiveClosureFixpoint()` in the default worklist mode. Once the main closure ends in `MarkTransitiveClosureLinear()`, unresolved ephemerons live in `key_to_values_` rather than `next_ephemerons`, and only the `kProcessRememberedEphemerons` mode consults that map -- so the values of a resurrected WeakMap key were never marked. * Linear is the common terminal path, not a rare fallback: `ProcessEphemeron` reports progress for every `kUnresolved` entry, so a single persistently unresolved ephemeron spins the fixpoint out to its iteration cap. A resurrected key is itself such an entry, so the objects that trigger the bug are the same ones that force the algorithm that exposes it. * `ClearWeakCollections()` keeps any entry whose key is marked and inspects the value only under VERIFY_HEAP, so the entry survived into a live table with a value pointing at a page that sweeping then released. * Drain in remembered-ephemerons mode before the fixpoint/linear pair. Sound unconditionally: fixpoint success implies `key_to_values_` is empty, so the block needs no flag telling it which algorithm ended the main closure, and neither `SetKeyToValues`' nor `MarkTransitiveClosureLinear`'s DCHECK can fire. `VerifyEphemeronMarking()` afterwards is a no-op outside --verify-heap builds.
1 parent fb6007e commit 737e8bd

1 file changed

Lines changed: 13 additions & 1 deletion

File tree

‎patches/v8_resurrecting_finalizers.patch‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc
339339
index b65cd3af3e0..d81667a115e 100644
340340
--- a/src/heap/mark-compact.cc
341341
+++ b/src/heap/mark-compact.cc
342-
@@ -2661,6 +2661,31 @@ void MarkCompactCollector::MarkLiveObjects() {
342+
@@ -2661,6 +2661,43 @@ void MarkCompactCollector::MarkLiveObjects() {
343343
VerifyEphemeronMarking();
344344
}
345345

@@ -359,13 +359,25 @@ index b65cd3af3e0..d81667a115e 100644
359359
+ &IsUnmarkedHeapObject);
360360
+ heap_->isolate()->global_handles()->IterateFinalizerHandlesAsRoots(
361361
+ &root_visitor);
362+
+ // Once the closure above ends in `MarkTransitiveClosureLinear()`,
363+
+ // unresolved ephemerons live in `key_to_values_`, which only the
364+
+ // `kProcessRememberedEphemerons` worklist mode consults. Draining the
365+
+ // resurrected closure in any other mode marks a resurrected WeakMap key
366+
+ // while leaving its value unmarked; `ClearWeakCollections()` tests only
367+
+ // the key, so the entry survives with a dangling value slot. When the
368+
+ // closure reached its fixpoint instead, the map is empty and this is a
369+
+ // plain worklist drain.
370+
+ ReachTransitiveClosureWithEmbedder<
371+
+ MarkingWorklistProcessingMode::kProcessRememberedEphemerons>();
362372
+ if (!MarkTransitiveClosureFixpoint()) {
363373
+ MarkTransitiveClosureLinear();
364374
+ }
375+
+ local_weak_objects()->ephemeron_hash_tables_local.Publish();
365376
+ CHECK(local_marking_worklists_->IsEmpty());
366377
+ CHECK(
367378
+ local_weak_objects()->current_ephemerons_local.IsLocalAndGlobalEmpty());
368379
+ CHECK(IsCppHeapMarkingFinished(heap_, local_marking_worklists_.get()));
380+
+ VerifyEphemeronMarking();
369381
+ }
370382
+
371383
if (was_marked_incrementally) {

0 commit comments

Comments
 (0)