Branch: refs/heads/webkitglib/2.52
Home: https://github.com/WebKit/WebKit
Commit: 5aa65ef3da00b1ba708833d1ff3424c203cbd8ca
https://github.com/WebKit/WebKit/commit/5aa65ef3da00b1ba708833d1ff3424c203cbd8ca
Author: Tyler Wilcock <[email protected]>
Date: 2026-08-11 (Tue, 11 Aug 2026)
Changed paths:
M Source/WebCore/platform/PlatformSpeechSynthesizer.cpp
M Source/WebCore/platform/PlatformSpeechSynthesizer.h
M Source/WebCore/platform/cocoa/PlatformSpeechSynthesizerCocoa.mm
M Source/WebCore/platform/gstreamer/PlatformSpeechSynthesizerGStreamer.cpp
M Source/WebCore/platform/mock/PlatformSpeechSynthesizerMock.cpp
M Source/WebCore/platform/spiel/PlatformSpeechSynthesizerSpiel.cpp
M Source/WebCore/testing/Internals.cpp
Log Message:
-----------
Cherry-pick 71471a83ed2d. https://bugs.webkit.org/show_bug.cgi?id=312793
PlatformSpeechSynthesizerClient should prevent use-after-free via weak
back-reference to client
https://bugs.webkit.org/show_bug.cgi?id=312793
rdar://172854014
Reviewed by Joshua Hoffman.
PlatformSpeechSynthesizer held a raw C++ reference
(PlatformSpeechSynthesizerClient&) back to its client
(SpeechSynthesis). When cancel() was made asynchronous via
callOnMainThread in 309349@main, the deferred lambda could fire after
SpeechSynthesis had been destroyed, dereferencing freed memory. ASan
caught this as a heap-use-after-free in 131 media/track layout tests.
This commit makes PlatformSpeechSynthesizerClient inherit from
AbstractRefCountedAndCanMakeWeakPtr so it supports both WeakPtr (for
the non-owning back-reference) and RefPtr (for strong promotion at
call sites). Convert the raw reference member to a WeakPtr, and update
all ~29 call sites across all platform implementations to promote to
RefPtr before calling through the client.
This also fixes two latent async bugs with the same pattern: the Cocoa
voicesDidChange async callback and the Spiel initializeVoiceList
lambda both accessed the client in a deferred context without lifetime
protection.
* Source/WebCore/platform/PlatformSpeechSynthesizer.cpp:
(WebCore::PlatformSpeechSynthesizer::voicesDidChange):
* Source/WebCore/platform/PlatformSpeechSynthesizer.h:
* Source/WebCore/platform/cocoa/PlatformSpeechSynthesizerCocoa.mm:
(-[WebSpeechSynthesisWrapper speakUtterance:]):
(-[WebSpeechSynthesisWrapper speechSynthesizer:didStartSpeechUtterance:]):
(-[WebSpeechSynthesisWrapper speechSynthesizer:didFinishSpeechUtterance:]):
(-[WebSpeechSynthesisWrapper speechSynthesizer:didPauseSpeechUtterance:]):
(-[WebSpeechSynthesisWrapper
speechSynthesizer:didContinueSpeechUtterance:]):
(-[WebSpeechSynthesisWrapper speechSynthesizer:didCancelSpeechUtterance:]):
(-[WebSpeechSynthesisWrapper
speechSynthesizer:willSpeakRangeOfSpeechString:utterance:]):
(WebCore::PlatformSpeechSynthesizer::initializeVoiceList):
* Source/WebCore/platform/gstreamer/PlatformSpeechSynthesizerGStreamer.cpp:
(WebCore::GstSpeechSynthesisWrapper::pause):
(WebCore::GstSpeechSynthesisWrapper::resume):
(WebCore::GstSpeechSynthesisWrapper::speakUtterance):
(WebCore::GstSpeechSynthesisWrapper::cancel):
* Source/WebCore/platform/mock/PlatformSpeechSynthesizerMock.cpp:
(WebCore::PlatformSpeechSynthesizerMock::speakingFinished):
(WebCore::PlatformSpeechSynthesizerMock::speak):
(WebCore::PlatformSpeechSynthesizerMock::cancel):
(WebCore::PlatformSpeechSynthesizerMock::pause):
(WebCore::PlatformSpeechSynthesizerMock::resume):
* Source/WebCore/platform/spiel/PlatformSpeechSynthesizerSpiel.cpp:
(WebCore::SpielSpeechWrapper::finishSpeakerInitialization):
(WebCore::SpielSpeechWrapper::speakUtterance):
(WebCore::PlatformSpeechSynthesizer::initializeVoiceList):
* Source/WebCore/testing/Internals.cpp:
(WebCore::Internals::simulateSpeechSynthesizerVoiceListChange):
Identifier: 305413.715@safari-7624-branch
Canonical link: https://commits.webkit.org/[email protected]
Canonical link: https://commits.webkit.org/305877.1089@webkitglib/2.52
Commit: c3fd584f6f3622423754702d337652e76a31a191
https://github.com/WebKit/WebKit/commit/c3fd584f6f3622423754702d337652e76a31a191
Author: Kristian Monsen <[email protected]>
Date: 2026-08-11 (Tue, 11 Aug 2026)
Changed paths:
A
LayoutTests/fast/speechsynthesis/speech-synthesis-speak-fuzzer-crash-expected.txt
A LayoutTests/fast/speechsynthesis/speech-synthesis-speak-fuzzer-crash.html
A
LayoutTests/fast/speechsynthesis/speech-synthesis-stop-cross-document-utterance-crash-expected.txt
A
LayoutTests/fast/speechsynthesis/speech-synthesis-stop-cross-document-utterance-crash.html
A
LayoutTests/platform/mac/fast/speechsynthesis/speech-synthesis-speak-fuzzer-crash-expected.png
M Source/WebCore/Modules/speech/SpeechSynthesis.cpp
M Source/WebCore/Modules/speech/SpeechSynthesis.h
Log Message:
-----------
Cherry-pick f1fe25fdbdb4. https://bugs.webkit.org/show_bug.cgi?id=315529
Unreviewed backport.
SpeechSynthesis::stop() must not synchronously dispatch error events; fix
crash when platform cancel() calls back synchronously
https://bugs.webkit.org/show_bug.cgi?id=315529
rdar://177692338
Reviewed by Per Arne Vollan, Zak Ridouh, and Chris Dumez.
ActiveDOMObject::stop() and suspend() are called from within
ScriptExecutionContext::forEachActiveDOMObject, which holds a
ScriptDisallowedScope that prohibits JavaScript from running. The previous
SpeechSynthesis::stop() and suspend() implementations both called
cancel(), which synchronously fires error events on every queued utterance.
In a debug build this trips the ScriptDisallowedScope assertion;
in a release build it silently executes JS listeners during a scope that is
supposed to forbid it.
The fix introduces stopPlatformSpeech(), called by both stop() and
suspend(), which clears the utterance queue and nulls
m_currentSpeechUtterance without firing any events, then tells the
platform/client to cancel. Any subsequent completion callbacks from the
platform find m_currentSpeechUtterance null and return early in
handleSpeakingCompleted().
A secondary crash was found where PlatformSpeechSynthesizerMock::cancel()
calls speakingErrorOccurred() synchronously, re-entering
handleSpeakingCompleted() before the caller has returned. Since
stopPlatformSpeech() nulls m_currentSpeechUtterance before calling cancel, the
re-entrant call arrived with a null current utterance and hit the
ASSERT(m_currentSpeechUtterance) in handleSpeakingCompleted(). The assert is
replaced with an early return for the null case.
Two layout tests are added: one verifying that speech is silently cancelled
when a page enters the back/forward cache (triggering suspend()), and
one verifying no crash when stop() is called on a SpeechSynthesis that
holds an utterance created in a different document. An existing fuzzer-crash
test is also fixed: it was previously passing only because a teardown crash
happened to occur after notifyDone() was already called, masking the
crash. It is rewritten to wait for the utterance's end or error event
before calling notifyDone(), so any crash in the speech completion path is
caught as a real failure.
Test:
fast/speechsynthesis/speech-synthesis-stop-cross-document-utterance-crash.html
* LayoutTests/fast/speechsynthesis/speech-synthesis-speak-fuzzer-crash.html:
*
LayoutTests/fast/speechsynthesis/speech-synthesis-stop-cross-document-utterance-crash-expected.txt:
Added.
*
LayoutTests/fast/speechsynthesis/speech-synthesis-stop-cross-document-utterance-crash.html:
Added.
*
LayoutTests/platform/mac/fast/speechsynthesis/speech-synthesis-speak-fuzzer-crash-expected.png:
Added.
* Source/WebCore/Modules/speech/SpeechSynthesis.cpp:
(WebCore::SpeechSynthesis::handleSpeakingCompleted):
(WebCore::SpeechSynthesis::suspend):
(WebCore::SpeechSynthesis::stop):
(WebCore::SpeechSynthesis::stopPlatformSpeech):
* Source/WebCore/Modules/speech/SpeechSynthesis.h:
Identifier: [email protected]
Canonical link: https://commits.webkit.org/[email protected]
Canonical link: https://commits.webkit.org/305877.1090@webkitglib/2.52
Compare: https://github.com/WebKit/WebKit/compare/3ed9b57d0094...c3fd584f6f36
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications