diff options
author | Alon Zakai <azakai@google.com> | 2024-09-30 12:35:09 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-30 12:35:09 -0700 |
commit | b5e995f774ebd72c8b6c100ee94b1e03c36d22cc (patch) | |
tree | a3d9a7ae7aeb24917dfb0ebeffa29d570b78e6ab | |
parent | 2da69a84b69a316409d5af65f66443a27422a353 (diff) | |
download | binaryen-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.cpp | 3 | ||||
-rw-r--r-- | test/lit/passes/precompute-ref-func.wast | 35 |
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) + ) + ) ) |