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

Reply via email to