forked from mirrors/gecko-dev
Bug 1851568 - Improve validation of tail call result types. r=bvisness
Differential Revision: https://phabricator.services.mozilla.com/D187501
This commit is contained in:
parent
e3cea5c34e
commit
fd29b97c09
9 changed files with 99 additions and 57 deletions
20
js/src/jit-test/tests/wasm/tail-calls/bug1851568.js
Normal file
20
js/src/jit-test/tests/wasm/tail-calls/bug1851568.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
wasmFailValidateText(`(module
|
||||
(func (result i32 f64)
|
||||
i32.const 1
|
||||
f64.const 2.0
|
||||
)
|
||||
(func (export "f") (result f64)
|
||||
return_call 0
|
||||
)
|
||||
)`, /type mismatch/);
|
||||
|
||||
wasmFailValidateText(`(module
|
||||
(func (result i32 f64)
|
||||
i32.const 1
|
||||
f64.const 2.0
|
||||
)
|
||||
(func (export "f") (result f32 i32 f64)
|
||||
f32.const 3.14
|
||||
return_call 0
|
||||
)
|
||||
)`, /type mismatch/);
|
||||
|
|
@ -168,3 +168,53 @@ let fns = i.exports;
|
|||
|
||||
assertEq(fns.churn(800), -575895114);
|
||||
assertEq(fns.churn(1200), -1164697516);
|
||||
|
||||
wasmValidateText(`(module
|
||||
(rec
|
||||
(type $s1 (sub (struct i32)))
|
||||
(type $s2 (sub $s1 (struct i32 f32)))
|
||||
)
|
||||
(func (result (ref $s2))
|
||||
struct.new_default $s2
|
||||
)
|
||||
(func (export "f") (result (ref $s1))
|
||||
return_call 0
|
||||
)
|
||||
)`);
|
||||
|
||||
wasmFailValidateText(`(module
|
||||
(rec
|
||||
(type $s1 (sub (struct i32)))
|
||||
(type $s2 (sub $s1 (struct i32 f32)))
|
||||
)
|
||||
(func (result (ref $s1))
|
||||
struct.new_default $s1
|
||||
)
|
||||
(func (export "f") (result (ref $s2))
|
||||
return_call 0
|
||||
)
|
||||
)`, /type mismatch/);
|
||||
|
||||
wasmValidateText(`(module
|
||||
(rec
|
||||
(type $s1 (sub (struct i32)))
|
||||
(type $s2 (sub $s1 (struct i32 f32)))
|
||||
)
|
||||
(type $t (func (result (ref $s2))))
|
||||
(func (export "f") (param (ref $t)) (result (ref $s1))
|
||||
local.get 0
|
||||
return_call_ref $t
|
||||
)
|
||||
)`);
|
||||
|
||||
wasmFailValidateText(`(module
|
||||
(rec
|
||||
(type $s1 (sub (struct i32)))
|
||||
(type $s2 (sub $s1 (struct i32 f32)))
|
||||
)
|
||||
(type $t (func (result (ref $s1))))
|
||||
(func (export "f") (param (ref $t)) (result (ref $s2))
|
||||
local.get 0
|
||||
return_call_ref $t
|
||||
)
|
||||
)`, /type mismatch/);
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ wasmFailValidateText(
|
|||
(table 0 anyfunc)
|
||||
(func $type-void-vs-num (result i32)
|
||||
(i32.eqz (return_call_indirect (type 0) (i32.const 0)))))`,
|
||||
/popping value from empty stack/);
|
||||
/type mismatch: expected 1 values, got 0 values/);
|
||||
|
||||
wasmFailValidateText(
|
||||
`(module
|
||||
|
|
@ -151,7 +151,7 @@ wasmFailValidateText(
|
|||
(table 0 anyfunc)
|
||||
(func $type-num-vs-num
|
||||
(i32.eqz (return_call_indirect (type 0) (i32.const 0)))))`,
|
||||
/unused values not explicitly dropped/);
|
||||
/type mismatch: expected 0 values, got 1 values/);
|
||||
|
||||
wasmFailValidateText(
|
||||
`(module
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ wasmFailValidateText(
|
|||
(func $type-void-vs-num (result i32)
|
||||
(return_call 1) (i32.const 0))
|
||||
(func))`,
|
||||
/popping value from empty stack/);
|
||||
/type mismatch: expected 1 values, got 0 values/);
|
||||
|
||||
wasmFailValidateText(
|
||||
`(module
|
||||
|
|
|
|||
|
|
@ -52,12 +52,13 @@ check_stub1: {
|
|||
var ins = wasmEvalText(`(module
|
||||
(import "" "fac-acc" (func $fac-acc (param i64 i64) (result i64)))
|
||||
(type $ty (func (param i64 i64) (result i64)))
|
||||
(type $tz (func (param i64) (result i64)))
|
||||
(table $t 1 1 funcref)
|
||||
(func $f (export "fac") (param i64) (result i64)
|
||||
local.get 0
|
||||
i64.const 1
|
||||
i32.const 0
|
||||
return_call_indirect $t
|
||||
return_call_indirect $t (type $tz)
|
||||
)
|
||||
(elem $t (i32.const 0) $fac-acc)
|
||||
|
||||
|
|
|
|||
|
|
@ -4817,8 +4817,7 @@ bool BaseCompiler::emitCall() {
|
|||
bool BaseCompiler::emitReturnCall() {
|
||||
uint32_t funcIndex;
|
||||
BaseNothingVector args_{};
|
||||
BaseNothingVector unused_values{};
|
||||
if (!iter_.readReturnCall(&funcIndex, &args_, &unused_values)) {
|
||||
if (!iter_.readReturnCall(&funcIndex, &args_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -4934,9 +4933,8 @@ bool BaseCompiler::emitReturnCallIndirect() {
|
|||
uint32_t tableIndex;
|
||||
Nothing callee_;
|
||||
BaseNothingVector args_{};
|
||||
BaseNothingVector unused_values{};
|
||||
if (!iter_.readReturnCallIndirect(&funcTypeIndex, &tableIndex, &callee_,
|
||||
&args_, &unused_values)) {
|
||||
&args_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -5042,9 +5040,7 @@ bool BaseCompiler::emitReturnCallRef() {
|
|||
const FuncType* funcType;
|
||||
Nothing unused_callee;
|
||||
BaseNothingVector unused_args{};
|
||||
BaseNothingVector unused_values{};
|
||||
if (!iter_.readReturnCallRef(&funcType, &unused_callee, &unused_args,
|
||||
&unused_values)) {
|
||||
if (!iter_.readReturnCallRef(&funcType, &unused_callee, &unused_args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5101,8 +5101,7 @@ static bool EmitReturnCall(FunctionCompiler& f) {
|
|||
|
||||
uint32_t funcIndex;
|
||||
DefVector args;
|
||||
DefVector unused_values;
|
||||
if (!f.iter().readReturnCall(&funcIndex, &args, &unused_values)) {
|
||||
if (!f.iter().readReturnCall(&funcIndex, &args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -5142,9 +5141,8 @@ static bool EmitReturnCallIndirect(FunctionCompiler& f) {
|
|||
uint32_t tableIndex;
|
||||
MDefinition* callee;
|
||||
DefVector args;
|
||||
DefVector unused_values;
|
||||
if (!f.iter().readReturnCallIndirect(&funcTypeIndex, &tableIndex, &callee,
|
||||
&args, &unused_values)) {
|
||||
&args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -5176,9 +5174,8 @@ static bool EmitReturnCallRef(FunctionCompiler& f) {
|
|||
const FuncType* funcType;
|
||||
MDefinition* callee;
|
||||
DefVector args;
|
||||
DefVector unused_values;
|
||||
|
||||
if (!f.iter().readReturnCallRef(&funcType, &callee, &args, &unused_values)) {
|
||||
if (!f.iter().readReturnCallRef(&funcType, &callee, &args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -690,12 +690,10 @@ class MOZ_STACK_CLASS OpIter : private Policy {
|
|||
ValueVector* argValues);
|
||||
#ifdef ENABLE_WASM_TAIL_CALLS
|
||||
[[nodiscard]] bool readReturnCall(uint32_t* funcTypeIndex,
|
||||
ValueVector* argValues,
|
||||
ValueVector* values);
|
||||
ValueVector* argValues);
|
||||
[[nodiscard]] bool readReturnCallIndirect(uint32_t* funcTypeIndex,
|
||||
uint32_t* tableIndex, Value* callee,
|
||||
ValueVector* argValues,
|
||||
ValueVector* values);
|
||||
ValueVector* argValues);
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
|
||||
[[nodiscard]] bool readCallRef(const FuncType** funcType, Value* callee,
|
||||
|
|
@ -703,8 +701,7 @@ class MOZ_STACK_CLASS OpIter : private Policy {
|
|||
|
||||
# ifdef ENABLE_WASM_TAIL_CALLS
|
||||
[[nodiscard]] bool readReturnCallRef(const FuncType** funcType, Value* callee,
|
||||
ValueVector* argValues,
|
||||
ValueVector* values);
|
||||
ValueVector* argValues);
|
||||
# endif
|
||||
#endif
|
||||
[[nodiscard]] bool readOldCallDirect(uint32_t numFuncImports,
|
||||
|
|
@ -2462,8 +2459,7 @@ inline bool OpIter<Policy>::readCall(uint32_t* funcTypeIndex,
|
|||
#ifdef ENABLE_WASM_TAIL_CALLS
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readReturnCall(uint32_t* funcTypeIndex,
|
||||
ValueVector* argValues,
|
||||
ValueVector* values) {
|
||||
ValueVector* argValues) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::ReturnCall);
|
||||
|
||||
if (!readVarU32(funcTypeIndex)) {
|
||||
|
|
@ -2480,15 +2476,11 @@ inline bool OpIter<Policy>::readReturnCall(uint32_t* funcTypeIndex,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!push(ResultType::Vector(funcType.results()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if callee results are subtypes of caller's.
|
||||
Control& body = controlStack_[0];
|
||||
MOZ_ASSERT(body.kind() == LabelKind::Body);
|
||||
|
||||
// Pop function results as the instruction will cause a return.
|
||||
if (!popWithType(body.resultType(), values)) {
|
||||
if (!checkIsSubtypeOf(ResultType::Vector(funcType.results()),
|
||||
body.resultType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2549,8 +2541,7 @@ template <typename Policy>
|
|||
inline bool OpIter<Policy>::readReturnCallIndirect(uint32_t* funcTypeIndex,
|
||||
uint32_t* tableIndex,
|
||||
Value* callee,
|
||||
ValueVector* argValues,
|
||||
ValueVector* values) {
|
||||
ValueVector* argValues) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::ReturnCallIndirect);
|
||||
MOZ_ASSERT(funcTypeIndex != tableIndex);
|
||||
|
||||
|
|
@ -2589,15 +2580,11 @@ inline bool OpIter<Policy>::readReturnCallIndirect(uint32_t* funcTypeIndex,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!push(ResultType::Vector(funcType.results()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if callee results are subtypes of caller's.
|
||||
Control& body = controlStack_[0];
|
||||
MOZ_ASSERT(body.kind() == LabelKind::Body);
|
||||
|
||||
// Pop function results as the instruction will cause a return.
|
||||
if (!popWithType(body.resultType(), values)) {
|
||||
if (!checkIsSubtypeOf(ResultType::Vector(funcType.results()),
|
||||
body.resultType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2636,8 +2623,7 @@ inline bool OpIter<Policy>::readCallRef(const FuncType** funcType,
|
|||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readReturnCallRef(const FuncType** funcType,
|
||||
Value* callee,
|
||||
ValueVector* argValues,
|
||||
ValueVector* values) {
|
||||
ValueVector* argValues) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::ReturnCallRef);
|
||||
|
||||
uint32_t funcTypeIndex;
|
||||
|
|
@ -2656,15 +2642,11 @@ inline bool OpIter<Policy>::readReturnCallRef(const FuncType** funcType,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!push(ResultType::Vector((*funcType)->results()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if callee results are subtypes of caller's.
|
||||
Control& body = controlStack_[0];
|
||||
MOZ_ASSERT(body.kind() == LabelKind::Body);
|
||||
|
||||
// Pop function results as the instruction will cause a return.
|
||||
if (!popWithType(body.resultType(), values)) {
|
||||
if (!checkIsSubtypeOf(ResultType::Vector((*funcType)->results()),
|
||||
body.resultType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -223,8 +223,7 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
|
|||
}
|
||||
uint32_t unusedIndex;
|
||||
NothingVector unusedArgs{};
|
||||
NothingVector unusedValues{};
|
||||
CHECK(iter.readReturnCall(&unusedIndex, &unusedArgs, &unusedValues));
|
||||
CHECK(iter.readReturnCall(&unusedIndex, &unusedArgs));
|
||||
}
|
||||
case uint16_t(Op::ReturnCallIndirect): {
|
||||
if (!env.tailCallsEnabled()) {
|
||||
|
|
@ -232,9 +231,8 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
|
|||
}
|
||||
uint32_t unusedIndex, unusedIndex2;
|
||||
NothingVector unusedArgs{};
|
||||
NothingVector unusedValues{};
|
||||
CHECK(iter.readReturnCallIndirect(&unusedIndex, &unusedIndex2, ¬hing,
|
||||
&unusedArgs, &unusedValues));
|
||||
&unusedArgs));
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
|
||||
|
|
@ -253,9 +251,7 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
|
|||
}
|
||||
const FuncType* unusedType;
|
||||
NothingVector unusedArgs{};
|
||||
NothingVector unusedValues{};
|
||||
CHECK(iter.readReturnCallRef(&unusedType, ¬hing, &unusedArgs,
|
||||
&unusedValues));
|
||||
CHECK(iter.readReturnCallRef(&unusedType, ¬hing, &unusedArgs));
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue