CRASH(nullptr) in WebCore::jsAudioContextCurrentTime()
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 14 Jun 2019 17:42:13 +0000 (17:42 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 14 Jun 2019 17:42:13 +0000 (17:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=198859
<rdar://problem/27986991>

Reviewed by Eric Carlson.

AudioContext's m_destinationNode can become null during iframe teardown,
but can AudioContext methods can still be called by JavaScript. Add null-checks
to all (remaing) unprotected dereferences of m_destinationNode.

* Modules/webaudio/AudioContext.cpp:
(WebCore::AudioContext::uninitialize):
(WebCore::AudioContext::createBufferSource):
(WebCore::AudioContext::createScriptProcessor):
(WebCore::AudioContext::createBiquadFilter):
(WebCore::AudioContext::createPanner):
(WebCore::AudioContext::createConvolver):
(WebCore::AudioContext::createDynamicsCompressor):
(WebCore::AudioContext::createAnalyser):
(WebCore::AudioContext::createGain):
(WebCore::AudioContext::createDelay):
(WebCore::AudioContext::createChannelSplitter):
(WebCore::AudioContext::createChannelMerger):
(WebCore::AudioContext::createOscillator):
* Modules/webaudio/AudioContext.h:
(WebCore::AudioContext::currentSampleFrame const):
(WebCore::AudioContext::currentTime const):
(WebCore::AudioContext::sampleRate const):

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

Source/WebCore/ChangeLog
Source/WebCore/Modules/webaudio/AudioContext.cpp
Source/WebCore/Modules/webaudio/AudioContext.h

index cc383b4..a2c12ef 100644 (file)
@@ -1,3 +1,34 @@
+2019-06-14  Jer Noble  <jer.noble@apple.com>
+
+        CRASH(nullptr) in WebCore::jsAudioContextCurrentTime()
+        https://bugs.webkit.org/show_bug.cgi?id=198859
+        <rdar://problem/27986991>
+
+        Reviewed by Eric Carlson.
+
+        AudioContext's m_destinationNode can become null during iframe teardown,
+        but can AudioContext methods can still be called by JavaScript. Add null-checks
+        to all (remaing) unprotected dereferences of m_destinationNode.
+
+        * Modules/webaudio/AudioContext.cpp:
+        (WebCore::AudioContext::uninitialize):
+        (WebCore::AudioContext::createBufferSource):
+        (WebCore::AudioContext::createScriptProcessor):
+        (WebCore::AudioContext::createBiquadFilter):
+        (WebCore::AudioContext::createPanner):
+        (WebCore::AudioContext::createConvolver):
+        (WebCore::AudioContext::createDynamicsCompressor):
+        (WebCore::AudioContext::createAnalyser):
+        (WebCore::AudioContext::createGain):
+        (WebCore::AudioContext::createDelay):
+        (WebCore::AudioContext::createChannelSplitter):
+        (WebCore::AudioContext::createChannelMerger):
+        (WebCore::AudioContext::createOscillator):
+        * Modules/webaudio/AudioContext.h:
+        (WebCore::AudioContext::currentSampleFrame const):
+        (WebCore::AudioContext::currentTime const):
+        (WebCore::AudioContext::sampleRate const):
+
 2019-06-14  Youenn Fablet  <youenn@apple.com>
 
         Cloning a MediaStreamTrack does not clone the logger
index 424683e..0d0500e 100644 (file)
@@ -267,7 +267,8 @@ void AudioContext::uninitialize()
         return;
 
     // This stops the audio thread and all audio rendering.
-    m_destinationNode->uninitialize();
+    if (m_destinationNode)
+        m_destinationNode->uninitialize();
 
     // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
     m_isAudioThreadFinished = true;
@@ -441,7 +442,7 @@ ExceptionOr<Ref<AudioBufferSourceNode>> AudioContext::createBufferSource()
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    Ref<AudioBufferSourceNode> node = AudioBufferSourceNode::create(*this, m_destinationNode->sampleRate());
+    Ref<AudioBufferSourceNode> node = AudioBufferSourceNode::create(*this, sampleRate());
 
     // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
     // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
@@ -577,7 +578,7 @@ ExceptionOr<Ref<ScriptProcessorNode>> AudioContext::createScriptProcessor(size_t
     if (numberOfOutputChannels > maxNumberOfChannels())
         return Exception { NotSupportedError };
 
-    auto node = ScriptProcessorNode::create(*this, m_destinationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels);
+    auto node = ScriptProcessorNode::create(*this, sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels);
 
     refNode(node); // context keeps reference until we stop making javascript rendering callbacks
     return node;
@@ -593,7 +594,7 @@ ExceptionOr<Ref<BiquadFilterNode>> AudioContext::createBiquadFilter()
 
     lazyInitialize();
 
-    return BiquadFilterNode::create(*this, m_destinationNode->sampleRate());
+    return BiquadFilterNode::create(*this, sampleRate());
 }
 
 ExceptionOr<Ref<WaveShaperNode>> AudioContext::createWaveShaper()
@@ -617,7 +618,7 @@ ExceptionOr<Ref<PannerNode>> AudioContext::createPanner()
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    return PannerNode::create(*this, m_destinationNode->sampleRate());
+    return PannerNode::create(*this, sampleRate());
 }
 
 ExceptionOr<Ref<ConvolverNode>> AudioContext::createConvolver()
@@ -629,7 +630,7 @@ ExceptionOr<Ref<ConvolverNode>> AudioContext::createConvolver()
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    return ConvolverNode::create(*this, m_destinationNode->sampleRate());
+    return ConvolverNode::create(*this, sampleRate());
 }
 
 ExceptionOr<Ref<DynamicsCompressorNode>> AudioContext::createDynamicsCompressor()
