WebSpeech: Crash in WebCore::PlatformSpeechSynthesisUtterance::client / WebCore:...
authorcfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Mar 2013 21:13:44 +0000 (21:13 +0000)
committercfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Mar 2013 21:13:44 +0000 (21:13 +0000)
https://bugs.webkit.org/show_bug.cgi?id=112728

Reviewed by Tim Horton.

When cancel() is called, there was a delay in the platform returning and saying speech was finished, which caused
the m_currentSpeechUtterance variable to get deallocated but not cleared.

This patch fixes up the management of the utterances in SpeechSynthesis and the Mac platform given that
we can't rely on the platform to return immediately on a stop speaking job.

Test: platform/mac/fast/speechsynthesis/speech-synthesis-cancel-crash.html

* Modules/speech/SpeechSynthesis.cpp:
(WebCore::SpeechSynthesis::cancel):
(WebCore::SpeechSynthesis::resume):
* platform/mac/PlatformSpeechSynthesizerMac.mm:
(-[WebSpeechSynthesisWrapper cancel]):
(-[WebSpeechSynthesisWrapper speechSynthesizer:didFinishSpeaking:]):
(-[WebSpeechSynthesisWrapper speechSynthesizer:willSpeakWord:ofString:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@146387 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/platform/mac/fast/speechsynthesis/speech-synthesis-cancel-crash-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/speechsynthesis/speech-synthesis-cancel-crash.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/speech/SpeechSynthesis.cpp
Source/WebCore/platform/mac/PlatformSpeechSynthesizerMac.mm

diff --git a/LayoutTests/platform/mac/fast/speechsynthesis/speech-synthesis-cancel-crash-expected.txt b/LayoutTests/platform/mac/fast/speechsynthesis/speech-synthesis-cancel-crash-expected.txt
new file mode 100644 (file)
index 0000000..67865ba
--- /dev/null
@@ -0,0 +1,9 @@
+This tests that cancelling speech at the right time will not crash due to mismanaging of the queue during a cancel.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac/fast/speechsynthesis/speech-synthesis-cancel-crash.html b/LayoutTests/platform/mac/fast/speechsynthesis/speech-synthesis-cancel-crash.html
new file mode 100644 (file)
index 0000000..25349e4
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<div id="console"></div>
+
+<script>
+
+    description("This tests that cancelling speech at the right time will not crash due to mismanaging of the queue during a cancel.");
+
+    if (window.testRunner)
+        testRunner.waitUntilDone();
+
+    if (window.internals)
+        window.internals.enableMockSpeechSynthesizer();
+
+    window.jsTestIsAsync = true;
+
+    function speak() {
+        var x = window.parent.speechSynthesis;
+        x.cancel();
+        x.resume();
+        x.speak(new SpeechSynthesisUtterance("X"));
+     }
+     speak();
+
+     // Don't crash!
+     setTimeout("speak(); finishJSTest()", 52);
+</script>
+
+<script src="../../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index 7de9867..67ee455 100644 (file)
@@ -1,3 +1,26 @@
+2013-03-20  Chris Fleizach  <cfleizach@apple.com>
+
+        WebSpeech: Crash in WebCore::PlatformSpeechSynthesisUtterance::client / WebCore::SpeechSynthesis::didResumeSpeaking
+        https://bugs.webkit.org/show_bug.cgi?id=112728
+
+        Reviewed by Tim Horton.
+
+        When cancel() is called, there was a delay in the platform returning and saying speech was finished, which caused
+        the m_currentSpeechUtterance variable to get deallocated but not cleared. 
+
+        This patch fixes up the management of the utterances in SpeechSynthesis and the Mac platform given that
+        we can't rely on the platform to return immediately on a stop speaking job.
+
+        Test: platform/mac/fast/speechsynthesis/speech-synthesis-cancel-crash.html
+
+        * Modules/speech/SpeechSynthesis.cpp:
+        (WebCore::SpeechSynthesis::cancel):
+        (WebCore::SpeechSynthesis::resume):
+        * platform/mac/PlatformSpeechSynthesizerMac.mm:
+        (-[WebSpeechSynthesisWrapper cancel]):
+        (-[WebSpeechSynthesisWrapper speechSynthesizer:didFinishSpeaking:]):
+        (-[WebSpeechSynthesisWrapper speechSynthesizer:willSpeakWord:ofString:]):
+
 2013-03-20  Eric Carlson  <eric.carlson@apple.com>
 
         Unreviewed, fix Mac release build.
index c4dff4e..11fbc10 100644 (file)
@@ -112,8 +112,14 @@ void SpeechSynthesis::speak(SpeechSynthesisUtterance* utterance)
 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.
+    RefPtr<SpeechSynthesisUtterance> current = m_currentSpeechUtterance;
     m_utteranceQueue.clear();
     m_platformSpeechSynthesizer->cancel();
+    current = 0;
+    
+    // The platform should have called back immediately and cleared the current utterance.
+    ASSERT(!m_currentSpeechUtterance);
 }
 
 void SpeechSynthesis::pause()
@@ -124,6 +130,8 @@ void SpeechSynthesis::pause()
 
 void SpeechSynthesis::resume()
 {
+    if (!m_currentSpeechUtterance)
+        return;
     m_platformSpeechSynthesizer->resume();
 }
 
index 7094fa3..bc4b531 100644 (file)
 
 - (void)cancel
 {
+    if (!m_utterance)
+        return;
+    
     [m_synthesizer stopSpeakingAtBoundary:NSSpeechImmediateBoundary];
+    m_synthesizerObject->client()->speakingErrorOccurred(m_utterance);
+    m_utterance = 0;
 }
 
 - (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)finishedSpeaking
 {
-    ASSERT(m_utterance);
+    if (!m_utterance)
+        return;
+    
     UNUSED_PARAM(sender);
     
     // Clear the m_utterance variable in case finish speaking kicks off a new speaking job immediately.
 
 - (void)speechSynthesizer:(NSSpeechSynthesizer *)sender willSpeakWord:(NSRange)characterRange ofString:(NSString *)string
 {
-    ASSERT(m_utterance);
     UNUSED_PARAM(sender);
     UNUSED_PARAM(string);
 
+    if (!m_utterance)
+        return;
+
     // Mac platform only supports word boundaries.
     m_synthesizerObject->client()->boundaryEventOccurred(m_utterance, WebCore::SpeechWordBoundary, characterRange.location);
 }