← WebKit — 2026-W37
7e946663438851db54f93b938cf06d2c2b73ac16 Annotate CachedScript's decoded script state as owner-thread state
severity low
class Race
confidence 0.3
signal score 7.3
Source/WebCore/loader
Primitive: CachedScript m_script/m_decoder/m_decodingState read on main thread without documented locking discipline while compilation threads read under lock.
Triage note: Adds WTF_GUARDED_BY_LOCK/WTF_REQUIRES_SHARED_LOCK annotations, assertIsOwnerThread()/release-reacquire assertions and owner-thread assertions; the locked write blocks already existed. Dominated by thread-safety annotations and assertions (instrumentation), not a concrete data-race fix in this diff.
Triage note: Adds WTF_GUARDED_BY_LOCK/WTF_REQUIRES_SHARED_LOCK annotations, assertIsOwnerThread()/release-reacquire assertions and owner-thread assertions; the locked write blocks already existed. Dominated by thread-safety annotations and assertions (instrumentation), not a concrete data-race fix in this diff.
Structural signals: smartptr_member_added (+3.0), msg_soft (+1.0), area:Source/WebCore/loader (+2.0), surgical (+1.3)
Commit message
Annotate CachedScript's decoded script state as owner-thread state
https://bugs.webkit.org/show_bug.cgi?id=323735
Reviewed by Geoffrey Garen.
m_script, m_decodingState and m_decoder are written on the main thread under m_lock and read
on compilation threads by codeBlockHashConcurrently(), which locks. The lock is therefore
load-bearing for those three, and nothing enforced that the writers took it. Guard them with
WTF_GUARDED_BY_LOCK() and assert on the main thread's unlocked read paths.
m_scriptHash and m_wasForceDecodedAsUTF8 are deliberately left unguarded. Neither is read
off the main thread, so by the rule that state should only be annotated where failing to
lock would be a bug, they do not qualify; m_scriptHash is in fact written without the lock
in script(), so guarding it would report existing code rather than describe an invariant.
encoding() and textResourceDecoder() read m_decoder from both sides: the main thread calls
them without the lock, and codeBlockHashConcurrently() calls encoding() while holding it.
They can therefore neither assert the owner thread, which would fire on a compilation
thread, nor require the lock exclusively. They instead require it shared, which both callers
satisfy, the main thread through its owner-thread assertion and the compilation thread by
holding the lock. Calls that arrive through a CachedResource pointer use the unannotated base
declaration and so are not checked, which is no weaker than before.
script() reads guarded state before, between and after its two critical sections, so it
asserts once at the top and then releases and re-asserts around each Locker; leaving the
assertion live would report the Locker as acquiring a lock that is already held.
setBodyDataFrom() reads a second CachedScript's guarded members, and holding this object's
lock grants nothing for another's, so it asserts on the source object as well.
No behaviour change is intended: neither helper generates code, so no lock is taken and no
ordering is introduced; both only move thread safety analysis state.
* Source/WebCore/loader/cache/CachedScript.cpp:
(WebCore::CachedScript::setEncoding):
(WebCore::CachedScript::script):
(WebCore::CachedScript::scriptHash):
(WebCore::CachedScript::setBodyDataFrom):
* Source/WebCore/loader/cache/CachedScript.h:
Canonical link: https://commits.webkit.org/320790@main
Before / after
Loading diff…
On This Page