Source code
Revision control
Copy as Markdown
Other Tools
// |jit-test| skip-if: !wasmDebuggingEnabled()
// Trigger crash via wasm trap with debug frames containing externref.
// The trap handling goes through signal handler -> HandleExceptionWasm.
// During exception unwinding, the DebugFrame's externref locals need
// to be properly handled. If getLocal reads a local after the frame
// has been partially unwound or the trap has corrupted frame state,
// we could get a use-after-free.
setJitCompilerOption("wasm.optimizing", 0);
var g = newGlobal({newCompartment: true});
var dbg = new Debugger(g);
g.evaluate(`
var bytes = wasmTextToBinary(
'(module ' +
' (type $S (struct (field i32)))' +
' (func (export "mkS") (result structref)' +
' struct.new_default $S' +
' )' +
' (func $zero (export "zero") (param structref)' +
' (unreachable)' +
' )' +
' (func $one (export "one") (param structref)' +
' (local.get 0) (call $zero)' +
' )' +
' (func $two (export "two") (param structref)' +
' (local.get 0) (call $one)' +
' )' +
' (func $three (export "three") (param structref)' +
' (local.get 0) (call $two)' +
' )' +
')'
);
var mod = new WebAssembly.Module(bytes);
var instance = new WebAssembly.Instance(mod, {});
var testTrap = instance.exports.three;
var mkS = instance.exports.mkS;
`);
dbg.onExceptionUnwind = function(frame, exc) {
if (frame.type !== "wasmcall") return;
// Force GC while accessing frame during unwind
gc();
// Try to access locals again after GC
try {
var env = frame.environment;
if (env) {
var names = env.names();
for (var n of names) {
var val = env.getVariable(n);
}
}
} catch(e) {}
};
// Test unreachable trap
try {
var obj1 = g.mkS();
g.testTrap(obj1);
} catch(e) {}