summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-04-22 10:56:40 -0700
committerGitHub <noreply@github.com>2022-04-22 10:56:40 -0700
commite16f1e7f250a832742397a1f082c9ea161619ca8 (patch)
treece433a68075350520dae08c2ff77565b3c38d530
parent2ab19d9ac528ff11fa14b184a84c92e72d5b0163 (diff)
downloadbinaryen-e16f1e7f250a832742397a1f082c9ea161619ca8.tar.gz
binaryen-e16f1e7f250a832742397a1f082c9ea161619ca8.tar.bz2
binaryen-e16f1e7f250a832742397a1f082c9ea161619ca8.zip
[NominalFuzzing] SignatureRefining: Ignore exported functions (#4601)
This hits the fuzzer when it tries to call reference exports with a null.
-rw-r--r--src/ir/export-utils.h36
-rw-r--r--src/passes/SignatureRefining.cpp25
-rw-r--r--test/lit/passes/signature-refining.wast31
3 files changed, 91 insertions, 1 deletions
diff --git a/src/ir/export-utils.h b/src/ir/export-utils.h
new file mode 100644
index 000000000..245365fbc
--- /dev/null
+++ b/src/ir/export-utils.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_ir_export_h
+#define wasm_ir_export_h
+
+#include "wasm.h"
+
+namespace wasm::ExportUtils {
+
+inline std::vector<Function*> getExportedFunctions(Module& wasm) {
+ std::vector<Function*> ret;
+ for (auto& ex : wasm.exports) {
+ if (ex->kind == ExternalKind::Function) {
+ ret.push_back(wasm.getFunction(ex->value));
+ }
+ }
+ return ret;
+}
+
+} // namespace wasm::ExportUtils
+
+#endif // wasm_ir_export_h
diff --git a/src/passes/SignatureRefining.cpp b/src/passes/SignatureRefining.cpp
index 37ca091df..d094382c7 100644
--- a/src/passes/SignatureRefining.cpp
+++ b/src/passes/SignatureRefining.cpp
@@ -26,6 +26,7 @@
// type, and all call_refs using it).
//
+#include "ir/export-utils.h"
#include "ir/find_all.h"
#include "ir/lubs.h"
#include "ir/module-utils.h"
@@ -69,6 +70,10 @@ struct SignatureRefining : public Pass {
// A possibly improved LUB for the results.
LUBFinder resultsLUB;
+
+ // Normally we can optimize, but some cases prevent a particular signature
+ // type from being changed at all, see below.
+ bool canModify = true;
};
ModuleUtils::ParallelFunctionAnalysis<Info> analysis(
@@ -106,6 +111,20 @@ struct SignatureRefining : public Pass {
allInfo[func->type].resultsLUB.combine(info.resultsLUB);
}
+ // We cannot alter the signature of an exported function, as the outside may
+ // notice us doing so. For example, if we turn a parameter from nullable
+ // into non-nullable then callers sending a null will break. Put another
+ // way, we need to see all callers to refine types, and for exports we
+ // cannot do so.
+ // TODO If a function type is passed we should also mark the types used
+ // there, etc., recursively. For now this code just handles the top-
+ // level type, which is enough to keep the fuzzer from erroring. More
+ // generally, we need to decide about adding a "closed-world" flag of
+ // some kind.
+ for (auto* exportedFunc : ExportUtils::getExportedFunctions(*module)) {
+ allInfo[exportedFunc->type].canModify = false;
+ }
+
bool refinedResults = false;
// Compute optimal LUBs.
@@ -116,6 +135,11 @@ struct SignatureRefining : public Pass {
continue;
}
+ auto& info = allInfo[type];
+ if (!info.canModify) {
+ continue;
+ }
+
auto sig = type.getSignature();
auto numParams = sig.params.size();
@@ -127,7 +151,6 @@ struct SignatureRefining : public Pass {
}
};
- auto& info = allInfo[type];
for (auto* call : info.calls) {
updateLUBs(call->operands);
}
diff --git a/test/lit/passes/signature-refining.wast b/test/lit/passes/signature-refining.wast
index fcffcc550..a6d4ba53f 100644
--- a/test/lit/passes/signature-refining.wast
+++ b/test/lit/passes/signature-refining.wast
@@ -624,3 +624,34 @@
(unreachable)
)
)
+
+;; Exports prevent optimization, so $func's type will not change here.
+(module
+ ;; CHECK: (type $sig (func_subtype (param anyref) func))
+
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
+ ;; CHECK: (type $struct (struct_subtype data))
+ (type $struct (struct_subtype data))
+
+ (type $sig (func_subtype (param anyref) func))
+
+ ;; CHECK: (export "prevent-opts" (func $func))
+
+ ;; CHECK: (func $func (type $sig) (param $x anyref)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $func (export "prevent-opts") (type $sig) (param $x anyref)
+ )
+
+ ;; CHECK: (func $caller (type $none_=>_none)
+ ;; CHECK-NEXT: (call $func
+ ;; CHECK-NEXT: (struct.new_default $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $caller
+ (call $func
+ (struct.new $struct)
+ )
+ )
+)