Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1710)

Unified Diff: Source/modules/speech/SpeechSynthesis.cpp

Issue 180553004: Fix use-after-free of m_currentSpeechUtterance. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fix nullptr again? Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/modules/speech/SpeechSynthesis.cpp
diff --git a/Source/modules/speech/SpeechSynthesis.cpp b/Source/modules/speech/SpeechSynthesis.cpp
index 9815767b80525cb72be1957446fc943c07d013b3..00b60091d8d97ef02dbd8da2764236da39ca1907 100644
--- a/Source/modules/speech/SpeechSynthesis.cpp
+++ b/Source/modules/speech/SpeechSynthesis.cpp
@@ -42,7 +42,6 @@ PassRefPtrWillBeRawPtr<SpeechSynthesis> SpeechSynthesis::create(ExecutionContext
SpeechSynthesis::SpeechSynthesis(ExecutionContext* context)
: ContextLifecycleObserver(context)
, m_platformSpeechSynthesizer(PlatformSpeechSynthesizer::create(this))
- , m_currentSpeechUtterance(nullptr)
, m_isPaused(false)
{
ScriptWrappable::init(this);
@@ -83,7 +82,7 @@ bool SpeechSynthesis::speaking() const
{
// If we have a current speech utterance, then that means we're assumed to be in a speaking state.
// This state is independent of whether the utterance happens to be paused.
- return m_currentSpeechUtterance;
+ return currentSpeechUtterance();
}
bool SpeechSynthesis::pending() const
@@ -98,11 +97,12 @@ bool SpeechSynthesis::paused() const
return m_isPaused;
}
-void SpeechSynthesis::startSpeakingImmediately(SpeechSynthesisUtterance* utterance)
+void SpeechSynthesis::startSpeakingImmediately()
{
- ASSERT(!m_currentSpeechUtterance);
+ SpeechSynthesisUtterance* utterance = currentSpeechUtterance();
+ ASSERT(utterance);
+
utterance->setStartTime(monotonicallyIncreasingTime());
- m_currentSpeechUtterance = utterance;
m_isPaused = false;
m_platformSpeechSynthesizer->speak(utterance->platformUtterance());
}
@@ -116,22 +116,18 @@ void SpeechSynthesis::speak(SpeechSynthesisUtterance* utterance, ExceptionState&
m_utteranceQueue.append(utterance);
- // If the queue was empty, speak this immediately and add it to the queue.
+ // If the queue was empty, speak this immediately.
if (m_utteranceQueue.size() == 1)
- startSpeakingImmediately(utterance);
+ startSpeakingImmediately();
}
void SpeechSynthesis::cancel()
{
- // Remove all the items from the utterance queue.
- // Hold on to the current utterance so the platform synthesizer can have a chance to clean up.
- RefPtrWillBeMember<SpeechSynthesisUtterance> current = m_currentSpeechUtterance;
+ // Remove all the items from the utterance queue. The platform
+ // may still have references to some of these utterances and may
+ // fire events on them asynchronously.
m_utteranceQueue.clear();
m_platformSpeechSynthesizer->cancel();
- current = nullptr;
-
- // The platform should have called back immediately and cleared the current utterance.
- ASSERT(!m_currentSpeechUtterance);
}
void SpeechSynthesis::pause()
@@ -142,7 +138,7 @@ void SpeechSynthesis::pause()
void SpeechSynthesis::resume()
{
- if (!m_currentSpeechUtterance)
+ if (!currentSpeechUtterance())
return;
m_platformSpeechSynthesizer->resume();
}
@@ -156,21 +152,24 @@ void SpeechSynthesis::fireEvent(const AtomicString& type, SpeechSynthesisUtteran
void SpeechSynthesis::handleSpeakingCompleted(SpeechSynthesisUtterance* utterance, bool errorOccurred)
{
ASSERT(utterance);
- ASSERT(m_currentSpeechUtterance);
- m_currentSpeechUtterance = nullptr;
- fireEvent(errorOccurred ? EventTypeNames::error : EventTypeNames::end, utterance, 0, String());
+ bool didJustFinishCurrentUtterance = false;
+ // If the utterance that completed was the one we're currently speaking,
+ // remove it from the queue and start speaking the next one.
+ if (utterance == currentSpeechUtterance()) {
+ m_utteranceQueue.removeFirst();
+ didJustFinishCurrentUtterance = true;
+ }
- if (m_utteranceQueue.size()) {
- RefPtrWillBeMember<SpeechSynthesisUtterance> firstUtterance = m_utteranceQueue.first();
- ASSERT(firstUtterance == utterance);
- if (firstUtterance == utterance)
- m_utteranceQueue.removeFirst();
+ // Always fire the event, because the platform may have asynchronously
+ // sent an event on an utterance before it got the message that we
+ // canceled it, and we should always report to the user what actually
+ // happened.
+ fireEvent(errorOccurred ? EventTypeNames::error : EventTypeNames::end, utterance, 0, String());
- // Start the next job if there is one pending.
- if (!m_utteranceQueue.isEmpty())
- startSpeakingImmediately(m_utteranceQueue.first().get());
- }
+ // Start the next utterance if we just finished one and one was pending.
+ if (didJustFinishCurrentUtterance && !m_utteranceQueue.isEmpty())
+ startSpeakingImmediately();
}
void SpeechSynthesis::boundaryEventOccurred(PassRefPtr<PlatformSpeechSynthesisUtterance> utterance, SpeechBoundary boundary, unsigned charIndex)
@@ -222,6 +221,13 @@ void SpeechSynthesis::speakingErrorOccurred(PassRefPtr<PlatformSpeechSynthesisUt
handleSpeakingCompleted(static_cast<SpeechSynthesisUtterance*>(utterance->client()), true);
}
+SpeechSynthesisUtterance* SpeechSynthesis::currentSpeechUtterance() const
+{
+ if (!m_utteranceQueue.isEmpty())
+ return m_utteranceQueue.first().get();
+ return 0;
+}
+
const AtomicString& SpeechSynthesis::interfaceName() const
{
return EventTargetNames::SpeechSynthesisUtterance;
@@ -230,7 +236,6 @@ const AtomicString& SpeechSynthesis::interfaceName() const
void SpeechSynthesis::trace(Visitor* visitor)
{
visitor->trace(m_voiceList);
- visitor->trace(m_currentSpeechUtterance);
visitor->trace(m_utteranceQueue);
}
« no previous file with comments | « Source/modules/speech/SpeechSynthesis.h ('k') | Source/modules/speech/testing/PlatformSpeechSynthesizerMock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698