diff options
author | Alon Zakai <azakai@google.com> | 2022-08-16 09:39:37 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-16 09:39:37 -0700 |
commit | 64629e9e73c40f0df240345c532163139ff1de68 (patch) | |
tree | f6f7e80451b7198ed0255273930f64bfe642a7b3 /src | |
parent | ffa40d7f408ed4d35c806f550b1d6bac2a039745 (diff) | |
download | binaryen-64629e9e73c40f0df240345c532163139ff1de68.tar.gz binaryen-64629e9e73c40f0df240345c532163139ff1de68.tar.bz2 binaryen-64629e9e73c40f0df240345c532163139ff1de68.zip |
Validator: Validate intrinsics (#4880)
call.without.effects has a specific form, where the last parameter is a
function reference, and that function reference must have the right type
for the other parameters if called with them:
(call $call.without.effects
(..i32..)
(..f64..)
(..function reference, which takes params i32 and f64..)
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm/wasm-validator.cpp | 63 |
1 files changed, 55 insertions, 8 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 572a3b4ba..8cf09e747 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -446,15 +446,20 @@ private: "return_call* requires tail calls to be enabled"); } + // |printable| is the expression to print in case of an error. That may differ + // from |curr| which we are validating. template<typename T> - void validateCallParamsAndResult(T* curr, HeapType sigType) { - if (!shouldBeTrue( - sigType.isSignature(), curr, "Heap type must be a signature type")) { + void validateCallParamsAndResult(T* curr, + HeapType sigType, + Expression* printable) { + if (!shouldBeTrue(sigType.isSignature(), + printable, + "Heap type must be a signature type")) { return; } auto sig = sigType.getSignature(); if (!shouldBeTrue(curr->operands.size() == sig.params.size(), - curr, + printable, "call* param number must match")) { return; } @@ -462,7 +467,7 @@ private: for (const auto& param : sig.params) { if (!shouldBeSubType(curr->operands[i]->type, param, - curr, + printable, "call param types must match") && !info.quiet) { getStream() << "(on argument " << i << ")\n"; @@ -472,22 +477,28 @@ private: if (curr->isReturn) { shouldBeEqual(curr->type, Type(Type::unreachable), - curr, + printable, "return_call* should have unreachable type"); shouldBeSubType( sig.results, getFunction()->getResults(), - curr, + printable, "return_call* callee return type must match caller return type"); } else { shouldBeEqualOrFirstIsUnreachable( curr->type, sig.results, - curr, + printable, "call* type must match callee return type"); } } + // In the common case, we use |curr| as |printable|. + template<typename T> + void validateCallParamsAndResult(T* curr, HeapType sigType) { + validateCallParamsAndResult(curr, sigType, curr); + } + Type indexType() { return getModule()->memory.indexType; } }; @@ -799,6 +810,42 @@ void FunctionValidator::visitCall(Call* curr) { return; } validateCallParamsAndResult(curr, target->type); + + if (Intrinsics(*getModule()).isCallWithoutEffects(curr)) { + // call.without.effects has the specific form of the last argument being a + // function reference, which will be called with all the previous arguments. + // The type must be consistent with that. This, for example, is not: + // + // (call $call.without.effects + // (i32.const 1) + // (.. some function reference that expects an f64 param and not i32 ..) + // ) + if (shouldBeTrue(!curr->operands.empty(), + curr, + "call.without.effects must have a target operand")) { + auto* target = curr->operands.back(); + // Validate only in the case that the target is a function. If it isn't, + // it might be unreachable (which is fine, and we can ignore this), or if + // the call.without.effects import doesn't have a function as the last + // parameter, then validateImports() will handle that later (and it's + // better to emit a single error there than one per callsite here). + if (target->type.isFunction()) { + // Copy the original call and remove the reference. It must then match + // the expected signature. + struct Copy { + std::vector<Expression*> operands; + bool isReturn; + Type type; + } copy; + for (Index i = 0; i < curr->operands.size() - 1; i++) { + copy.operands.push_back(curr->operands[i]); + } + copy.isReturn = curr->isReturn; + copy.type = curr->type; + validateCallParamsAndResult(©, target->type.getHeapType(), curr); + } + } + } } void FunctionValidator::visitCallIndirect(CallIndirect* curr) { |