From c1309aad2272f8e35f6d7efe4fec101631aae19b Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 16 Sep 2026 13:37:22 -0700 Subject: [PATCH] [GUFA] Fix crash on switch handlers Switch handlers on `resume` and `resume_throw` instructions do not have associated labels. GUFA previously assumed that all handlers would have labels, and would crash after trying to look up the target of an empty name. Fix the bug by explicitly checking for the presence of a label on the handlers. --- src/ir/possible-contents.cpp | 6 +++- test/lit/passes/gufa-cont.wast | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index c61163cdc33..549ec7169ef 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -1411,8 +1411,12 @@ struct InfoCollector // continuation values. auto numTags = curr->handlerTags.size(); for (Index tagIndex = 0; tagIndex < numTags; tagIndex++) { - auto tag = curr->handlerTags[tagIndex]; auto target = curr->handlerBlocks[tagIndex]; + if (!target) { + // A switch handler does not branch to a target block. + continue; + } + auto tag = curr->handlerTags[tagIndex]; auto params = getModule()->getTag(tag)->params(); // Add the values from the tag. diff --git a/test/lit/passes/gufa-cont.wast b/test/lit/passes/gufa-cont.wast index d35e77a60ef..a4d5b6c4a3a 100644 --- a/test/lit/passes/gufa-cont.wast +++ b/test/lit/passes/gufa-cont.wast @@ -44,6 +44,10 @@ ;; CHECK: (export "resume-i32" (func $resume-i32)) + ;; CHECK: (export "resume-switch" (func $resume-switch)) + + ;; CHECK: (export "resume_throw-switch" (func $resume_throw-switch)) + ;; CHECK: (func $cont (type $func) ;; CHECK-NEXT: (suspend $tag) ;; CHECK-NEXT: ) @@ -53,6 +57,10 @@ ;; OPEN_WORLD: (export "resume-i32" (func $resume-i32)) + ;; OPEN_WORLD: (export "resume-switch" (func $resume-switch)) + + ;; OPEN_WORLD: (export "resume_throw-switch" (func $resume_throw-switch)) + ;; OPEN_WORLD: (func $cont (type $func) ;; OPEN_WORLD-NEXT: (suspend $tag) ;; OPEN_WORLD-NEXT: ) @@ -195,6 +203,58 @@ ) ) ) + + ;; CHECK: (func $resume-switch (type $func) + ;; CHECK-NEXT: (resume $cont (on $tag switch) + ;; CHECK-NEXT: (cont.new $cont + ;; CHECK-NEXT: (ref.func $cont) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; OPEN_WORLD: (func $resume-switch (type $func) + ;; OPEN_WORLD-NEXT: (resume $cont (on $tag switch) + ;; OPEN_WORLD-NEXT: (cont.new $cont + ;; OPEN_WORLD-NEXT: (ref.func $cont) + ;; OPEN_WORLD-NEXT: ) + ;; OPEN_WORLD-NEXT: ) + ;; OPEN_WORLD-NEXT: ) + (func $resume-switch (export "resume-switch") + ;; Switch handlers do not branch to a target block. Ensure GUFA does not + ;; attempt to look up a target block name (which would incorrectly find an + ;; unnamed block in scope or null) and crash. + (block + (resume $cont (on $tag switch) + (cont.new $cont + (ref.func $cont) + ) + ) + ) + ) + + ;; CHECK: (func $resume_throw-switch (type $func) + ;; CHECK-NEXT: (resume_throw $cont $tag (on $tag switch) + ;; CHECK-NEXT: (cont.new $cont + ;; CHECK-NEXT: (ref.func $cont) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; OPEN_WORLD: (func $resume_throw-switch (type $func) + ;; OPEN_WORLD-NEXT: (resume_throw $cont $tag (on $tag switch) + ;; OPEN_WORLD-NEXT: (cont.new $cont + ;; OPEN_WORLD-NEXT: (ref.func $cont) + ;; OPEN_WORLD-NEXT: ) + ;; OPEN_WORLD-NEXT: ) + ;; OPEN_WORLD-NEXT: ) + (func $resume_throw-switch (export "resume_throw-switch") + ;; As above, but with resume_throw. + (block + (resume_throw $cont $tag (on $tag switch) + (cont.new $cont + (ref.func $cont) + ) + ) + ) + ) ) (module