Bug 1333112 - Fix windowClient.Navigate leak. r=bkelly

This commit is contained in:
Catalin Badea 2017-01-26 21:37:17 +02:00
Родитель d1775338ca
Коммит d766bfbd2b
3 изменённых файлов: 36 добавлений и 20 удалений

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

@ -825,16 +825,6 @@ PromiseWorkerProxy::WorkerPromise() const
return mWorkerPromise;
}
void
PromiseWorkerProxy::StoreISupports(nsISupports* aSupports)
{
MOZ_ASSERT(NS_IsMainThread());
nsMainThreadPtrHandle<nsISupports> supports(
new nsMainThreadPtrHolder<nsISupports>(aSupports));
mSupportsArray.AppendElement(supports);
}
void
PromiseWorkerProxy::RunCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue,

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

@ -147,8 +147,6 @@ public:
// worker thread! Do not call this after calling CleanUp().
Promise* WorkerPromise() const;
void StoreISupports(nsISupports* aSupports);
// Worker thread only. Calling this invalidates several assumptions, so be
// sure this is the last thing you do.
// 1. WorkerPrivate() will no longer return a valid worker.
@ -217,10 +215,6 @@ private:
const PromiseWorkerProxyStructuredCloneCallbacks* mCallbacks;
// Aimed to keep objects alive when doing the structured-clone read/write,
// which can be added by calling StoreISupports() on the main thread.
nsTArray<nsMainThreadPtrHandle<nsISupports>> mSupportsArray;
// Ensure the worker and the main thread won't race to access |mCleanedUp|.
Mutex mCleanUpLock;

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

@ -204,18 +204,21 @@ public:
nsIWebProgressListener)
WebProgressListener(PromiseWorkerProxy* aPromiseProxy,
ServiceWorkerPrivate* aServiceWorkerPrivate,
nsPIDOMWindowOuter* aWindow, nsIURI* aBaseURI)
: mPromiseProxy(aPromiseProxy)
, mServiceWorkerPrivate(aServiceWorkerPrivate)
, mWindow(aWindow)
, mBaseURI(aBaseURI)
{
MOZ_ASSERT(aPromiseProxy);
MOZ_ASSERT(aServiceWorkerPrivate);
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsOuterWindow());
MOZ_ASSERT(aBaseURI);
AssertIsOnMainThread();
mPromiseProxy->StoreISupports(static_cast<nsIWebProgressListener*>(this));
mServiceWorkerPrivate->StoreISupports(static_cast<nsIWebProgressListener*>(this));
}
NS_IMETHOD
@ -227,6 +230,8 @@ public:
return NS_OK;
}
// This is safe because our caller holds a strong ref.
mServiceWorkerPrivate->RemoveISupports(static_cast<nsIWebProgressListener*>(this));
aWebProgress->RemoveProgressListener(this);
WorkerPrivate* workerPrivate;
@ -308,6 +313,7 @@ private:
~WebProgressListener() {}
RefPtr<PromiseWorkerProxy> mPromiseProxy;
RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
nsCOMPtr<nsPIDOMWindowOuter> mWindow;
nsCOMPtr<nsIURI> mBaseURI;
};
@ -315,7 +321,7 @@ private:
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebProgressListener)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebProgressListener)
NS_IMPL_CYCLE_COLLECTION(WebProgressListener, mPromiseProxy,
mWindow)
mServiceWorkerPrivate, mWindow)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
@ -327,14 +333,17 @@ class ClientNavigateRunnable final : public Runnable
uint64_t mWindowId;
nsString mUrl;
nsCString mBaseUrl;
nsString mScope;
RefPtr<PromiseWorkerProxy> mPromiseProxy;
MOZ_INIT_OUTSIDE_CTOR WorkerPrivate* mWorkerPrivate;
public:
ClientNavigateRunnable(uint64_t aWindowId, const nsAString& aUrl,
const nsAString& aScope,
PromiseWorkerProxy* aPromiseProxy)
: mWindowId(aWindowId)
, mUrl(aUrl)
, mScope(aScope)
, mPromiseProxy(aPromiseProxy)
, mWorkerPrivate(nullptr)
{
@ -360,6 +369,7 @@ public:
WorkerPrivate::LocationInfo& info = mWorkerPrivate->GetLocationInfo();
mBaseUrl = info.mHref;
principal = mWorkerPrivate->GetPrincipal();
MOZ_DIAGNOSTIC_ASSERT(principal);
}
nsCOMPtr<nsIURI> baseUrl;
@ -387,8 +397,25 @@ public:
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerRegistrationInfo> registration =
swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
if (NS_WARN_IF(!registration)) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
registration->GetServiceWorkerInfoById(mWorkerPrivate->ServiceWorkerID());
if (NS_WARN_IF(!serviceWorkerInfo)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIWebProgressListener> listener =
new WebProgressListener(mPromiseProxy, window->GetOuterWindow(), baseUrl);
new WebProgressListener(mPromiseProxy, serviceWorkerInfo->WorkerPrivate(),
window->GetOuterWindow(), baseUrl);
rv = webProgress->AddProgressListener(
listener, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
@ -512,11 +539,16 @@ ServiceWorkerWindowClient::Navigate(const nsAString& aUrl, ErrorResult& aRv)
return promise.forget();
}
ServiceWorkerGlobalScope* globalScope =
static_cast<ServiceWorkerGlobalScope*>(workerPrivate->GlobalScope());
nsString scope;
globalScope->GetScope(scope);
RefPtr<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (promiseProxy) {
RefPtr<ClientNavigateRunnable> r =
new ClientNavigateRunnable(mWindowId, aUrl, promiseProxy);
new ClientNavigateRunnable(mWindowId, aUrl, scope, promiseProxy);
MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
} else {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);