Firefox · SpiderMonkey
CVE-2026-16363
Logic Error in SpiderMonkey
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifjs/src/jit/CodeGenerator.cpp |
modified | |
ifjs/src/jit/MacroAssembler.cpp |
modified | |
switchjs/src/jit/MacroAssembler.cpp |
modified |
Files Changed
js/src/jit/CodeGenerator.cppjs/src/jit/MacroAssembler.cppjs/src/jit/MacroAssembler.hjs/src/wasm/WasmBCClass.hjs/src/wasm/WasmBaselineCompile.cpp
Patch
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index a46730a5f3d..e76e3d52f98 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -10410,11 +10410,13 @@ void CodeGenerator::visitWasmCall(LWasmCall* lir) {
reloadPinnedRegs = true;
switchRealm = false;
break;
- case wasm::CalleeDesc::BuiltinInstanceMethod:
- retOffset = masm.wasmCallBuiltinInstanceMethod(
- desc, callBase->instanceArg(), callee.builtin(),
- callBase->builtinMethodFailureMode(),
- callBase->builtinMethodFailureTrap());
+ case wasm::CalleeDesc::BuiltinInstanceMethod: {
+ CodeOffset unused_trapStackMapKey;
+ masm.wasmCallBuiltinInstanceMethod(desc, callBase->instanceArg(),
+ callee.builtin(),
+ callBase->builtinMethodFailureMode(),
+ callBase->builtinMethodFailureTrap(),
+ &retOffset, &unused_trapStackMapKey);
// The builtin ABI preserves the instance and pinned registers. However,
// builtins may grow the memory which requires us to reload the pinned
// registers.
@@ -10422,6 +10424,7 @@ void CodeGenerator::visitWasmCall(LWasmCall* lir) {
reloadPinnedRegs = true;
switchRealm = false;
break;
+ }
case wasm::CalleeDesc::FuncRef:
if (isReturnCall) {
ReturnCallAdjustmentInfo retCallInfo(
diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
index 11c67b355a1..09d2a24b2bd 100644
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -6613,10 +6613,11 @@ CodeOffset MacroAssembler::wasmReturnCall(
return offset;
}
-CodeOffset MacroAssembler::wasmCallBuiltinInstanceMethod(
+void MacroAssembler::wasmCallBuiltinInstanceMethod(
const wasm::CallSiteDesc& desc, const ABIArg& instanceArg,
wasm::SymbolicAddress builtin, wasm::FailureMode failureMode,
- wasm::Trap failureTrap) {
+ wasm::Trap failureTrap, CodeOffset* callStackMapKey,
+ CodeOffset* trapStackMapKey) {
MOZ_ASSERT(instanceArg != ABIArg());
MOZ_ASSERT_IF(!wasm::NeedsBuiltinThunk(builtin),
failureMode == wasm::FailureMode::Infallible ||
@@ -6643,7 +6644,7 @@ CodeOffset MacroAssembler::wasmCallBuiltinInstanceMethod(
}
#endif
- CodeOffset ret = call(desc, builtin);
+ *callStackMapKey = call(desc, builtin);
#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
if (checkUnsafeCallWithABI) {
@@ -6651,19 +6652,18 @@ CodeOffset MacroAssembler::wasmCallBuiltinInstanceMethod(
}
#endif
- wasmTrapOnFailedInstanceCall(ReturnReg, failureMode, failureTrap,
- desc.toTrapSiteDesc());
- return ret;
+ *trapStackMapKey = wasmTrapOnFailedInstanceCall(
+ ReturnReg, failureMode, failureTrap, desc.toTrapSiteDesc());
}
-void MacroAssembler::wasmTrapOnFailedInstanceCall(
+CodeOffset MacroAssembler::wasmTrapOnFailedInstanceCall(
Register resultRegister, wasm::FailureMode failureMode,
wasm::Trap failureTrap, const wasm::TrapSiteDesc& trapSiteDesc) {
Label noTrap;
switch (failureMode) {
case wasm::FailureMode::Infallible:
MOZ_ASSERT(failureTrap == wasm::Trap::Limit);
- return;
+ return CodeOffset();
case wasm::FailureMode::FailOnNegI32:
branchTest32(Assembler::NotSigned, resultRegister, resultRegister,
&noTrap);
@@ -6684,6 +6684,14 @@ void MacroAssembler::wasmTrapOnFailedInstanceCall(
}
wasmTrap(failureTrap, trapSiteDesc);
bind(&noTrap);
+
+ if (failureTrap != wasm::Trap::ThrowReported) {
+ return CodeOffset();
+ }
+
+ // For Trap::ThrowReported, the caller(s) may want to create a stackmap, so
+ // tell them what its key must be.
+ return CodeOffset(masm.currentOffset());
}
// In principle, call_indirect requires an expensive context switch to the
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
index 6920cafa0d1..ba70caf10a8 100644
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -3986,20 +3986,26 @@ class MacroAssembler : public MacroAssemblerSpecific {
// This function takes care of loading the pointer to the current instance
// as the implicit first argument. It preserves instance and pinned registers.
// (instance & pinned regs are non-volatile registers in the system ABI).
- CodeOffset wasmCallBuiltinInstanceMethod(const wasm::CallSiteDesc& desc,
- const ABIArg& instanceArg,
- wasm::SymbolicAddress builtin,
- wasm::FailureMode failureMode,
- wasm::Trap failureTrap);
+ // Offsets for stackmaps for the call and (if required) for the following
+ // failure trap, are returned.
+ void wasmCallBuiltinInstanceMethod(const wasm::CallSiteDesc& desc,
+ const ABIArg& instanceArg,
+ wasm::SymbolicAddress builtin,
+ wasm::FailureMode failureMode,
+ wasm::Trap failureTrap,
+ CodeOffset* callStackMapKey,
+ CodeOffset* trapStackMapKey);
// Performs the appropriate check based on the instance call's FailureMode,
// and traps if the check fails. The resultRegister should likely be
// ReturnReg, but this depends on whatever you do with registers immediately
- // after the call.
- void wasmTrapOnFailedInstanceCall(Register resultRegister,
- wasm::FailureMode failureMode,
- wasm::Trap failureTrap,
- const wasm::TrapSiteDesc& trapSiteDesc);
+ // after the call. In the case where a trap is generated, the returned
+ // CodeOffset points at the first byte of the instruction following the trap,
+ // and that is where a stackmap, if needed, should be keyed. If a trap is not
+ // generated, a CodeOffset satisfying !CodeOffset::bound() is returned.
+ CodeOffset wasmTrapOnFailedInstanceCall(
+ Register resultRegister, wasm::FailureMode failureMode,
+ wasm::Trap failureTrap, const wasm::TrapSiteDesc& trapSiteDesc);
// Performs a bounds check for ranged wasm operations like memory.fill or
// array.fill. This handles the bizarre edge case in the wasm spec where a
diff --git a/js/src/wasm/WasmBCClass.h b/js/src/wasm/WasmBCClass.h
index 4abcde369bb..3ff004c4655 100644
--- a/js/src/wasm/WasmBCClass.h
+++ b/js/src/wasm/WasmBCClass.h
@@ -1053,9 +1053,11 @@ struct BaseCompiler final {
void returnCallRef(const Stk& calleeRef, const FunctionCall& call,
const FuncType& funcType);
CodeOffset builtinCall(SymbolicAddress builtin, const FunctionCall& call);
- CodeOffset builtinInstanceMethodCall(const SymbolicAddressSignature& builtin,
- const ABIArg& instanceArg,
- const FunctionCall& call);
+ void builtinInstanceMethodCall(const SymbolicAddressSignature& builtin,
+ const ABIArg& instanceArg,
+ const FunctionCall& call,
+ CodeOffset* callStackMapKey,
+ CodeOffset* trapStackMapKey);
// Helpers to pick up the returned value from the return register.
inline RegI32 captureReturnedI32();
diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp
index c9dd7dac3c3..54d0a3c7fb6 100644
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -2254,17 +2254,18 @@ CodeOffset BaseCompiler::builtinCall(SymbolicAddress builtin,
return callSymbolic(builtin, call);
}
-CodeOffset BaseCompiler::builtinInstanceMethodCall(
+void BaseCompiler::builtinInstanceMethodCall(
const SymbolicAddressSignature& builtin, const ABIArg& instanceArg,
- const FunctionCall& call) {
+ const FunctionCall& call, CodeOffset* callStackMapKey,
+ CodeOffset* trapStackMapKey) {
#ifndef RABALDR_PIN_INSTANCE
// Builtin method calls assume the instance register has been set.
fr.loadInstancePtr(InstanceReg);
#endif
CallSiteDesc desc(bytecodeOffset(), CallSiteKind::Symbolic);
- return masm.wasmCallBuiltinInstanceMethod(desc, instanceArg, builtin.identity,
- builtin.failureMode,
- builtin.failureTrap);
+ masm.wasmCallBuiltinInstanceMethod(desc, instanceArg, builtin.identity,
+ builtin.failureMode, builtin.failureTrap,
+ callStackMapKey, trapStackMapKey);
}
//////////////////////////////////////////////////////////////////////////////
@@ -6553,12 +6554,18 @@ bool BaseCompiler::emitInstanceCall(const SymbolicAddressSignature& builtin) {
}
passArg(t, peek(numNonInstanceArgs - i), &baselineCall);
}
- CodeOffset raOffset =
- builtinInstanceMethodCall(builtin, instanceArg, baselineCall);
- if (!createStackMap("emitInstanceCall", raOffset)) {
+
+ CodeOffset callStackMapKey;
+ CodeOffset trapStackMapKey;
+ builtinInstanceMethodCall(builtin, instanceArg, baselineCall,
+ &callStackMapKey, &trapStackMapKey);
+ if (!createStackMap("emitInstanceCall-call", callStackMapKey)) {
+ return false;
+ }
Loading diff…
References
On This Page