Bug 1658571 - Don't create a reference cycle when catching redirects of a preload. r=smaug

PreloaderBase -> RedirectSink -> PreloaderBase is a strong,
non-cycle-collected reference cycle, which in cases where we don't drop
the channel because we never get an NotifyStop notification, it can
cause leaks.

I'm investigating the root cause of the lack of NotifyStop, but this
should fix the leak and is correct anyhow.

Move the class to the cpp file to ease debugging and changes.

Differential Revision: https://phabricator.services.mozilla.com/D91259
This commit is contained in:
Emilio Cobos Álvarez 2020-09-24 16:01:50 +00:00
Родитель 9626163a2a
Коммит a88d74d517
2 изменённых файлов: 34 добавлений и 24 удалений

Просмотреть файл

@ -22,11 +22,35 @@ PreloaderBase::UsageTimer::UsageTimer(PreloaderBase* aPreload,
dom::Document* aDocument) dom::Document* aDocument)
: mDocument(aDocument), mPreload(aPreload) {} : mDocument(aDocument), mPreload(aPreload) {}
class PreloaderBase::RedirectSink final : public nsIInterfaceRequestor,
public nsIChannelEventSink,
public nsIRedirectResultListener {
RedirectSink() = delete;
virtual ~RedirectSink();
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIREDIRECTRESULTLISTENER
RedirectSink(PreloaderBase* aPreloader, nsIInterfaceRequestor* aCallbacks);
private:
WeakPtr<PreloaderBase> mPreloader;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsIChannel> mRedirectChannel;
};
PreloaderBase::RedirectSink::RedirectSink(PreloaderBase* aPreloader, PreloaderBase::RedirectSink::RedirectSink(PreloaderBase* aPreloader,
nsIInterfaceRequestor* aCallbacks) nsIInterfaceRequestor* aCallbacks)
: mPreloader(new nsMainThreadPtrHolder<PreloaderBase>( : mPreloader(aPreloader), mCallbacks(aCallbacks) {}
"RedirectSink.mPreloader", aPreloader)),
mCallbacks(aCallbacks) {} PreloaderBase::RedirectSink::~RedirectSink() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
"Should figure out how to safely drop mPreloader "
"otherwise");
}
NS_IMPL_ISUPPORTS(PreloaderBase::RedirectSink, nsIInterfaceRequestor, NS_IMPL_ISUPPORTS(PreloaderBase::RedirectSink, nsIInterfaceRequestor,
nsIChannelEventSink, nsIRedirectResultListener) nsIChannelEventSink, nsIRedirectResultListener)
@ -34,13 +58,17 @@ NS_IMPL_ISUPPORTS(PreloaderBase::RedirectSink, nsIInterfaceRequestor,
NS_IMETHODIMP PreloaderBase::RedirectSink::AsyncOnChannelRedirect( NS_IMETHODIMP PreloaderBase::RedirectSink::AsyncOnChannelRedirect(
nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags, nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* aCallback) { nsIAsyncVerifyRedirectCallback* aCallback) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
mRedirectChannel = aNewChannel; mRedirectChannel = aNewChannel;
// Deliberately adding this before confirmation. // Deliberately adding this before confirmation.
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
aNewChannel->GetOriginalURI(getter_AddRefs(uri)); aNewChannel->GetOriginalURI(getter_AddRefs(uri));
mPreloader->mRedirectRecords.AppendElement( if (mPreloader) {
RedirectRecord(aFlags, uri.forget())); mPreloader->mRedirectRecords.AppendElement(
RedirectRecord(aFlags, uri.forget()));
}
if (mCallbacks) { if (mCallbacks) {
nsCOMPtr<nsIChannelEventSink> sink(do_GetInterface(mCallbacks)); nsCOMPtr<nsIChannelEventSink> sink(do_GetInterface(mCallbacks));

Просмотреть файл

@ -150,25 +150,7 @@ class PreloaderBase : public SupportsWeakPtr, public nsISupports {
// directly is to keep PreloaderBase as simple as possible so that derived // directly is to keep PreloaderBase as simple as possible so that derived
// classes don't have to deal with calling super when implementing these // classes don't have to deal with calling super when implementing these
// interfaces from some reason as well. // interfaces from some reason as well.
class RedirectSink final : public nsIInterfaceRequestor, class RedirectSink;
public nsIChannelEventSink,
public nsIRedirectResultListener {
RedirectSink() = delete;
virtual ~RedirectSink() = default;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIREDIRECTRESULTLISTENER
RedirectSink(PreloaderBase* aPreloader, nsIInterfaceRequestor* aCallbacks);
private:
nsMainThreadPtrHandle<PreloaderBase> mPreloader;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsIChannel> mRedirectChannel;
};
// A timer callback to trigger the unuse warning for this preload // A timer callback to trigger the unuse warning for this preload
class UsageTimer final : public nsITimerCallback { class UsageTimer final : public nsITimerCallback {