Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: c8e53c74403ff33f7dcbafbe74b77f3c67e316d9
https://github.com/WebKit/WebKit/commit/c8e53c74403ff33f7dcbafbe74b77f3c67e316d9
Author: Sosuke Suzuki <[email protected]>
Date: 2026-06-10 (Wed, 10 Jun 2026)
Changed paths:
M Source/JavaScriptCore/heap/Heap.cpp
Log Message:
-----------
[JSC] `Heap::clearConcurrentRetainedDataIfPossible()` should not run while
concurrent marking is active
https://bugs.webkit.org/show_bug.cgi?id=316635
Reviewed by Keith Miller.
The between-GC clearing path added in 314730@main guards against JS
executing, a live GCOwnedDataScope, and in-flight JIT compilations, but
not against concurrent marking. Marker threads load a JSString's
StringImpl via fiberConcurrently() and then dereference it without
taking a ref (JSString::visitChildrenImpl / JSString::estimatedSize).
The retained list is exactly what keeps those racily-loaded impls
alive, so clearing it while marking is in flight can free an impl a
marker is about to read, which is a use-after-free on the collector
thread. ASAN confirms: the read is in WTF::StringImpl::costDuringGC
under SlotVisitor::drain on the collector thread, and the free is in
clearConcurrentRetainedDataIfPossible under the IncrementalSweeper
timer on the mutator thread.
Skip the clear while mutatorShouldBeFenced() is true. That flag is set
exactly while markers can be running (the same invariant the write
barriers rely on), and the read is properly ordered because the timer
callback acquires the API lock first. The clear is only deferred, not
lost: the sweep timer re-fires every 100ms, so the list is cleared on
the first fire after marking finishes, and GC-finalize pruning still
bounds the list across collection cycles.
* Source/JavaScriptCore/heap/Heap.cpp:
(JSC::Heap::clearConcurrentRetainedDataIfPossible):
Canonical link: https://commits.webkit.org/314978@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications