From 391372ea9970e2a01798042d1f421710b6497e06 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sat, 3 Oct 2015 00:18:24 +1000 Subject: [PATCH] Bug 1186745 part 6 - Fix event leak when using NS_DispatchToCurrentThread. r=froydnj --- xpcom/glue/nsThreadUtils.cpp | 32 +++++++++++++++++++++++++------- xpcom/glue/nsThreadUtils.h | 2 ++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/xpcom/glue/nsThreadUtils.cpp b/xpcom/glue/nsThreadUtils.cpp index 228e3b86285..286037c1b8c 100644 --- a/xpcom/glue/nsThreadUtils.cpp +++ b/xpcom/glue/nsThreadUtils.cpp @@ -142,13 +142,11 @@ NS_IsMainThread() } #endif -// It is common to call NS_DispatchToCurrentThread with a newly -// allocated runnable with a refcount of zero. To keep us from leaking -// the runnable if the dispatch method fails, we take a death grip. NS_METHOD -NS_DispatchToCurrentThread(nsIRunnable* aEvent) +NS_DispatchToCurrentThread(already_AddRefed&& aEvent) { - nsCOMPtr deathGrip = aEvent; + nsresult rv; + nsCOMPtr event(aEvent); #ifdef MOZILLA_INTERNAL_API nsIThread* thread = NS_GetCurrentThread(); if (!thread) { @@ -156,12 +154,32 @@ NS_DispatchToCurrentThread(nsIRunnable* aEvent) } #else nsCOMPtr thread; - nsresult rv = NS_GetCurrentThread(getter_AddRefs(thread)); + rv = NS_GetCurrentThread(getter_AddRefs(thread)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } #endif - return thread->Dispatch(aEvent, NS_DISPATCH_NORMAL); + // To keep us from leaking the runnable if dispatch method fails, + // we grab the reference on failures and release it. + nsIRunnable* temp = event.get(); + rv = thread->Dispatch(event.forget(), NS_DISPATCH_NORMAL); + if (NS_WARN_IF(NS_FAILED(rv))) { + // Dispatch() leaked the reference to the event, but due to caller's + // assumptions, we shouldn't leak here. And given we are on the same + // thread as the dispatch target, it's mostly safe to do it here. + NS_RELEASE(temp); + } + return rv; +} + +// It is common to call NS_DispatchToCurrentThread with a newly +// allocated runnable with a refcount of zero. To keep us from leaking +// the runnable if the dispatch method fails, we take a death grip. +NS_METHOD +NS_DispatchToCurrentThread(nsIRunnable* aEvent) +{ + nsCOMPtr event(aEvent); + return NS_DispatchToCurrentThread(event.forget()); } NS_METHOD diff --git a/xpcom/glue/nsThreadUtils.h b/xpcom/glue/nsThreadUtils.h index a4997c9c9ce..b9ac39040fe 100644 --- a/xpcom/glue/nsThreadUtils.h +++ b/xpcom/glue/nsThreadUtils.h @@ -106,6 +106,8 @@ extern NS_METHOD NS_GetCurrentThread(nsIThread** aResult); * If event is null. */ extern NS_METHOD NS_DispatchToCurrentThread(nsIRunnable* aEvent); +extern NS_METHOD +NS_DispatchToCurrentThread(already_AddRefed&& aEvent); /** * Dispatch the given event to the main thread.