Repository: bytecodealliance/wasm-tools
Pull request #2147 (2025-04-15 21:41:02)

cli: for subcommands other than `parse`, don't guarantee successful parse
Response to https://github.com/bytecodealliance/wasm-tools/pull/2134#discussion_r2039710418

This PR goes back to the original behavior for most subcommands (other than `parse`): the module is not explicitly parsed before the relevant action (e.g. print, dump) is taken.


Patch:
diff --git a/src/bin/wasm-tools/addr2line.rs b/src/bin/wasm-tools/addr2line.rs
index 989929da..9efacce4 100644
--- a/src/bin/wasm-tools/addr2line.rs
+++ b/src/bin/wasm-tools/addr2line.rs
@@ -44,7 +44,7 @@ impl Opts {
     }
 
     pub fn run(&self) -> Result<()> {
-        let wasm = self.io.parse_input_wasm()?;
+        let wasm = self.io.get_input_wasm()?;
 
         let mut modules = Addr2lineModules::parse(&wasm)
             .context("failed to parse input and read custom sections")?;
diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs
index 15e8edae..2d2e4375 100644
--- a/src/bin/wasm-tools/component.rs
+++ b/src/bin/wasm-tools/component.rs
@@ -169,7 +169,7 @@ impl NewOpts {
 
     /// Executes the application.
     fn run(self) -> Result<()> {
-        let wasm = self.io.parse_input_wasm()?;
+        let wasm = self.io.get_input_wasm()?;
         let mut encoder = ComponentEncoder::default()
             .validate(!self.skip_validation)
             .reject_legacy_names(self.reject_legacy_names);
@@ -389,7 +389,7 @@ impl EmbedOpts {
                 },
             )
         } else {
-            self.io.parse_input_wasm()?
+            self.io.get_input_wasm()?
         };
 
         embed_component_metadata(
@@ -1046,7 +1046,7 @@ impl UnbundleOpts {
     }
 
     fn run(self) -> Result<()> {
-        let input = self.io.parse_input_wasm()?;
+        let input = self.io.get_input_wasm()?;
         if !wasmparser::Parser::is_component(&input) {
             return self.io.output_wasm(&input, self.wat);
         }
diff --git a/src/bin/wasm-tools/demangle.rs b/src/bin/wasm-tools/demangle.rs
index 1513a5db..65a649fa 100644
--- a/src/bin/wasm-tools/demangle.rs
+++ b/src/bin/wasm-tools/demangle.rs
@@ -24,7 +24,7 @@ impl Opts {
     }
 
     pub fn run(&self) -> Result<()> {
-        let input = self.io.parse_input_wasm()?;
+        let input = self.io.get_input_wasm()?;
         let mut module = wasm_encoder::Module::new();
 
         for payload in Parser::new(0).parse_all(&input) {
diff --git a/src/bin/wasm-tools/dump.rs b/src/bin/wasm-tools/dump.rs
index 525e08aa..cec6f9ed 100644
--- a/src/bin/wasm-tools/dump.rs
+++ b/src/bin/wasm-tools/dump.rs
@@ -20,7 +20,7 @@ impl Opts {
     }
 
     pub fn run(&self) -> Result<()> {
-        let input = self.io.parse_input_wasm()?;
+        let input = self.io.get_input_wasm()?;
         let output = self.io.output_writer()?;
         let mut d = Dump::new(&input, output);
         d.run()?;
diff --git a/src/bin/wasm-tools/metadata.rs b/src/bin/wasm-tools/metadata.rs
index a1197b34..852f43cc 100644
--- a/src/bin/wasm-tools/metadata.rs
+++ b/src/bin/wasm-tools/metadata.rs
@@ -48,7 +48,7 @@ impl ShowOpts {
     }
 
     pub fn run(&self) -> Result<()> {
-        let input = self.io.parse_input_wasm()?;
+        let input = self.io.get_input_wasm()?;
         let mut output = self.io.output_writer()?;
 
         let payload = wasm_metadata::Payload::from_binary(&input)?;
@@ -82,7 +82,7 @@ impl AddOpts {
     }
 
     pub fn run(&self) -> Result<()> {
-        let input = self.io.parse_input_wasm()?;
+        let input = self.io.get_input_wasm()?;
 
         let output = self.add_metadata.to_wasm(&input)?;
 
diff --git a/src/bin/wasm-tools/mutate.rs b/src/bin/wasm-tools/mutate.rs
index 9eae6da8..5072ec4d 100644
--- a/src/bin/wasm-tools/mutate.rs
+++ b/src/bin/wasm-tools/mutate.rs
@@ -54,7 +54,7 @@ impl Opts {
     }
 
     pub fn run(mut self) -> Result<()> {
-        let input_wasm = self.io.parse_input_wasm()?;
+        let input_wasm = self.io.get_input_wasm()?;
 
         // Currently `self.wasm_mutate` is typed as `'static` for the input wasm
         // due to how this subcommand is defined. To get the input wasm to live
diff --git a/src/bin/wasm-tools/objdump.rs b/src/bin/wasm-tools/objdump.rs
index db4c8f1a..33442f9f 100644
--- a/src/bin/wasm-tools/objdump.rs
+++ b/src/bin/wasm-tools/objdump.rs
@@ -20,7 +20,7 @@ impl Opts {
     }
 
     pub fn run(&self) -> Result<()> {
-        let input = self.io.parse_input_wasm()?;
+        let input = self.io.get_input_wasm()?;
 
         let mut printer = Printer {
             indices: Vec::new(),
diff --git a/src/bin/wasm-tools/print.rs b/src/bin/wasm-tools/print.rs
index a88e2de9..cdb2dd81 100644
--- a/src/bin/wasm-tools/print.rs
+++ b/src/bin/wasm-tools/print.rs
@@ -45,7 +45,7 @@ impl Opts {
     }
 
     pub fn run(&self) -> Result<()> {
-        let wasm = self.io.parse_input_wasm()?;
+        let wasm = self.io.get_input_wasm()?;
 
         let mut config = wasmprinter::Config::new();
         config.print_offsets(self.print_offsets);
diff --git a/src/bin/wasm-tools/shrink.rs b/src/bin/wasm-tools/shrink.rs
index c70f550d..844b4c5c 100644
--- a/src/bin/wasm-tools/shrink.rs
+++ b/src/bin/wasm-tools/shrink.rs
@@ -41,7 +41,7 @@ impl Opts {
     }
 
     pub fn run(self) -> Result<()> {
-        let input = self.io.parse_input_wasm()?;
+        let input = self.io.get_input_wasm()?;
         let initial_size = input.len();
 
         // Prerequisites for the predicate.
diff --git a/src/bin/wasm-tools/strip.rs b/src/bin/wasm-tools/strip.rs
index 53884612..44aa5708 100644
--- a/src/bin/wasm-tools/strip.rs
+++ b/src/bin/wasm-tools/strip.rs
@@ -32,7 +32,7 @@ impl Opts {
     }
 
     pub fn run(&self) -> Result<()> {
-        let input = self.io.parse_input_wasm()?;
+        let input = self.io.get_input_wasm()?;
         let to_delete = regex::RegexSet::new(self.delete.iter())?;
 
         let strip_custom_section = |name: &str| {


Test patch:
diff --git a/tests/cli/dangling_if.wat.stdout b/tests/cli/dangling_if.wat.stdout
new file mode 100644
index 00000000..45f65ca9
--- /dev/null
+++ b/tests/cli/dangling_if.wat.stdout
@@ -0,0 +1,4 @@
+(module
+  (type (;0;) (func))
+  (func (;0;) (type 0)
+    if ;; label = @1
diff --git a/tests/cli/dump/select.wat b/tests/cli/dump/select.wat
index 0ee91710..c72d8625 100644
--- a/tests/cli/dump/select.wat
+++ b/tests/cli/dump/select.wat
@@ -1,6 +1,4 @@
-;; FAIL: dump %
-;; This fails because wasmprinter can't (yet) print an invalid multi-value select.
-;; Can be changed back to a "RUN" test once that code lands.
+;; RUN: dump %
 
 (module
     (func
diff --git a/tests/cli/dump/select.wat.stderr b/tests/cli/dump/select.wat.stderr
deleted file mode 100644
index f86ca350..00000000
--- a/tests/cli/dump/select.wat.stderr
+++ /dev/null
@@ -1,1 +0,0 @@
-error: invalid result arity (at offset 0x18)
diff --git a/tests/cli/dump/select.wat.stdout b/tests/cli/dump/select.wat.stdout
new file mode 100644
index 00000000..be65160b
--- /dev/null
+++ b/tests/cli/dump/select.wat.stdout
@@ -0,0 +1,21 @@
+  0x0 | 00 61 73 6d | version 1 (Module)
+      | 01 00 00 00
+  0x8 | 01 04       | type section
+  0xa | 01          | 1 count
+--- rec group 0 (implicit) ---
+  0xb | 60 00 00    | [type 0] SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: Func(FuncType { params: [], results: [] }), shared: false } }
+  0xe | 03 02       | func section
+ 0x10 | 01          | 1 count
+ 0x11 | 00          | [func 0] type 0
+ 0x12 | 0a 0e       | code section
+ 0x14 | 01          | 1 count
+============== func 0 ====================
+ 0x15 | 0c          | size of function
+ 0x16 | 00          | 0 local blocks
+ 0x17 | 1b          | select
+ 0x18 | 1c 00       | ??
+ 0x1a | 1c 01 7f    | typed_select ty:I32
+ 0x1d | 1c 02       | ??
+ 0x1f | 7f          | i64_div_s
+ 0x20 | 7f          | i64_div_s
+ 0x21 | 0b          | end
diff --git a/tests/cli/print-code-section-overflow.wat.stdout b/tests/cli/print-code-section-overflow.wat.stdout
new file mode 100644
index 00000000..b55cecc0
--- /dev/null
+++ b/tests/cli/print-code-section-overflow.wat.stdout
@@ -0,0 +1,1 @@
+(module
diff --git a/tests/cli/print-dont-reserve-the-world.wat.stderr b/tests/cli/print-dont-reserve-the-world.wat.stderr
index 19f2dec5..bab93a74 100644
--- a/tests/cli/print-dont-reserve-the-world.wat.stderr
+++ b/tests/cli/print-dont-reserve-the-world.wat.stderr
@@ -1,1 +1,1 @@
-error: unexpected end-of-file (at offset 0xf)
+error: function section has non-zero count but code section is absent (at offset 0xf)
diff --git a/tests/cli/print-dont-reserve-the-world.wat.stdout b/tests/cli/print-dont-reserve-the-world.wat.stdout
new file mode 100644
index 00000000..b55cecc0
--- /dev/null
+++ b/tests/cli/print-dont-reserve-the-world.wat.stdout
@@ -0,0 +1,1 @@
+(module
diff --git a/tests/cli/print-locals-overflow.wat.stderr b/tests/cli/print-locals-overflow.wat.stderr
index 990d4303..42167d7e 100644
--- a/tests/cli/print-locals-overflow.wat.stderr
+++ b/tests/cli/print-locals-overflow.wat.stderr
@@ -1,1 +1,1 @@
-error: control frames remain at end of function body or expression (at offset 0x1d)
+error: function exceeds the maximum number of locals that can be printed
diff --git a/tests/cli/print-locals-overflow.wat.stdout b/tests/cli/print-locals-overflow.wat.stdout
new file mode 100644
index 00000000..5af803de
--- /dev/null
+++ b/tests/cli/print-locals-overflow.wat.stdout
@@ -0,0 +1,3 @@
+(module
+  (type (;0;) (func))
+  (func (;0;) (type 0)
diff --git a/tests/cli/print-no-panic-dangling-else.wat.stdout b/tests/cli/print-no-panic-dangling-else.wat.stdout
new file mode 100644
index 00000000..5af803de
--- /dev/null
+++ b/tests/cli/print-no-panic-dangling-else.wat.stdout
@@ -0,0 +1,3 @@
+(module
+  (type (;0;) (func))
+  (func (;0;) (type 0)
diff --git a/tests/cli/print-no-panic-double-end.wat.stdout b/tests/cli/print-no-panic-double-end.wat.stdout
new file mode 100644
index 00000000..cac212e7
--- /dev/null
+++ b/tests/cli/print-no-panic-double-end.wat.stdout
@@ -0,0 +1,4 @@
+(module
+  (type (;0;) (func))
+  (func (;0;) (type 0)
+    end
diff --git a/tests/cli/print-with-too-many-ends.wat.stdout b/tests/cli/print-with-too-many-ends.wat.stdout
new file mode 100644
index 00000000..cac212e7
--- /dev/null
+++ b/tests/cli/print-with-too-many-ends.wat.stdout
@@ -0,0 +1,4 @@
+(module
+  (type (;0;) (func))
+  (func (;0;) (type 0)
+    end