[16] [JSC] JSLock m_hasOwnerThread has concurrency issue
Rated Medium because the diff restores publication symmetry on
JSLockownership state. The race could causecurrentThreadIsHoldingLock()to return true on a thread that did not hold the lock, allowing two threads to enter the VM concurrently — but reaching the racy observation requires a stalem_ownerThreadthat happens to equal the current thread, which is timing-dependent.
JSLock::lock published m_ownerThread then m_hasOwnerThread = true separated by a writer-side storeStoreFence(). Readers loaded both fields with plain non-atomic loads — no matching acquire barrier — so on weakly ordered hardware a reader could observe m_hasOwnerThread == true paired with a stale m_ownerThread.
Source/JavaScriptCore/runtime/JSLock.cpp / JSLock.h
Patch Details
m_hasOwnerThread becomes std::atomic<bool>. Writers use memory_order_release; readers in ownerThread(), ownerThreadUID(), and currentThreadIsHoldingLock() use memory_order_acquire.
Asymmetric memory fencing — release-side ordering on the writer paired with unordered, non-atomic loads on the reader breaks the publication invariant between two fields.
Background
JSLock is recursive — lock() checks currentThreadIsHoldingLock() and bumps m_lockCount instead of taking the underlying mutex if true. The (m_hasOwnerThread, m_ownerThread) pair is a published racy-readable view used by SamplingProfiler, MachineThreads, and Web Thread interop without holding m_lock. Release-acquire pairing on the same atomic synchronizes prior writes with subsequent reads.
If a stale m_ownerThread happens to equal the current thread, the recursive fast path skips the underlying m_lock.lock() and proceeds — two threads in the VM concurrently, with all the downstream Structure/IndexingType corruption that implies.
This vulnerability weakens the mutual-exclusion invariant JSC's threading model is built on. WTF::storeStoreFence() constrains the writer only; any flag published this way and read by other threads needs a matching reader-side ordering.
Audit directions
- One-sided fencing where a writer uses
storeStoreFence()but readers use plain loads. GrepSource/forstoreStoreFenceand for each hit verify reader-sideloadLoadFence()or acquire-atomic on the published flag. - Racy-readable ownership views (hasOwner-bool, owner-handle pairs). Audit
Lock,RecursiveLock, sampling profiler ownership flags,MachineStackMarkerthread suspension flags. - Recursive-lock re-entrance fast paths reading owner state without the underlying mutex. Inspect every call site of
JSLock::currentThreadIsHoldingLock,ownerThread,ownerThreadUID. - Plain
boolmembers documented "safe to read across threads." Grep WebKit for member comments containing "racy", "across threads", "unlocked read".