summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-09-30 12:35:09 -0700
committerGitHub <noreply@github.com>2024-09-30 12:35:09 -0700
commitb5e995f774ebd72c8b6c100ee94b1e03c36d22cc (patch)
treea3d9a7ae7aeb24917dfb0ebeffa29d570b78e6ab
parent2da69a84b69a316409d5af65f66443a27422a353 (diff)
downloadbinaryen-b5e995f774ebd72c8b6c100ee94b1e03c36d22cc.tar.gz
binaryen-b5e995f774ebd72c8b6c100ee94b1e03c36d22cc.tar.bz2
binaryen-b5e995f774ebd72c8b6c100ee94b1e03c36d22cc.zip
Fix the type of reused RefFunc in Precompute (#6976)
When we precompute something, we try to avoid allocating a new copy. That's important to avoid many allocations each time we run Precompute - otherwise, each time we see a br we'd allocate a fresh one, and for its values. But we had a bug where we reused a RefFunc as the value of a br without updating the type. It's actually tricky to reach a situation where we find a RefFunc to reuse and it is different from the actual one we want, but the fuzzer found one. Fixes the fuzz bug reported on #6845 (but unrelated to that PR).
-rw-r--r--src/passes/Precompute.cpp3
-rw-r--r--test/lit/passes/precompute-ref-func.wast35
2 files changed, 34 insertions, 4 deletions
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp
index 709fd7d3d..0fc0753ae 100644
--- a/src/passes/Precompute.cpp
+++ b/src/passes/Precompute.cpp
@@ -298,7 +298,8 @@ struct Precompute
singleValue.type.getHeapType().isSignature()) {
if (auto* r = curr->value->template dynCast<RefFunc>()) {
r->func = singleValue.getFunc();
- r->finalize();
+ auto heapType = getModule()->getFunction(r->func)->type;
+ r->finalize(Type(heapType, NonNullable));
curr->finalize();
return;
}
diff --git a/test/lit/passes/precompute-ref-func.wast b/test/lit/passes/precompute-ref-func.wast
index df4415c7b..495563271 100644
--- a/test/lit/passes/precompute-ref-func.wast
+++ b/test/lit/passes/precompute-ref-func.wast
@@ -2,18 +2,23 @@
;; RUN: wasm-opt %s -all --precompute -S -o - | filecheck %s
(module
- ;; CHECK: (type $0 (func (result funcref)))
;; CHECK: (type $shared-func (shared (func (result (ref null (shared func))))))
(type $shared-func (shared (func (result (ref null (shared func))))))
+
+ ;; CHECK: (type $func (func (result funcref)))
+ (type $func (func (result funcref)))
+
+ ;; CHECK: (type $2 (func (result (ref $shared-func))))
+
;; CHECK: (elem declare func $test $test-shared)
- ;; CHECK: (func $test (type $0) (result funcref)
+ ;; CHECK: (func $test (type $func) (result funcref)
;; CHECK-NEXT: (return
;; CHECK-NEXT: (ref.func $test)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $test (result funcref)
+ (func $test (type $func) (result funcref)
(block
(return
(ref.func $test)
@@ -33,4 +38,28 @@
)
)
)
+
+ ;; CHECK: (func $precompute-nested-brs (type $2) (result (ref $shared-func))
+ ;; CHECK-NEXT: (ref.func $test-shared)
+ ;; CHECK-NEXT: )
+ (func $precompute-nested-brs (result (ref $shared-func))
+ ;; We have two nested brs here, and we can precompute it all. While doing so
+ ;; we must not get confused between the targets and values: one sends a
+ ;; shared func, the other a normal func, so the types are different, and any
+ ;; mistake there will fail validation (say, if we reused the ref.func from
+ ;; the inner br when generating the outer one).
+ (block $shared (result (ref $shared-func))
+ (drop
+ (block $func (result (ref $func))
+ (br_if $func
+ (ref.func $test)
+ (br $shared
+ (ref.func $test-shared)
+ )
+ )
+ )
+ )
+ (ref.func $test-shared)
+ )
+ )
)