commit a8dfb8b4c814b294b02f737575a15810107c60c9
parent 52fdd186700f329256cc2fd782ad6a48d0549fdb
Author: Jon Coppeard <jcoppeard@mozilla.com>
Date: Tue, 2 Dec 2025 08:26:44 +0000
Bug 2003100 - Suppress GC during wrapper remapping r=sfink
We rely on tracing a CCW to the debugger from a script with a breakpoint that's
in another compartment. The problem here is that wrapper remapping can trigger
a GC after nuking the original CCW but before remapping is complete, meaning
that we wouldn't trace the debugger target in this case.
The patch suppresses GC during remapping.
Differential Revision: https://phabricator.services.mozilla.com/D274575
Diffstat:
2 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/js/src/jit-test/tests/gc/bug-2003100.js b/js/src/jit-test/tests/gc/bug-2003100.js
@@ -0,0 +1,9 @@
+var dbgA = new Debugger;
+var g1 = newGlobal({newCompartment: true});
+g1.eval('function g1f() { print("Weltuntergang"); }');
+var DOAg1 = dbgA.addDebuggee(g1);
+var DOAg1f = DOAg1.getOwnPropertyDescriptor('g1f').value;
+DOAg1f.script.setBreakpoint(0, { hit: () => { logA += '1'; } });
+gczeal(2,1)
+class Base { }
+recomputeWrappers();
diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -508,6 +508,9 @@ void js::RemapWrapper(JSContext* cx, JSObject* wobjArg,
AutoDisableProxyCheck adpc;
+ // This can't GC (and RemapDeadWrapper suppresses it).
+ JS::AutoAssertNoGC nogc(cx);
+
// If we're mapping to a different target (as opposed to just recomputing
// for the same target), we must not have an existing wrapper for the new
// target, otherwise this will break.
@@ -549,6 +552,10 @@ void js::RemapDeadWrapper(JSContext* cx, HandleObject wobj,
AutoDisableProxyCheck adpc;
+ // Suppress GC while we manipulate the wrapper map so that it can't observe
+ // intervening state.
+ gc::AutoSuppressGC nogc(cx);
+
// wobj is not a cross-compartment wrapper, so we can use nonCCWRealm.
Realm* wrealm = wobj->nonCCWRealm();