tor-browser

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

commit be45c3dff0d54d13191e9684f34b8ebb10a8aff6
parent 683ff1c5684b7bfce9aec2f0c9b1f41699962897
Author: Tooru Fujisawa <arai_a@mac.com>
Date:   Wed, 29 Oct 2025 09:18:44 +0000

Bug 1995991 - Do not assert the remaining tasks when force-quitting. r=iain

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

Diffstat:
Ajs/src/jit-test/tests/atomics/waitAsync-quit.js | 11+++++++++++
Mjs/src/shell/js.cpp | 9+++++++++
Mjs/src/vm/OffThreadPromiseRuntimeState.cpp | 12++++++++----
Mjs/src/vm/OffThreadPromiseRuntimeState.h | 11+++++++++++
4 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/js/src/jit-test/tests/atomics/waitAsync-quit.js b/js/src/jit-test/tests/atomics/waitAsync-quit.js @@ -0,0 +1,11 @@ +// This shouldn't hit any assertion failure during the shutdown. + +let c = new SharedArrayBuffer(16); +let d = new Int32Array(c); + +for (var i = 0; i < 200; i++) { + Atomics.waitAsync(d, 0, 0, 1); +} + +// Any remainig delayed tasks for the timeout should be ignored. +quit(); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp @@ -2761,6 +2761,15 @@ static bool ConvertTranscodeResultToJSException(JSContext* cx, static void SetQuitting(JSContext* cx, int32_t code) { ShellContext* sc = GetShellContext(cx); js::StopDrainingJobQueue(cx); +#ifdef DEBUG + { + AutoLockHelperThreadState helperLock; + + OffThreadPromiseRuntimeState& state = + cx->runtime()->offThreadPromiseState.ref(); + state.setForceQuitting(); + } +#endif sc->exitCode = code; sc->quitting = true; } diff --git a/js/src/vm/OffThreadPromiseRuntimeState.cpp b/js/src/vm/OffThreadPromiseRuntimeState.cpp @@ -249,13 +249,17 @@ OffThreadPromiseRuntimeState::OffThreadPromiseRuntimeState() : dispatchToEventLoopCallback_(nullptr), delayedDispatchToEventLoopCallback_(nullptr), dispatchToEventLoopClosure_(nullptr), +#ifdef DEBUG + forceQuitting_(false), +#endif numRegistered_(0), - internalDispatchQueueClosed_(false) {} + internalDispatchQueueClosed_(false) { +} OffThreadPromiseRuntimeState::~OffThreadPromiseRuntimeState() { - MOZ_ASSERT(numRegistered_ == 0); - MOZ_ASSERT(numDelayed_ == 0); - MOZ_ASSERT(internalDispatchQueue_.refNoCheck().empty()); + MOZ_ASSERT_IF(!forceQuitting_, numRegistered_ == 0); + MOZ_ASSERT_IF(!forceQuitting_, numDelayed_ == 0); + MOZ_ASSERT_IF(!forceQuitting_, internalDispatchQueue_.refNoCheck().empty()); MOZ_ASSERT(!initialized()); } diff --git a/js/src/vm/OffThreadPromiseRuntimeState.h b/js/src/vm/OffThreadPromiseRuntimeState.h @@ -259,6 +259,13 @@ class OffThreadPromiseRuntimeState { JS::DelayedDispatchToEventLoopCallback delayedDispatchToEventLoopCallback_; void* dispatchToEventLoopClosure_; +#ifdef DEBUG + // Set to true when the JS shell is force-quitting. + // In this case the tasks won't be drained and the destructor cannot + // assert anything. + HelperThreadLockData<bool> forceQuitting_; +#endif + // A set of all OffThreadPromiseTasks that have successfully called 'init'. // This set doesn't own tasks. OffThreadPromiseTask's destructor decrements // this counter. @@ -357,6 +364,10 @@ class OffThreadPromiseRuntimeState { // shutdown() must be called by the JSRuntime while the JSRuntime is valid. void shutdown(JSContext* cx); + +#ifdef DEBUG + void setForceQuitting() { forceQuitting_ = true; } +#endif }; } // namespace js