Bug 1495748: Make sure ChannelWrappers get cleaned up before JS engine shutdown. r=aswan,mccr8
The gross contortions here are required to deal with the deferred finalizers HTTP channels use for their property bags. The actual channels get destroyed relatively early during shutdown, but their property bag hashes which hold our ChannelWrapper reference end up being destroyed after JS engine shutdown, which gives us no good point to clear our reference. The stub holder class takes the place of our existing property bag entry, and behaves more or less the same, but allows us to cut the reference to the ChannelWrapper without having a strong reference to the channel. Differential Revision: https://phabricator.services.mozilla.com/D8923
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "nsITransportSecurityInfo.h"
|
||||
|
||||
#include "mozilla/AddonManagerWebAPI.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/ErrorNames.h"
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
#include "mozilla/Unused.h"
|
||||
@@ -32,6 +33,7 @@
|
||||
#include "nsIProxiedChannel.h"
|
||||
#include "nsIProxyInfo.h"
|
||||
#include "nsITraceableChannel.h"
|
||||
#include "nsIWritablePropertyBag.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsProxyRelease.h"
|
||||
@@ -45,12 +47,81 @@ namespace extensions {
|
||||
|
||||
#define CHANNELWRAPPER_PROP_KEY NS_LITERAL_STRING("ChannelWrapper::CachedInstance")
|
||||
|
||||
/*****************************************************************************
|
||||
* Lifetimes
|
||||
*****************************************************************************/
|
||||
|
||||
namespace {
|
||||
class ChannelListHolder : public LinkedList<ChannelWrapper>
|
||||
{
|
||||
public:
|
||||
ChannelListHolder()
|
||||
: LinkedList<ChannelWrapper>()
|
||||
{}
|
||||
|
||||
~ChannelListHolder();
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ChannelListHolder::~ChannelListHolder()
|
||||
{
|
||||
while (ChannelWrapper* wrapper = popFirst()) {
|
||||
wrapper->Die();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LinkedList<ChannelWrapper>&
|
||||
ChannelList()
|
||||
{
|
||||
static UniquePtr<ChannelListHolder> sChannelList;
|
||||
if (!sChannelList) {
|
||||
sChannelList.reset(new ChannelListHolder());
|
||||
ClearOnShutdown(&sChannelList, ShutdownPhase::Shutdown);
|
||||
}
|
||||
return *sChannelList;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ChannelWrapper::ChannelWrapperStub)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ChannelWrapper::ChannelWrapperStub)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(ChannelWrapper::ChannelWrapperStub, mChannelWrapper)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChannelWrapper::ChannelWrapperStub)
|
||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(ChannelWrapper, mChannelWrapper)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
/*****************************************************************************
|
||||
* Initialization
|
||||
*****************************************************************************/
|
||||
|
||||
/* static */
|
||||
ChannelWrapper::ChannelWrapper(nsISupports* aParent, nsIChannel* aChannel)
|
||||
: ChannelHolder(aChannel)
|
||||
, mParent(aParent)
|
||||
{
|
||||
mStub = new ChannelWrapperStub(this);
|
||||
|
||||
ChannelList().insertBack(this);
|
||||
}
|
||||
|
||||
ChannelWrapper::~ChannelWrapper()
|
||||
{
|
||||
if (LinkedListElement<ChannelWrapper>::isInList()) {
|
||||
LinkedListElement<ChannelWrapper>::remove();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChannelWrapper::Die()
|
||||
{
|
||||
if (mStub) {
|
||||
mStub->mChannelWrapper = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<ChannelWrapper>
|
||||
ChannelWrapper::Get(const GlobalObject& global, nsIChannel* channel)
|
||||
{
|
||||
@@ -72,7 +143,7 @@ ChannelWrapper::Get(const GlobalObject& global, nsIChannel* channel)
|
||||
wrapper = new ChannelWrapper(global.GetAsSupports(), channel);
|
||||
if (props) {
|
||||
Unused << props->SetPropertyAsInterface(CHANNELWRAPPER_PROP_KEY,
|
||||
wrapper);
|
||||
wrapper->mStub);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1055,10 +1126,12 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStub)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStub)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "mozilla/extensions/WebExtensionPolicy.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
@@ -111,6 +112,7 @@ class WebRequestChannelEntry;
|
||||
|
||||
class ChannelWrapper final : public DOMEventTargetHelper
|
||||
, public SupportsWeakPtr<ChannelWrapper>
|
||||
, public LinkedListElement<ChannelWrapper>
|
||||
, private detail::ChannelHolder
|
||||
{
|
||||
public:
|
||||
@@ -120,6 +122,8 @@ public:
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CHANNELWRAPPER_IID)
|
||||
|
||||
void Die();
|
||||
|
||||
static already_AddRefed<extensions::ChannelWrapper> Get(const dom::GlobalObject& global, nsIChannel* channel);
|
||||
static already_AddRefed<extensions::ChannelWrapper> GetRegisteredChannel(const dom::GlobalObject& global, uint64_t aChannelId, const WebExtensionPolicy& aAddon, nsITabParent* aTabParent);
|
||||
|
||||
@@ -241,13 +245,10 @@ public:
|
||||
JSObject* WrapObject(JSContext* aCx, JS::HandleObject aGivenProto) override;
|
||||
|
||||
protected:
|
||||
~ChannelWrapper() = default;
|
||||
~ChannelWrapper();
|
||||
|
||||
private:
|
||||
ChannelWrapper(nsISupports* aParent, nsIChannel* aChannel)
|
||||
: ChannelHolder(aChannel)
|
||||
, mParent(aParent)
|
||||
{}
|
||||
ChannelWrapper(nsISupports* aParent, nsIChannel* aChannel);
|
||||
|
||||
void ClearCachedAttributes();
|
||||
|
||||
@@ -279,6 +280,27 @@ private:
|
||||
|
||||
void CheckEventListeners();
|
||||
|
||||
class ChannelWrapperStub final : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(ChannelWrapperStub)
|
||||
|
||||
explicit ChannelWrapperStub(ChannelWrapper* aChannelWrapper)
|
||||
: mChannelWrapper(aChannelWrapper)
|
||||
{}
|
||||
|
||||
private:
|
||||
friend class ChannelWrapper;
|
||||
|
||||
RefPtr<ChannelWrapper> mChannelWrapper;
|
||||
|
||||
protected:
|
||||
~ChannelWrapperStub() = default;
|
||||
};
|
||||
|
||||
RefPtr<ChannelWrapperStub> mStub;
|
||||
|
||||
mutable Maybe<URLInfo> mFinalURLInfo;
|
||||
mutable Maybe<URLInfo> mDocumentURLInfo;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user