tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit ecdc16905e250ad631f23e9ec604b8e099f7ad53
parent 6f8fbe841ac3f16980a743e8073b91e0e9ec7741
Author: Eden Chuang <echuang@mozilla.com>
Date:   Mon,  3 Nov 2025 10:46:45 +0000

Bug 1968451 - Using ThreadSafeWorkerRef instead of WeakWorkerRef in PermissionStatusSink. r=dom-worker-reviewers,hsingh,permissions-reviewers,asuth,timhuang

Differential Revision: https://phabricator.services.mozilla.com/D268513

Diffstat:
Mdom/permission/PermissionStatusSink.cpp | 42++++++++++++++++++++++++++++++++++--------
Mdom/permission/PermissionStatusSink.h | 4++--
2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/dom/permission/PermissionStatusSink.cpp b/dom/permission/PermissionStatusSink.cpp @@ -51,10 +51,26 @@ PermissionStatusSink::Init() { MutexAutoLock lock(mMutex); - mWorkerRef = WeakWorkerRef::Create( - workerPrivate, [self = RefPtr(this)] { self->Disentangle(); }); + RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create( + workerPrivate, "PermissionStatusSink", + [self = RefPtr(this)]() { self->Disentangle(); }); + if (NS_WARN_IF(!workerRef)) { + // If WorkerRef creation fails, the Worker has started shutting down. But + // we are on the Worker thread, promise handlers in + // PermissionStatus::Init()/Permissions::Query() can still be dispatched + // to the Worker thread for outer promise rejection. + return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE, + __func__); + ; + } + + mWorkerRef = new ThreadSafeWorkerRef(workerRef); } + // On the Worker thread, so the below async function must be executed before + // WorkerRef callback which should also be on the Worker thread. So the above + // created WorkerRef should protect the outer promise handling can be + // dispatched on the Worker thread. return InvokeAsync(GetMainThreadSerialEventTarget(), __func__, [self = RefPtr(this)] { MOZ_ASSERT(!self->mObserver); @@ -102,6 +118,17 @@ bool PermissionStatusSink::MaybeUpdatedByNotifyOnlyOnMainThread( void PermissionStatusSink::PermissionChangedOnMainThread() { MOZ_ASSERT(NS_IsMainThread()); + // Nothing to do if Worker had shutted down. + if (!mSerialEventTarget->IsOnCurrentThread()) { + MutexAutoLock lock(mMutex); + if (!mWorkerRef) { + return; + } + } + + // mWorkerRef is not nullptr, it will protect the promise handling can be + // dispatched to the Worker thread, even though the Worker starts shutdown, + // because mWorkerRef is nullify on the main thread. ComputeStateOnMainThread()->Then( mSerialEventTarget, __func__, [self = RefPtr(this)]( @@ -117,17 +144,16 @@ void PermissionStatusSink::Disentangle() { mPermissionStatus = nullptr; - { - MutexAutoLock lock(mMutex); - mWorkerRef = nullptr; - } - NS_DispatchToMainThread( NS_NewRunnableFunction(__func__, [self = RefPtr(this)] { if (self->mObserver) { self->mObserver->RemoveSink(self); self->mObserver = nullptr; } + { + MutexAutoLock lock(self->mMutex); + self->mWorkerRef = nullptr; + } })); } @@ -167,7 +193,7 @@ PermissionStatusSink::ComputeStateOnMainThread() { // If we have mWorkerRef, we haven't received the WorkerRef notification // yet. - WorkerPrivate* workerPrivate = mWorkerRef->GetUnsafePrivate(); + WorkerPrivate* workerPrivate = mWorkerRef->Private(); MOZ_ASSERT(workerPrivate); ancestorWindow = workerPrivate->GetAncestorWindow(); diff --git a/dom/permission/PermissionStatusSink.h b/dom/permission/PermissionStatusSink.h @@ -19,7 +19,7 @@ namespace mozilla::dom { class PermissionObserver; class PermissionStatus; -class WeakWorkerRef; +class ThreadSafeWorkerRef; class PermissionStatusSink { public: @@ -70,7 +70,7 @@ class PermissionStatusSink { // Protected by mutex. // Created and released on worker-thread. Used also on main-thread. - RefPtr<WeakWorkerRef> mWorkerRef MOZ_GUARDED_BY(mMutex); + RefPtr<ThreadSafeWorkerRef> mWorkerRef MOZ_GUARDED_BY(mMutex); PermissionName mPermissionName; nsCString mPermissionType;