@@ -641,7 +642,7 @@ ExceptionOr<Ref<DynamicsCompressorNode>> AudioContext::createDynamicsCompressor(
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    return DynamicsCompressorNode::create(*this, m_destinationNode->sampleRate());
+    return DynamicsCompressorNode::create(*this, sampleRate());
 }
 
 ExceptionOr<Ref<AnalyserNode>> AudioContext::createAnalyser()
@@ -653,7 +654,7 @@ ExceptionOr<Ref<AnalyserNode>> AudioContext::createAnalyser()
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    return AnalyserNode::create(*this, m_destinationNode->sampleRate());
+    return AnalyserNode::create(*this, sampleRate());
 }
 
 ExceptionOr<Ref<GainNode>> AudioContext::createGain()
@@ -665,7 +666,7 @@ ExceptionOr<Ref<GainNode>> AudioContext::createGain()
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    return GainNode::create(*this, m_destinationNode->sampleRate());
+    return GainNode::create(*this, sampleRate());
 }
 
 ExceptionOr<Ref<DelayNode>> AudioContext::createDelay(double maxDelayTime)
@@ -677,7 +678,7 @@ ExceptionOr<Ref<DelayNode>> AudioContext::createDelay(double maxDelayTime)
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    return DelayNode::create(*this, m_destinationNode->sampleRate(), maxDelayTime);
+    return DelayNode::create(*this, sampleRate(), maxDelayTime);
 }
 
 ExceptionOr<Ref<ChannelSplitterNode>> AudioContext::createChannelSplitter(size_t numberOfOutputs)
@@ -689,7 +690,7 @@ ExceptionOr<Ref<ChannelSplitterNode>> AudioContext::createChannelSplitter(size_t
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    auto node = ChannelSplitterNode::create(*this, m_destinationNode->sampleRate(), numberOfOutputs);
+    auto node = ChannelSplitterNode::create(*this, sampleRate(), numberOfOutputs);
     if (!node)
         return Exception { IndexSizeError };
     return node.releaseNonNull();
@@ -704,7 +705,7 @@ ExceptionOr<Ref<ChannelMergerNode>> AudioContext::createChannelMerger(size_t num
         return Exception { InvalidStateError };
 
     lazyInitialize();
-    auto node = ChannelMergerNode::create(*this, m_destinationNode->sampleRate(), numberOfInputs);
+    auto node = ChannelMergerNode::create(*this, sampleRate(), numberOfInputs);
     if (!node)
         return Exception { IndexSizeError };
     return node.releaseNonNull();
@@ -720,7 +721,7 @@ ExceptionOr<Ref<OscillatorNode>> AudioContext::createOscillator()
 
     lazyInitialize();
 
-    Ref<OscillatorNode> node = OscillatorNode::create(*this, m_destinationNode->sampleRate());
+    Ref<OscillatorNode> node = OscillatorNode::create(*this, sampleRate());
 
     // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
     // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
index 5d790a4..cf3464e 100644 (file)
@@ -108,9 +108,9 @@ public:
     Document* hostingDocument() const final;
 
     AudioDestinationNode* destination() { return m_destinationNode.get(); }
-    size_t currentSampleFrame() const { return m_destinationNode->currentSampleFrame(); }
-    double currentTime() const { return m_destinationNode->currentTime(); }
-    float sampleRate() const { return m_destinationNode->sampleRate(); }
+    size_t currentSampleFrame() const { return m_destinationNode ? m_destinationNode->currentSampleFrame() : 0; }
+    double currentTime() const { return m_destinationNode ? m_destinationNode->currentTime() : 0.; }
+    float sampleRate() const { return m_destinationNode ? m_destinationNode->sampleRate() : 0.f; }
     unsigned long activeSourceCount() const { return static_cast<unsigned long>(m_activeSourceCount); }
 
     void incrementActiveSourceCount();