Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 37cfccb3c6c9ae9cc09b9d9908c190286ac2e858
https://github.com/WebKit/WebKit/commit/37cfccb3c6c9ae9cc09b9d9908c190286ac2e858
Author: Kristian Monsen <[email protected]>
Date: 2026-08-07 (Fri, 07 Aug 2026)
Changed paths:
A
LayoutTests/navigation-api/navigation-navigate-state-clone-exception-crash-expected.txt
A
LayoutTests/navigation-api/navigation-navigate-state-clone-exception-crash.html
A
LayoutTests/navigation-api/navigation-reload-state-clone-exception-crash-expected.txt
A
LayoutTests/navigation-api/navigation-reload-state-clone-exception-crash.html
M Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp
Log Message:
-----------
Fix crash from double-consuming the pending exception in
DeferredPromise::reject() during Navigation reload()/navigate() error handling
https://bugs.webkit.org/show_bug.cgi?id=321250
rdar://183911429
Reviewed by Rupin Mittal.
Navigation::createErrorResult() rejects both the committed and finished
promises with the same Exception. When that exception carries
ExceptionCode::ExistingExceptionError — the
sentinel meaning "the real JS exception is already sitting on the VM's
exception scope" — DeferredPromise::reject() pulled the value straight off
scope.exception() and called
scope.clearException() as a side effect. That works for the first reject()
call, but clears the exception before the second call runs, so it finds nothing
there: an assert in
debug/ASan builds, a null-pointer read of Exception::m_value in release builds
— either way, a crash on every reload()/navigate() whose state argument throws
during
structured-clone.
The fix reuses the exceptionObject out-parameter that's already threaded
through both reject() calls (the same parameter the plain-ExceptionCode branch
a few lines below already
uses to build the DOMException once and share it across calls). On the first
call, if exceptionObject is still empty, it extracts the value from the
exception scope, clears it, and
caches the result in exceptionObject; on the second call, exceptionObject is
already populated, so it skips touching the exception scope entirely and just
rejects with the cached
value. This matches the pattern already used elsewhere in Navigation.cpp
(rejectFinishedPromise, which precomputes a DOMException once and passes it to
both promise rejections),
and it satisfies the spec requirement that committed and finished reject with
the identical error value — which a "swallow and fall back to a generic error"
fix would not have.
Tests: navigation-api/navigation-navigate-state-clone-exception-crash.html
navigation-api/navigation-reload-state-clone-exception-crash.html
*
LayoutTests/navigation-api/navigation-navigate-state-clone-exception-crash-expected.txt:
Added.
*
LayoutTests/navigation-api/navigation-navigate-state-clone-exception-crash.html:
Added.
*
LayoutTests/navigation-api/navigation-reload-state-clone-exception-crash-expected.txt:
Added.
*
LayoutTests/navigation-api/navigation-reload-state-clone-exception-crash.html:
Added.
* Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp:
(WebCore::DeferredPromise::reject):
Canonical link: https://commits.webkit.org/318836@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications