← WebKit — 2026-W41

76ed77ce7f2a81229f376a17a63f8e32cfd98506  ScriptExecutionContext::circularSequentialID() relies on signed integer overflow to wrap

severity low class IntegerOverflow confidence 0.35 signal score 8.3 Source/WebCore/dom
Primitive: signed-int overflow (UB) in circularSequentialID counter wrap
Triage note: ScriptExecutionContext::circularSequentialID() previously did ++m_circularSequentialID then reset to 1 if <=0, relying on signed-int overflow (UB); the fix wraps to 0 when the value is INT_MAX before incrementing. A hardening of a signed-overflow counter with no demonstrated memory-corruption or attacker-controlled impact.
Structural signals: msg_strong (+3.0), msg_medium (+2.0), area:Source/WebCore/dom (+2.0), surgical (+1.3)

Commit message

ScriptExecutionContext::circularSequentialID() relies on signed integer overflow to wrap
https://bugs.webkit.org/show_bug.cgi?id=326630
rdar://189373355

Reviewed by Chris Dumez.

circularSequentialID() incremented the int m_circularSequentialID and only
afterwards checked for a non-positive result to wrap back to 1. Once the
counter reaches INT_MAX, the increment is signed integer overflow, which is
undefined behavior, so the wrap check relied on behavior the compiler is
free to assume never happens.

The counter backs setTimeout()/setInterval() IDs and
Geolocation.watchPosition() IDs, so a long-lived document or worker that
creates around 2^31 timers can reach it.

Check for INT_MAX before incrementing instead. The ID sequence stays the
same: 1 to INT_MAX, then back to 1. DOMTimer::install() still retries on
collision after the wrap.

No new tests, since reaching the wrap requires around 2^31 calls.

* Source/WebCore/dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::circularSequentialID):

Canonical link: https://commits.webkit.org/323055@main

Before / after

Loading diff…