Open
Bug 1844895
Opened 1 year ago
Updated 1 year ago
Assertion failure: frame.isDebuggee(), at gecko-dev/js/src/debugger/DebugAPI-inl.h:77
Categories
(Core :: JavaScript Engine: JIT, defect, P3)
Tracking
()
NEW
People
(Reporter: anbu1024.me, Unassigned)
References
(Blocks 1 open bug)
Details
Steps to reproduce:
SpiderMonkey version:
commit 920be8b5eee004fc10a2785fab49b860be4d4ba3
SpiderMonkey build cmd:
/bin/sh ../../gecko-dev/js/src/configure --enable-debug --disable-optimize --disable-shared-js --disable-tests
Exec:
./js --baseline-warmup-threshold=10 --ion-warmup-threshold=100 --ion-check-range-analysis --ion-extra-checks ./test.js
Test case:
for (let i = 512, j = 10;
(() => {
const x = i < j;
function bob() {
this.sameZoneAs = bob;
}
const alice = new bob();
const t = this.newGlobal(alice).Debugger;
class T extends t {}
const ttt = new T();
ttt.addAllGlobalsAsDebuggees();
return x;
})();
(() => {j--;})()
)
{}
async function foo(a) {
return a;
}
const f = foo();
const ppp = f.then(foo);
for (let i = 0, j = 10;
(() => {
const x = i !== j;
return x;
})();
(() => {
function black(arg) {
async function* melon(arg1) {
try { arg1.finally(melon); } catch (e) {}
return arg;
}
melon(f).next(arg);
}
const apple = new black(ppp);
const banana = apple?.constructor;
try { new banana(apple, Float32Array); } catch (e) {}
j--;
})()) {
;
}
const dbg = this.Debugger;
const obj = this.wasmIntrinsicI8VecMul(this, foo, this);
function test() {
const a = dbg();
const b = a.findAllGlobals();
return b;
}
Object.defineProperty(obj, "constructor", { writable: true, configurable: true, value: test });
const cons = obj.constructor;
const x = cons();
const y = x[1];
const z = y.makeDebuggeeValue(ppp);
z.getPromiseReactions();
gc();
Actual results:
Error msg:
Assertion failure: frame.isDebuggee(), at gecko-dev/js/src/debugger/DebugAPI-inl.h:77
Comment 1•1 year ago
|
||
Thank you for reporting!
Here's reduced testcase for --baselin-eager
option:
function f1() {}
const g1 = this.newGlobal({ sameZoneAs: f1 });
{
const dbg1 = new g1.Debugger();
dbg1.addAllGlobalsAsDebuggees();
}
const p1 = Promise.resolve();
const p2 = p1.then(() => {});
async function* f2() {
return p2;
}
p1.finally(f2);
f2().next();
const dbg2 = new Debugger();
const globals = dbg2.findAllGlobals();
const g2 = globals[1];
const q2 = g2.makeDebuggeeValue(p2);
q2.getPromiseReactions();
gc();
What's happening here is the following:
- debugger
dbg1
is created and it adds all globals as debuggee - after leaving the block around
dbg1
, it's has no reference and will be collected on the next GC - async generator
f2
is called and gets baseline-compiled - during the baseline-compilation, given the global is debugee, debug epilogue is generated [1]
f2
gets suspended on implicitawait
inreturn p2
DebuggerFrame
is created for the suspendedf2
's frame ingetPromiseReactions
, and it createsDebugScript
- the debugger
dbg1
gets GC-ed ingc()
call, and all globals are no longer debugeee - when GC-ing the debugger, the
DebugScript
doesn't get removed due to theDebuggerFrame
above (not sure why it's not GC-ed in this case tho, explicitly keeping a reference can cause this) - after the top-level script finishes, the job queue is drained
f2
gets resumed, and it reaches the debug epilogue- the debug epilogue hits the assertion failure because the frame isn't marked as debuggee, but the script still has the
DebugScript
[2]
template <typename Handler>
bool BaselineCodeGen<Handler>::emitDebugEpilogue() {
...
if (!callVM<Fn, jit::DebugEpilogueOnBaselineReturn>(kind)) {
...
bool BaselineCodeGen<Handler>::emitReturn() {
if (handler.shouldEmitDebugEpilogueAtReturnOp()) {
if (!emitDebugEpilogue()) {
return false;
MOZ_ASSERT_IF(frame.hasScript() && frame.script()->isDebuggee(),
frame.isDebuggee());
Anyway, if a DebugScript
can be kept after the Debugger
gets GC-ed, logic around that should expect that case.
So far this is just an assertion failure and it doesn't go wrong on non-debug build.
You need to log in
before you can comment on or make changes to this bug.
Description
•