Skip to content

Commit 93c0be4

Browse files
sygCommit Bot
authored andcommitted
[weakrefs] Make unregister_token undefined on popped WeakCells
The unregister_token slot is iterated as a custom weak pointer slot, which means the heap verifier treats it as a strong slot. Currently, popped WeakCells (that is, WeakCells for which the owning FinalizationRegistry's finalizer has already been invoked) neither clears out the unregister_token slot nor marks it, which trips the heap verifier. Bug: chromium:1102161 Change-Id: I0a803f12379fc9df6935bc8331b3d5ecb199571a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2284202 Commit-Queue: Ulan Degenbaev <[email protected]> Reviewed-by: Ulan Degenbaev <[email protected]> Auto-Submit: Shu-yu Guo <[email protected]> Cr-Commit-Position: refs/heads/master@{#68723}
1 parent f41e519 commit 93c0be4

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

src/heap/mark-compact.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2541,6 +2541,11 @@ void MarkCompactCollector::ClearJSWeakRefs() {
25412541
matched_cell.set_unregister_token(undefined);
25422542
},
25432543
gc_notify_updated_slot);
2544+
// The following is necessary because in the case that weak_cell has
2545+
// already been popped and removed from the FinalizationRegistry, the call
2546+
// to JSFinalizationRegistry::RemoveUnregisterToken above will not find
2547+
// weak_cell itself to clear its unregister token.
2548+
weak_cell.set_unregister_token(undefined);
25442549
} else {
25452550
// The unregister_token is alive.
25462551
ObjectSlot slot = weak_cell.RawField(WeakCell::kUnregisterTokenOffset);

test/cctest/test-js-weak-refs.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,5 +968,52 @@ TEST(JSWeakRefTenuredInWorklist) {
968968
CHECK(weak_ref->target().IsUndefined(isolate));
969969
}
970970

971+
TEST(UnregisterTokenHeapVerifier) {
972+
FLAG_harmony_weak_refs = true;
973+
if (!FLAG_incremental_marking) return;
974+
ManualGCScope manual_gc_scope;
975+
#ifdef VERIFY_HEAP
976+
FLAG_verify_heap = true;
977+
#endif
978+
979+
CcTest::InitializeVM();
980+
v8::Isolate* isolate = CcTest::isolate();
981+
Heap* heap = CcTest::heap();
982+
v8::HandleScope outer_scope(isolate);
983+
984+
{
985+
// Make a new FinalizationRegistry and register an object with an unregister
986+
// token that's unreachable after the IIFE returns.
987+
v8::HandleScope scope(isolate);
988+
CompileRun(
989+
"var token = {}; "
990+
"var registry = new FinalizationRegistry(function () {}); "
991+
"(function () { "
992+
" let o = {}; "
993+
" registry.register(o, {}, token); "
994+
"})();");
995+
}
996+
997+
// GC so the WeakCell corresponding to o is moved from the active_cells to
998+
// cleared_cells.
999+
CcTest::CollectAllGarbage();
1000+
CcTest::CollectAllGarbage();
1001+
1002+
{
1003+
// Override the unregister token to make the original object collectible.
1004+
v8::HandleScope scope(isolate);
1005+
CompileRun("token = 0;");
1006+
}
1007+
1008+
heap::SimulateIncrementalMarking(heap, true);
1009+
1010+
// Pump message loop to run the finalizer task, then the incremental marking
1011+
// task. The finalizer task will pop the WeakCell from the cleared list. This
1012+
// should make the unregister_token slot undefined. That slot is iterated as a
1013+
// custom weak pointer, so if it is not made undefined, the verifier as part
1014+
// of the incremental marking task will crash.
1015+
EmptyMessageQueues(isolate);
1016+
}
1017+
9711018
} // namespace internal
9721019
} // namespace v8

0 commit comments

Comments
 (0)