Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit ad6c092

Browse files
author
Ehsan Akhgari
committed
Bug 864709 - Part 2: Protect accesses to AudioNodeEngine::mNode using a lock; r=padenot
1 parent 14378dc commit ad6c092

6 files changed

Lines changed: 68 additions & 14 deletions

File tree

content/media/AudioNodeEngine.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "AudioSegment.h"
1010
#include "mozilla/dom/AudioParam.h"
11+
#include "mozilla/Mutex.h"
1112

1213
namespace mozilla {
1314

@@ -151,6 +152,7 @@ class AudioNodeEngine {
151152
public:
152153
explicit AudioNodeEngine(dom::AudioNode* aNode)
153154
: mNode(aNode)
155+
, mNodeMutex("AudioNodeEngine::mNodeMutex")
154156
{
155157
MOZ_ASSERT(mNode, "The engine is constructed with a null node");
156158
MOZ_COUNT_CTOR(AudioNodeEngine);
@@ -206,15 +208,25 @@ class AudioNodeEngine {
206208
*aOutput = aInput;
207209
}
208210

211+
Mutex& NodeMutex() { return mNodeMutex;}
212+
209213
dom::AudioNode* Node() const
210214
{
211-
MOZ_ASSERT(NS_IsMainThread());
215+
mNodeMutex.AssertCurrentThreadOwns();
212216
return mNode;
213217
}
214218

215-
protected:
216-
friend class dom::AudioNode;
219+
void ClearNode()
220+
{
221+
MOZ_ASSERT(NS_IsMainThread());
222+
MOZ_ASSERT(mNode != nullptr);
223+
mNodeMutex.AssertCurrentThreadOwns();
224+
mNode = nullptr;
225+
}
226+
227+
private:
217228
dom::AudioNode* mNode;
229+
Mutex mNodeMutex;
218230
};
219231

220232
}

content/media/webaudio/AnalyserNode.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@ class AnalyserNodeEngine : public AudioNodeEngine
3030

3131
NS_IMETHOD Run()
3232
{
33-
nsRefPtr<AnalyserNode> node = static_cast<AnalyserNode*>(mStream->Engine()->Node());
33+
nsRefPtr<AnalyserNode> node;
34+
{
35+
// No need to keep holding the lock for the whole duration of this
36+
// function, since we're holding a strong reference to it, so if
37+
// we can obtain the reference, we will hold the node alive in
38+
// this function.
39+
MutexAutoLock lock(mStream->Engine()->NodeMutex());
40+
node = static_cast<AnalyserNode*>(mStream->Engine()->Node());
41+
}
3442
if (node) {
3543
node->AppendChunk(mChunk);
3644
}
@@ -56,7 +64,9 @@ class AnalyserNodeEngine : public AudioNodeEngine
5664
{
5765
*aOutput = aInput;
5866

59-
if (mNode &&
67+
MutexAutoLock lock(NodeMutex());
68+
69+
if (Node() &&
6070
aInput.mChannelData.Length() > 0) {
6171
nsRefPtr<TransferBuffer> transfer = new TransferBuffer(aStream, aInput);
6272
NS_DispatchToMainThread(transfer);

content/media/webaudio/AudioNode.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,17 @@ void
205205
AudioNode::DestroyMediaStream()
206206
{
207207
if (mStream) {
208-
// Remove the node reference on the engine
209-
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
210-
MOZ_ASSERT(ns, "How come we don't have a stream here?");
211-
MOZ_ASSERT(ns->Engine()->mNode == this, "Invalid node reference");
212-
ns->Engine()->mNode = nullptr;
208+
{
209+
// Remove the node reference on the engine, and take care to not
210+
// hold the lock when the stream gets destroyed, because that will
211+
// cause the engine to be destroyed as well, and we don't want to
212+
// be holding the lock as we're trying to destroy it!
213+
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
214+
MutexAutoLock lock(ns->Engine()->NodeMutex());
215+
MOZ_ASSERT(ns, "How come we don't have a stream here?");
216+
MOZ_ASSERT(ns->Engine()->Node() == this, "Invalid node reference");
217+
ns->Engine()->ClearNode();
218+
}
213219

214220
mStream->Destroy();
215221
mStream = nullptr;

content/media/webaudio/DelayNode.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ class DelayNodeEngine : public AudioNodeEngine
3737

3838
NS_IMETHOD Run()
3939
{
40-
nsRefPtr<DelayNode> node = static_cast<DelayNode*>(mStream->Engine()->Node());
40+
nsRefPtr<DelayNode> node;
41+
{
42+
// No need to keep holding the lock for the whole duration of this
43+
// function, since we're holding a strong reference to it, so if
44+
// we can obtain the reference, we will hold the node alive in
45+
// this function.
46+
MutexAutoLock lock(mStream->Engine()->NodeMutex());
47+
node = static_cast<DelayNode*>(mStream->Engine()->Node());
48+
}
4149
if (node) {
4250
if (mChange == ADDREF) {
4351
node->mPlayingRef.Take(node);

content/media/webaudio/DynamicsCompressorNode.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,15 @@ class DynamicsCompressorNodeEngine : public AudioNodeEngine
140140

141141
NS_IMETHODIMP Run()
142142
{
143-
nsRefPtr<DynamicsCompressorNode> node = static_cast<DynamicsCompressorNode*>(mStream->Engine()->Node());
143+
nsRefPtr<DynamicsCompressorNode> node;
144+
{
145+
// No need to keep holding the lock for the whole duration of this
146+
// function, since we're holding a strong reference to it, so if
147+
// we can obtain the reference, we will hold the node alive in
148+
// this function.
149+
MutexAutoLock lock(mStream->Engine()->NodeMutex());
150+
node = static_cast<DynamicsCompressorNode*>(mStream->Engine()->Node());
151+
}
144152
if (node) {
145153
AudioParam* reduction = node->Reduction();
146154
reduction->CancelAllEvents();

content/media/webaudio/ScriptProcessorNode.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,10 @@ class ScriptProcessorNodeEngine : public AudioNodeEngine
188188
AudioChunk* aOutput,
189189
bool* aFinished) MOZ_OVERRIDE
190190
{
191+
MutexAutoLock lock(NodeMutex());
192+
191193
// If our node is dead, just output silence
192-
if (!mNode) {
194+
if (!Node()) {
193195
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
194196
return;
195197
}
@@ -275,7 +277,15 @@ class ScriptProcessorNodeEngine : public AudioNodeEngine
275277
return NS_OK;
276278
}
277279

278-
nsRefPtr<ScriptProcessorNode> node = static_cast<ScriptProcessorNode*>(mStream->Engine()->Node());
280+
nsRefPtr<ScriptProcessorNode> node;
281+
{
282+
// No need to keep holding the lock for the whole duration of this
283+
// function, since we're holding a strong reference to it, so if
284+
// we can obtain the reference, we will hold the node alive in
285+
// this function.
286+
MutexAutoLock lock(mStream->Engine()->NodeMutex());
287+
node = static_cast<ScriptProcessorNode*>(mStream->Engine()->Node());
288+
}
279289
if (!node) {
280290
return NS_OK;
281291
}

0 commit comments

Comments
 (0)