Closed Bug 1414852 Opened 2 years ago Closed 2 years ago

Assertion failure: code, at js/src/wasm/WasmFrameIter.cpp:590

Categories

(Core :: JavaScript Engine, defect, P1, critical)

ARM
Linux
defect

Tracking

()

RESOLVED FIXED
mozilla58
Tracking Status
firefox-esr52 --- unaffected
firefox56 --- unaffected
firefox57 --- unaffected
firefox58 --- fixed

People

(Reporter: decoder, Assigned: bbouvier)

References

Details

(4 keywords, Whiteboard: [jsbugmon:update,bisect])

Attachments

(1 file)

The following testcase crashes on mozilla-central revision 4e6df5159df3 (build with --enable-posix-nspr-emulation --enable-valgrind --enable-gczeal --disable-tests --enable-stdcxx-compat --disable-profiling --enable-debug --without-intl-api --enable-optimize --target=i686-pc-linux-gnu --enable-simulator=arm, run with --fuzzing-safe --cpu-count=2 --ion-eager --arm-asm-nop-fill=1):

const USE_ASM = '"use asm";';
function asmCompile() {
    var f = Function.apply(null, arguments);
    return f;
}
function asmLink(f) {
    var ret = f.apply(null, Array.slice(arguments, 1));
    return ret;
}
var ffi = function(enable) {
    enableGeckoProfiling();
    enableSingleStepProfiling();
}
var f = asmLink(asmCompile('global', 'ffis', 
  USE_ASM + `
    var ffi=ffis.ffi;
    function g(i) { 
      i=i|0;
      ffi(i|0);
    }
    function f(i) {
      i=i|0;
      g(i|0)
    } return f
  `), null, {
    ffi
});
f(0);
f(+1);


Backtrace:

received signal SIGSEGV, Segmentation fault.
0x08981396 in AssertMatchesCallSite (callerPC=0x1, callerFP=0x1448, activation=...) at js/src/wasm/WasmFrameIter.cpp:590
#0  0x08981396 in AssertMatchesCallSite (callerPC=0x1, callerFP=0x1448, activation=...) at js/src/wasm/WasmFrameIter.cpp:590
#1  0x0898183c in js::wasm::StartUnwinding (activation=..., registers=..., unwindState=0xffffb58c, unwoundCaller=0xffffb58b) at js/src/wasm/WasmFrameIter.cpp:817
#2  0x08981ad3 in js::wasm::ProfilingFrameIterator::ProfilingFrameIterator (this=0xffffb6ac, activation=..., state=...) at js/src/wasm/WasmFrameIter.cpp:864
#3  0x08845a19 in JS::ProfilingFrameIterator::iteratorConstruct (this=0xffffb69c, state=...) at js/src/vm/Stack.cpp:1925
#4  0x08846155 in JS::ProfilingFrameIterator::ProfilingFrameIterator (this=0xffffb69c, cx=0xf791d000, state=..., sampleBufferGen=4294967295) at js/src/vm/Stack.cpp:1858
#5  0x080a9269 in SingleStepCallback (arg=0xf791d000, sim=<optimized out>, pc=<optimized out>) at js/src/shell/js.cpp:5384
#6  0x0854937a in js::jit::Simulator::execute<false> (this=0xf7942000) at js/src/jit/arm/Simulator-arm.cpp:4851
#7  js::jit::Simulator::callInternal (this=0xf7942000, entry=0x5580d550 "\377\377\377\352\004\340-\345\377\377\377\352\360\037-\351\377\377\377\352\020\212-\355\377\377\377", <incomplete sequence \352>) at js/src/jit/arm/Simulator-arm.cpp:4940
#8  0x085496b1 in js::jit::Simulator::call (this=<optimized out>, entry=<optimized out>, argument_count=<optimized out>) at js/src/jit/arm/Simulator-arm.cpp:5023
#9  0x089af270 in js::wasm::Instance::callExport (this=0xf798e900, cx=0xf791d000, funcIndex=2, args=...) at js/src/wasm/WasmInstance.cpp:698
#10 0x089afefd in WasmCall (cx=0xf791d000, argc=1, vp=0xf61ffed0) at js/src/wasm/WasmJS.cpp:1156
#11 0x0818f829 in js::CallJSNative (cx=0xf791d000, native=0x89afe40 <WasmCall(JSContext*, unsigned int, JS::Value*)>, args=...) at js/src/jscntxtinlines.h:291
[...]
#33 main (argc=6, argv=0xffffcdb4, envp=0xffffcdd0) at js/src/shell/js.cpp:8962
eax	0x0	0
ebx	0x1	1
ecx	0xf7da4864	-136689564
edx	0x0	0
esi	0x8d79ff4	148348916
edi	0x49c	1180
ebp	0xffffb518	4294948120
esp	0xffffb4f0	4294948080
eip	0x8981396 <AssertMatchesCallSite(void*, js::wasm::Frame*, js::jit::JitActivation const&)+166>
=> 0x8981396 <AssertMatchesCallSite(void*, js::wasm::Frame*, js::jit::JitActivation const&)+166>:	movl   $0x0,0x0
   0x89813a0 <AssertMatchesCallSite(void*, js::wasm::Frame*, js::jit::JitActivation const&)+176>:	ud2
Flags: needinfo?(bbouvier)
Blocks: 1360211
Flags: needinfo?(bbouvier)
Quick explanation for the patch: because of nop fill, the distance [begin, start of untrusted zone] was bigger than u8's range, under-flowing it. The CodeRange's union has to be bigger than u32 anyway, so we can safely use u16 without regressing perf of CodeRange.
Assignee: nobody → bbouvier
Status: NEW → ASSIGNED
Priority: -- → P1
When we've encountered this problem in the prologue/epilogue and, in those cases, we've used AutoForbidPools scoped to the region of instructions in which we can't insert nops or pools.  Could we do that here instead?  One nice thing about this is that it doesn't raise the question: "could a large pool somehow end up even overflowing a u16?".
In this case, it'd mean all the instructions from the start of GenerateImportJitExit up to the untrusted fp range start. I'm worried the number of instructions would be variable on parameters and hard to predetermine (depending on number of args, etc.).
Oh, of course.  I was thinking that the *span* of instructions was finite, but of course what matters here is the *offset* from the prologue.
Comment on attachment 8926811 [details]
Bug 1414852: Don't overflow offset from begin to untrusted wasm jit exit range;

https://reviewboard.mozilla.org/r/198062/#review203404
Attachment #8926811 - Flags: review?(luke) → review+
Pushed by bbouvier@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/c6dc3b5ff989
Don't overflow offset from begin to untrusted wasm jit exit range; r=luke
https://hg.mozilla.org/mozilla-central/rev/c6dc3b5ff989
Status: ASSIGNED → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla58
You need to log in before you can comment on or make changes to this bug.