From aee1effa487849cc3c48c28c60a866211b05ebae Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 14 Feb 2023 10:32:47 +0000 Subject: [PATCH] Part 1: Disallow GC while iterating global's debugger vector Conflict:NA Reference:https://hg.mozilla.org/integration/autoland/rev/760275af660b20d35ace80f4d245c4ad9c4a3869 --- js/src/debugger/Debugger.cpp | 37 +++++++++++++++++++++++------------- js/src/debugger/Debugger.h | 10 ++++++---- js/src/gc/GC.h | 2 +- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/js/src/debugger/Debugger.cpp b/js/src/debugger/Debugger.cpp index be22c18354..56a172c457 100644 --- a/js/src/debugger/Debugger.cpp +++ b/js/src/debugger/Debugger.cpp @@ -1240,8 +1240,9 @@ bool DebugAPI::slowPathOnNewGenerator(JSContext* cx, AbstractFramePtr frame, MakeScopeExit([&] { Debugger::terminateDebuggerFrames(cx, frame); }); bool ok = true; + gc::AutoSuppressGC nogc(cx); Debugger::forEachOnStackDebuggerFrame( - frame, [&](Debugger* dbg, DebuggerFrame* frameObjPtr) { + frame, nogc, [&](Debugger* dbg, DebuggerFrame* frameObjPtr) { if (!ok) { return; } @@ -3265,7 +3266,10 @@ bool Debugger::updateExecutionObservabilityOfScripts( template /* static */ -void Debugger::forEachOnStackDebuggerFrame(AbstractFramePtr frame, FrameFn fn) { +void Debugger::forEachOnStackDebuggerFrame(AbstractFramePtr frame, + const JS::AutoRequireNoGC& nogc, + FrameFn fn) { + // GC is disallowed because it may mutate the vector we are iterating. for (Realm::DebuggerVectorEntry& entry : frame.global()->getDebuggers()) { Debugger* dbg = entry.dbg; if (FrameMap::Ptr frameEntry = dbg->frames.lookup(frame)) { @@ -3276,9 +3280,10 @@ void Debugger::forEachOnStackDebuggerFrame(AbstractFramePtr frame, FrameFn fn) { template /* static */ -void Debugger::forEachOnStackOrSuspendedDebuggerFrame(JSContext* cx, - AbstractFramePtr frame, - FrameFn fn) { +void Debugger::forEachOnStackOrSuspendedDebuggerFrame( + JSContext* cx, AbstractFramePtr frame, const JS::AutoRequireNoGC& nogc, + FrameFn fn) { + // GC is disallowed because it may mutate the vector we are iterating. Rooted genObj( cx, frame.isGeneratorFrame() ? GetGeneratorObjectForFrame(cx, frame) : nullptr); @@ -3304,11 +3309,13 @@ void Debugger::forEachOnStackOrSuspendedDebuggerFrame(JSContext* cx, bool Debugger::getDebuggerFrames(AbstractFramePtr frame, MutableHandle frames) { bool hadOOM = false; - forEachOnStackDebuggerFrame(frame, [&](Debugger*, DebuggerFrame* frameobj) { - if (!hadOOM && !frames.append(frameobj)) { - hadOOM = true; - } - }); + JS::AutoAssertNoGC nogc; + forEachOnStackDebuggerFrame(frame, nogc, + [&](Debugger*, DebuggerFrame* frameobj) { + if (!hadOOM && !frames.append(frameobj)) { + hadOOM = true; + } + }); return !hadOOM; } @@ -6466,8 +6473,10 @@ bool Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from, /* static */ bool DebugAPI::inFrameMaps(AbstractFramePtr frame) { bool foundAny = false; + JS::AutoAssertNoGC nogc; Debugger::forEachOnStackDebuggerFrame( - frame, [&](Debugger*, DebuggerFrame* frameobj) { foundAny = true; }); + frame, nogc, + [&](Debugger*, DebuggerFrame* frameobj) { foundAny = true; }); return foundAny; } @@ -6475,8 +6484,9 @@ bool DebugAPI::inFrameMaps(AbstractFramePtr frame) { void Debugger::suspendGeneratorDebuggerFrames(JSContext* cx, AbstractFramePtr frame) { JSFreeOp* fop = cx->runtime()->defaultFreeOp(); + JS::AutoAssertNoGC nogc; forEachOnStackDebuggerFrame( - frame, [&](Debugger* dbg, DebuggerFrame* dbgFrame) { + frame, nogc, [&](Debugger* dbg, DebuggerFrame* dbgFrame) { dbg->frames.remove(frame); #if DEBUG @@ -6495,8 +6505,9 @@ void Debugger::suspendGeneratorDebuggerFrames(JSContext* cx, void Debugger::terminateDebuggerFrames(JSContext* cx, AbstractFramePtr frame) { JSFreeOp* fop = cx->runtime()->defaultFreeOp(); + JS::AutoAssertNoGC nogc; forEachOnStackOrSuspendedDebuggerFrame( - cx, frame, [&](Debugger* dbg, DebuggerFrame* dbgFrame) { + cx, frame, nogc, [&](Debugger* dbg, DebuggerFrame* dbgFrame) { Debugger::terminateDebuggerFrame(fop, dbg, dbgFrame, frame); }); diff --git a/js/src/debugger/Debugger.h b/js/src/debugger/Debugger.h index bc89e4bfb1..d9da8bbe36 100644 --- a/js/src/debugger/Debugger.h +++ b/js/src/debugger/Debugger.h @@ -930,11 +930,13 @@ class Debugger : private mozilla::LinkedListElement { IsObserving observing); template - static void forEachOnStackDebuggerFrame(AbstractFramePtr frame, FrameFn fn); + static void forEachOnStackDebuggerFrame(AbstractFramePtr frame, + const JS::AutoRequireNoGC& nogc, + FrameFn fn); template - static void forEachOnStackOrSuspendedDebuggerFrame(JSContext* cx, - AbstractFramePtr frame, - FrameFn fn); + static void forEachOnStackOrSuspendedDebuggerFrame( + JSContext* cx, AbstractFramePtr frame, const JS::AutoRequireNoGC& nogc, + FrameFn fn); /* * Return a vector containing all Debugger.Frame instances referring to diff --git a/js/src/gc/GC.h b/js/src/gc/GC.h index 9cee0190b6..c6fe40c263 100644 --- a/js/src/gc/GC.h +++ b/js/src/gc/GC.h @@ -179,7 +179,7 @@ static inline void MaybeVerifyBarriers(JSContext* cx, bool always = false) {} * This works by updating the |JSContext::suppressGC| counter which is checked * at the start of GC. */ -class MOZ_RAII JS_HAZ_GC_SUPPRESSED AutoSuppressGC { +class MOZ_RAII JS_HAZ_GC_SUPPRESSED AutoSuppressGC : public JS::AutoRequireNoGC { int32_t& suppressGC_; public: -- 2.33.0