Bug 1724101 - Protect nsHtml5StreamListener::mDelegate with a monitor. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D122471
This commit is contained in:
Henri Sivonen 2021-08-13 12:13:48 +00:00
parent 56f30defc0
commit 10374eb129
6 changed files with 74 additions and 19 deletions

View File

@ -38,6 +38,7 @@ EXPORTS += [
"nsHtml5StreamListener.h",
"nsHtml5StreamParser.h",
"nsHtml5StreamParserPtr.h",
"nsHtml5StreamParserReleaser.h",
"nsHtml5String.h",
"nsHtml5StringParser.h",
"nsHtml5SVGLoadDispatcher.h",

View File

@ -4,6 +4,8 @@
#include "nsHtml5StreamListener.h"
#include "nsHtml5StreamParserReleaser.h"
NS_IMPL_ADDREF(nsHtml5StreamListener)
NS_IMPL_RELEASE(nsHtml5StreamListener)
@ -15,14 +17,40 @@ NS_INTERFACE_MAP_BEGIN(nsHtml5StreamListener)
NS_INTERFACE_MAP_END
nsHtml5StreamListener::nsHtml5StreamListener(nsHtml5StreamParser* aDelegate)
: mDelegate(aDelegate) {}
: mDelegateMonitor("nsHtml5StreamListener mDelegateMonitor"),
mDelegate(aDelegate) {
MOZ_ASSERT(aDelegate, "Must have delegate");
aDelegate->AddRef();
}
nsHtml5StreamListener::~nsHtml5StreamListener() {}
nsHtml5StreamListener::~nsHtml5StreamListener() { DropDelegateImpl(); }
void nsHtml5StreamListener::DropDelegate() {
MOZ_ASSERT(NS_IsMainThread(),
"Must not call DropDelegate from non-main threads.");
mDelegate = nullptr;
DropDelegateImpl();
}
void nsHtml5StreamListener::DropDelegateImpl() {
mozilla::ReentrantMonitorAutoEnter autoEnter(mDelegateMonitor);
if (mDelegate) {
nsCOMPtr<nsIRunnable> releaser = new nsHtml5StreamParserReleaser(mDelegate);
if (NS_FAILED(mDelegate->DispatchToMain(releaser.forget()))) {
NS_WARNING("Failed to dispatch releaser event.");
}
mDelegate = nullptr;
}
}
nsHtml5StreamParser* nsHtml5StreamListener::GetDelegate() {
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
// Let's acquire the monitor in order to always access mDelegate
// with monitor held. Since this can be called only on the main
// thread and DropDelegate() can only be called on the main thread
// it's OK that the monitor here doesn't protect the use of the
// return value.
mozilla::ReentrantMonitorAutoEnter autoEnter(mDelegateMonitor);
return mDelegate;
}
NS_IMETHODIMP
@ -35,6 +63,7 @@ nsHtml5StreamListener::CheckListenerChain() {
NS_IMETHODIMP
nsHtml5StreamListener::OnStartRequest(nsIRequest* aRequest) {
mozilla::ReentrantMonitorAutoEnter autoEnter(mDelegateMonitor);
if (MOZ_UNLIKELY(!mDelegate)) {
return NS_ERROR_NOT_AVAILABLE;
}
@ -43,6 +72,7 @@ nsHtml5StreamListener::OnStartRequest(nsIRequest* aRequest) {
NS_IMETHODIMP
nsHtml5StreamListener::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
mozilla::ReentrantMonitorAutoEnter autoEnter(mDelegateMonitor);
if (MOZ_UNLIKELY(!mDelegate)) {
return NS_ERROR_NOT_AVAILABLE;
}
@ -54,6 +84,7 @@ nsHtml5StreamListener::OnDataAvailable(nsIRequest* aRequest,
nsIInputStream* aInStream,
uint64_t aSourceOffset,
uint32_t aLength) {
mozilla::ReentrantMonitorAutoEnter autoEnter(mDelegateMonitor);
if (MOZ_UNLIKELY(!mDelegate)) {
return NS_ERROR_NOT_AVAILABLE;
}

View File

@ -7,8 +7,8 @@
#include "nsIStreamListener.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "nsHtml5StreamParserPtr.h"
#include "nsHtml5StreamParser.h"
#include "mozilla/ReentrantMonitor.h"
/**
* The purpose of this class is to reconcile the problem that
@ -38,14 +38,23 @@ class nsHtml5StreamListener : public nsIStreamListener,
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
inline nsHtml5StreamParser* GetDelegate() { return mDelegate; }
// Main-thread-only
nsHtml5StreamParser* GetDelegate();
// Main-thread-only
void DropDelegate();
private:
void DropDelegateImpl();
virtual ~nsHtml5StreamListener();
nsHtml5StreamParserPtr mDelegate;
// ReentrantMonitor instead of Mutex, because `GetDelegate()`
// can be called from within the Necko callbacks when Necko events
// are delivered on the main thread.
mozilla::ReentrantMonitor mDelegateMonitor;
// Owning pointer with manually-managed refcounting, protected by
// mDelegateMonitor.
nsHtml5StreamParser* mDelegate;
};
#endif // nsHtml5StreamListener_h

View File

@ -191,6 +191,7 @@ class nsHtml5StreamParser final : public nsISupports {
friend class nsHtml5StreamParserContinuation;
friend class nsHtml5TimerKungFu;
friend class nsHtml5StreamParserPtr;
friend class nsHtml5StreamListener;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View File

@ -7,22 +7,10 @@
#define nsHtml5StreamParserPtr_h
#include "nsHtml5StreamParser.h"
#include "nsHtml5StreamParserReleaser.h"
#include "nsThreadUtils.h"
#include "mozilla/dom/DocGroup.h"
class nsHtml5StreamParserReleaser : public mozilla::Runnable {
private:
nsHtml5StreamParser* mPtr;
public:
explicit nsHtml5StreamParserReleaser(nsHtml5StreamParser* aPtr)
: mozilla::Runnable("nsHtml5StreamParserReleaser"), mPtr(aPtr) {}
NS_IMETHOD Run() override {
mPtr->Release();
return NS_OK;
}
};
/**
* Like nsRefPtr except release is proxied to the main
* thread. Mostly copied from nsRefPtr.

View File

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsHtml5StreamParserReleaser_h
#define nsHtml5StreamParserReleaser_h
#include "nsHtml5StreamParser.h"
#include "nsThreadUtils.h"
class nsHtml5StreamParserReleaser : public mozilla::Runnable {
private:
nsHtml5StreamParser* mPtr;
public:
explicit nsHtml5StreamParserReleaser(nsHtml5StreamParser* aPtr)
: mozilla::Runnable("nsHtml5StreamParserReleaser"), mPtr(aPtr) {}
NS_IMETHOD Run() override {
mPtr->Release();
return NS_OK;
}
};
#endif // nsHtml5StreamParserReleaser_h