Assertion failure: false, at vm/SelfHosting.cpp:417 or Assertion failure: args[0].isObject(), at vm/SelfHosting.cpp:219 with onNativeCall
Categories
(Core :: JavaScript: Debugger API, defect, P3)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox-esr115 | --- | unaffected |
| firefox-esr140 | --- | unaffected |
| firefox147 | --- | wontfix |
| firefox148 | --- | wontfix |
| firefox149 | --- | wontfix |
| firefox150 | --- | fix-optional |
People
(Reporter: gkw, Unassigned)
References
(Blocks 2 open bugs, Regression)
Details
(Keywords: regression, reporter-external, testcase)
Attachments
(1 file)
|
2.86 KB,
text/plain
|
Details |
var g = newGlobal({ newCompartment: true });
g.eval("async function h() { await 0; }");
g.h();
var x = Debugger();
x.addAllGlobalsAsDebuggees();
x.onNativeCall = function (y) {
y["call"](y);
};
(gdb) bt
#0 0x000055555836dd10 in MOZ_CrashSequence (aAddress=0x0, aLine=417) at /home/msf1/shell-cache/js-dbg-64-linux-x86_64-997d55938096-606949/objdir-js/dist/include/mozilla/Assertions.h:237
#1 intrinsic_AssertionFailed (cx=cx@entry=0x7ffff5e3d600, argc=<optimized out>, vp=<optimized out>) at /home/msf1/trees/firefox/js/src/vm/SelfHosting.cpp:417
#2 0x00005555582b1885 in CallJSNative (cx=cx@entry=0x7ffff5e3d600, native=0x55555836dbd0 <intrinsic_AssertionFailed(JSContext*, unsigned int, JS::Value*)>, reason=<optimized out>,
args=...) at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:490
#3 0x000055555828cf36 in js::InternalCallOrConstruct (cx=0x7ffff5e3d600, args=..., construct=construct@entry=js::NO_CONSTRUCT, reason=js::CallReason::Call)
at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:586
#4 0x000055555828dc08 in InternalCall (cx=<optimized out>, args=..., reason=417) at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:653
#5 0x000055555829cd80 in js::CallFromStack (cx=0x7ffff7805700 <_IO_stdfile_2_lock>, args=..., reason=<optimized out>) at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:658
/snip
a7a098a77b3e-596254
a7a098a77b3eeab64d88d8b0cc5ca5598aed8cef is the first interesting commit
commit a7a098a77b3eeab64d88d8b0cc5ca5598aed8cef
Author: Matthew Gaudet
Date: Thu Nov 13 15:44:00 2025 +0000
Bug 1997192 - Enable JS MicroTaskQueue by default r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D271689
=====
Also run with --setpref=use_js_microtask_queue=true :
811324ab997c-589653
811324ab997c958182ef1b339cd0088dca7d545b is the first interesting commit
commit 811324ab997c958182ef1b339cd0088dca7d545b
Author: Matthew Gaudet
Date: Wed Oct 1 21:38:51 2025 +0000
Bug 1983154 - Shell support for a JS MicroTaskQueue. r=arai
Also adds a method to CycleCollectedJSContext (reviewed in D261179) to
make the browser build with these changes.
Differential Revision: https://phabricator.services.mozilla.com/D261178
Run with --fuzzing-safe --no-threads --no-baseline --no-ion, compile with AR=ar sh ~/trees/firefox/js/src/configure --enable-debug --enable-debug-symbols --with-ccache --enable-nspr-build --enable-ctypes --enable-gczeal --enable-rust-simd --disable-tests, tested on gh rev 997d55938096e03a72bfedb57279d42a62cd1467.
Matt, is bug 1997192 or bug 1983154 a likely regressor?
| Reporter | ||
Comment 1•4 months ago
|
||
A variant (same flags and parameters) causes:
Assertion failure: args[0].isObject(), at vm/SelfHosting.cpp:219
var g = newGlobal({ newCompartment: true });
g.eval("async function h() { await 0; }");
g.h();
var x = Debugger();
x.addAllGlobalsAsDebuggees();
x.onNativeCall = function (y) {
Reflect.apply(y["call"], y, []);
};
(gdb) bt
#0 0x0000555558376ca3 in MOZ_CrashSequence (aAddress=0x0, aLine=219) at /home/msf1/shell-cache/js-dbg-64-linux-x86_64-997d55938096-606949/objdir-js/dist/include/mozilla/Assertions.h:237
#1 intrinsic_IsInstanceOfBuiltin<js::AsyncFunctionGeneratorObject> (cx=<optimized out>, argc=<optimized out>, vp=<optimized out>)
at /home/msf1/trees/firefox/js/src/vm/SelfHosting.cpp:219
#2 0x00005555582b1885 in CallJSNative (cx=cx@entry=0x7ffff5e38200,
native=0x555558376b10 <intrinsic_IsInstanceOfBuiltin<js::AsyncFunctionGeneratorObject>(JSContext*, unsigned int, JS::Value*)>, reason=<optimized out>, args=...)
at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:490
#3 0x000055555828cf36 in js::InternalCallOrConstruct (cx=0x7ffff5e38200, args=..., construct=construct@entry=js::NO_CONSTRUCT, reason=js::CallReason::Call)
at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:586
#4 0x000055555828dc08 in InternalCall (cx=<optimized out>, args=..., reason=219) at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:653
#5 0x000055555829cd80 in js::CallFromStack (cx=0x7ffff7805700 <_IO_stdfile_2_lock>, args=..., reason=<optimized out>) at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:658
#6 js::Interpret (cx=0x7ffff5e38200, state=...) at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:3272
#7 0x000055555828c8d7 in MaybeEnterInterpreterTrampoline (cx=0x7ffff7805700 <_IO_stdfile_2_lock>, cx@entry=0x7ffff5e38200, state=...)
at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:384
#8 0x000055555828c5ab in js::RunScript (cx=cx@entry=0x7ffff5e38200, state=...) at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:460
#9 0x000055555828cf5c in js::InternalCallOrConstruct (cx=0x7ffff5e38200, args=..., construct=construct@entry=js::NO_CONSTRUCT, reason=<optimized out>)
at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:618
#10 0x000055555828dc08 in InternalCall (cx=<optimized out>, args=..., reason=219, reason@entry=js::CallReason::Call) at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:653
#11 0x000055555828de1d in js::Call (cx=<optimized out>, fval=fval@entry=..., thisv=thisv@entry=..., args=..., rval=..., reason=reason@entry=js::CallReason::Call)
at /home/msf1/trees/firefox/js/src/vm/Interpreter.cpp:685
#12 0x00005555576ce844 in js::DebuggerObject::call (cx=0x7ffff5e38200, object=..., thisv_=..., args=args@entry=...) at /home/msf1/trees/firefox/js/src/debugger/Object.cpp:2518
#13 0x00005555576cdf98 in js::DebuggerObject::CallData::callMethod (this=this@entry=0x7fffffdfef10) at /home/msf1/trees/firefox/js/src/debugger/Object.cpp:956
#14 0x00005555576e9141 in js::DebuggerObject::CallData::ToNative<&js::DebuggerObject::CallData::callMethod> (cx=0x7ffff5e38200, argc=<optimized out>, vp=<optimized out>)
at /home/msf1/trees/firefox/js/src/debugger/Object.cpp:239
#15 0x000017bd1e0f22e3 in ?? ()
#16 0x00007fffffdfefc0 in ?? ()
#17 0x00007fffffdfefb0 in ?? ()
#18 0x0000000000000000 in ?? ()
(gdb)
Comment 2•4 months ago
|
||
Set release status flags based on info from the regressing bug 1997192
Updated•4 months ago
|
Updated•4 months ago
|
Comment 3•4 months ago
|
||
We're infinitely recursing here by calling onNativeCall while calling onNativeCall. So first and foremost we should be banning that
js/src/jit-test/tests/debug/bug2014995.js:7:5 InternalError: too much recursion
Stack:
x.onNativeCall@js/src/jit-test/tests/debug/bug2014995.js:7:5
x.onNativeCall@js/src/jit-test/tests/debug/bug2014995.js:7:5
x.onNativeCall@js/src/jit-test/tests/debug/bug2014995.js:7:5
x.onNativeCall@js/src/jit-test/tests/debug/bug2014995.js:7:5
I expect this happens because of addAllGlobalsAsDebuggees() -- these two methods feel incompatible, and AFAICT this test case is the first that combines the two.
The actual failure we're seeing is an assertion failure in self hosted code, specifically this one:
function AsyncFunctionNext(val) {
assert(
IsAsyncFunctionGeneratorObject(this),
"ThisArgument must be a generator object for async functions"
);
return resumeGenerator(this, val, "next");
}
The problem is this is actually: (JSObject &) @0x237b48287100 [object Function "AsyncFunctionNext"] for some reason.
So it appears that said this was provided by the debugger all the way up at js::DebuggerObject::CallData::callMethod -- it appears to be stack corruption of sorts. Probably a missed recursion check. Will have more update later.
Comment 4•4 months ago
|
||
Ok my initial analysis was wrong. I got distracted by the stack overflowing, but it turns out we need none of this to hit this assertion
// Create a global, and put an object in it. We'll use this to get a debugger object
// that's not an AsyncGeneratorObject.
var g = newGlobal({ newCompartment: true });
g.eval("var debugObject = {};");
var x = Debugger();
let gdo = x.addDebuggee(g);
let debugObject = gdo.getOwnPropertyDescriptor("debugObject").value;
assertEq(debugObject != undefined, true );
g.eval("async function h() { await 0; }");
g.h();
// This hook fires on AsyncGeneratorNext and provides debugger
// access to AsyncGeneratorNext. This asserts that it's
// this value is an AsyncGeneratorObject, but we call it
// explicitly with a different this value, which triggers the
// assertion.
x.onNativeCall = function (callee) {
callee.call(debugObject);
};
This is unfortunately yet another instance of too much power. Devtools uses (AFAICT) a single onNativeCall hook, which is used to implement the eager evaluation system. The callee is analyzed and allowed to continue execution, but never called directly. We shouldn't allow the callee parameter passed to the onNativeCall hook to be invoked else you can basically do all sorts of powerful silly invocations of self-hosted code.
Comment 5•4 months ago
|
||
This isn't security sensitive because this can't be accessed through product. The one use of this hook is already safe.
Comment 6•4 months ago
|
||
I'm tempted to re-invent EnterDebuggeeNoExecute for this, or perhaps tweak it. basically, when execuing the onNativeCall hook it feels like EnterDebuggeeNoExecute would be the right thing to stop further execution. -except- DebugObject::call explicitly calls LeaveDebuggeeNoExecute, so we'd need a way to make that not do-the-thing.
Updated•4 months ago
|
Updated•4 months ago
|
| Reporter | ||
Comment 7•4 months ago
|
||
Just curious, Matt, will you be taking this on anytime soon? (or at least a patch?)
Comment 8•4 months ago
|
||
Not too soon; maybe in week or two -- I'll set a reminder if I don't circle back manually.
Updated•3 months ago
|
Updated•2 months ago
|
Updated•1 month ago
|
Comment 10•14 days ago
|
||
Not a security bug per comment 5.
Description
•