Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 2a837da2d80e4bf5745127d9e425524a189207c1
https://github.com/WebKit/WebKit/commit/2a837da2d80e4bf5745127d9e425524a189207c1
Author: Yijia Huang <[email protected]>
Date: 2025-11-18 (Tue, 18 Nov 2025)
Changed paths:
M Source/JavaScriptCore/runtime/VMTraps.cpp
M Source/JavaScriptCore/runtime/VMTraps.h
Log Message:
-----------
[JSC] Fix VMTraps race condition in fireTrap() for async events
https://bugs.webkit.org/show_bug.cgi?id=302605
rdar://164842717
Reviewed by Mark Lam and Dan Hecht.
There was a race condition where m_trapBits and m_threadStopRequested could
be observed in an inconsistent state, causing assertion failures.
The bug occurred in VMTraps::fireTrap() for async events:
1. Thread A calls fireTrap() and executes m_trapBits.exchangeOr(event)
atomically WITHOUT holding m_trapSignalingLock.
2. Thread B in cancelThreadStopIfNeeded() acquires m_trapSignalingLock first.
3. Thread B reads m_trapBits and sees the bit set by Thread A.
4. Thread B checks m_threadStopRequested, which is still false because Thread A
hasn't acquired the lock yet to call requestThreadStopIfNeeded()
5. This breaks the assertion in cancelThreadStopIfNeeded() that
m_threadStopRequested must be true when needHandling(AsyncEvents) is true.
The fix introduces updateThreadStopRequestIfNeeded(), which synchronizes
m_threadStopRequested to match m_trapBits regardless of how we got to the
current state. Instead of having separate requestThreadStopIfNeeded() and
cancelThreadStopIfNeeded() calls that must reason about complex interleavings,
we have a single function that ensures the flag matches the source of truth.
Key changes:
- fireTrap() and clearTrap() now call updateThreadStopRequestIfNeeded() after
modifying trap bits (with compiler fence to prevent reordering).
- updateThreadStopRequestIfNeeded() checks if m_threadStopRequested matches
needHandling(AsyncEvents) and calls the appropriate helper if out of sync.
- requestThreadStopIfNeeded() and cancelThreadStopIfNeeded() are simplified
to just perform their work, with asserts instead of guards.
- All interleavings now converge to the correct state because we sync to
the source of truth rather than trying to maintain invariants.
This approach is conceptually simpler: instead of reasoning about whether to
request or cancel based on what operation we're performing, we simply ensure
the derived state (m_threadStopRequested) matches the source of truth
(m_trapBits). The lock-free fast path for trap bit modifications is preserved.
Tests: The corresponding stress tests will be attached in a follow-up patch
Canonical link: https://commits.webkit.org/303185@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications