From 24d1611207c79c26937c480ad4bd21fc09ca1c94 Mon Sep 17 00:00:00 2001 From: Kershaw Chang Date: Wed, 20 May 2020 09:09:10 +0000 Subject: [PATCH] Bug 1629457 - Make sure TRRServiceChannel is released on target thread r=dragana The reason of this crash is because that `TRRServiceChannel` is released on the wrong thread. Bug 1616014 fixed a possible case that makes `TRRServiceChannel` release on main thread, but there could be other hidden cases that we are not aware of. To be on the safe side, we should consider to take this future-proof patch. Differential Revision: https://phabricator.services.mozilla.com/D75973 --- netwerk/protocol/http/TRRServiceChannel.cpp | 38 ++++++++++++++++++++- netwerk/protocol/http/TRRServiceChannel.h | 1 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/netwerk/protocol/http/TRRServiceChannel.cpp b/netwerk/protocol/http/TRRServiceChannel.cpp index b70408da1e0c..7acc66a8afef 100644 --- a/netwerk/protocol/http/TRRServiceChannel.cpp +++ b/netwerk/protocol/http/TRRServiceChannel.cpp @@ -29,7 +29,43 @@ namespace mozilla { namespace net { NS_IMPL_ADDREF(TRRServiceChannel) -NS_IMPL_RELEASE(TRRServiceChannel) + +// Because nsSupportsWeakReference isn't thread-safe we must ensure that +// TRRServiceChannel is destroyed on the target thread. Any Release() called +// on a different thread is dispatched to the target thread. +bool TRRServiceChannel::DispatchRelease() { + if (mCurrentEventTarget->IsOnCurrentThread()) { + return false; + } + + mCurrentEventTarget->Dispatch( + NewNonOwningRunnableMethod("net::TRRServiceChannel::Release", this, + &TRRServiceChannel::Release), + NS_DISPATCH_NORMAL); + + return true; +} + +NS_IMETHODIMP_(MozExternalRefCountType) +TRRServiceChannel::Release() { + nsrefcnt count = mRefCnt - 1; + if (DispatchRelease()) { + // Redispatched to the target thread. + return count; + } + + MOZ_ASSERT(0 != mRefCnt, "dup release"); + count = --mRefCnt; + NS_LOG_RELEASE(this, count, "TRRServiceChannel"); + + if (0 == count) { + mRefCnt = 1; + delete (this); + return 0; + } + + return count; +} NS_INTERFACE_MAP_BEGIN(TRRServiceChannel) NS_INTERFACE_MAP_ENTRY(nsIRequest) diff --git a/netwerk/protocol/http/TRRServiceChannel.h b/netwerk/protocol/http/TRRServiceChannel.h index 533b5d6ceba0..2087bc5ff5e9 100644 --- a/netwerk/protocol/http/TRRServiceChannel.h +++ b/netwerk/protocol/http/TRRServiceChannel.h @@ -134,6 +134,7 @@ class TRRServiceChannel : public HttpBaseChannel, uint32_t aRedirectFlags) override; virtual bool SameOriginWithOriginalUri(nsIURI* aURI) override; + bool DispatchRelease(); // True only when we have computed the value of the top window origin. bool mTopWindowOriginComputed;