Skip to content

Pop in catch emitted inside a block ("not enough arguments on the stack" from VM) #4237

Closed
@kripken

Description

@kripken
(module
 (tag $tag (param i32))

 (func $foo
  (local $temp i32)
  (try
   (do
    (nop)
   )
   (catch $tag
    (call $call
     (block (result i32)
      (local.set $temp
       (pop i32)
      )
      (call $nop)
      (local.get $temp)
     )
    )
   )
  )
 )

 (func $call (param i32))
 (func $nop)
)

In this IR the pop exists in a place that Binaryen accepts but wasm does not: we use a pop to get the catch value, but we are inside a block so the wasm does not validate, and a VM will error on something like this:

CompileError: WebAssembly.instantiate(): Compiling function #0 failed: not enough arguments on the stack for local.set (need 1, got 0) @+43)

That is with just translating that wat into a binary, bin/wasm-opt a.wat -all -o a.out.wasm. However, if we add a --roundtrip in that command, then the IR becomes this:

   (catch $tag$0
    (local.set $temp
     (pop i32)
    )
    (call $call
     (block $label$3 (result i32)
      (call $nop)
      (local.get $temp)
     )
    )
   )

Note how the pop was moved into a proper position. So it seems like we have some logic in the binary reading code that handles this somehow, and so using --roundtrip is a workaround, at least, so this is probably not urgent.

I noticed this in wasm GC that had this:

   (catch $tag$0
    (throw $tag$0
     (ref.cast
      (pop (ref null $type$16))
      (global.get $global$1)
     )
    )
   )

That cast can be statically removed, leading to:

   (catch $tag$0
    (throw $tag$0
     (block (result (ref null $type$16))
      (local.set $4
       (pop (ref null $type$16))
      )
      (drop
       (global.get $global$1)
      )
      (local.get $4)
     )
    )
   )

And that is how the problem can occur.

This does not seem specific to wasm GC, but perhaps we have more peephole opts that end up emitting small blocks, which increase the risk.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions