Skip to content

catch_unwind doesn't catch non-C++ exceptions on wasm #148273

@bjorn3

Description

@bjorn3

I tried this code:

#[unsafe(no_mangle)]
pub fn square(num: i32) -> std::thread::Result<i32> {
    std::panic::catch_unwind(|| bar())
}

unsafe extern "C-unwind" {
    safe fn bar() -> i32;
}

compiled with -Cpanic=unwind --crate-type cdylib --target wasm32-wasip1 + -Zbuild-std.

I expected to see this happen: An exception originating from bar which doesn't conform with the wasm C++ exception ABI will cause an abort, just like foreign exceptions would on native platforms when unwinding through catch_unwind.

Instead, this happened: catch_unwind only generates a wasm catch instruction matching the C++ exception tag. For unwinding out of functions that are not allowed to unwind at all we do correctly generate a catch_all instruction to call panic_cannot_unwind.

(func $square (;2;) (type 0) (param i32 i32)
    (local i32 i32 i32)
    global.get $__stack_pointer
    i32.const 16
    i32.sub
    local.tee 2
    global.set $__stack_pointer
    block ;; label = @1
      try ;; label = @2
        call $bar
        local.set 3
      catch 0
        local.set 3
        local.get 2
        global.set $__stack_pointer
        try ;; label = @3
          local.get 2
          i32.const 8
          i32.add
          local.get 3
          call $_ZN3std9panicking12catch_unwind7cleanup17h1c165d98d6186f41E
        catch_all
          local.get 2
          global.set $__stack_pointer
          call $_ZN4core9panicking19panic_cannot_unwind17h45f1d8e8d54a6393E
          unreachable
        end
        local.get 2
        i32.load offset=12
        local.set 3
        local.get 2
        i32.load offset=8
        local.set 4
        local.get 0
        local.get 4
        i32.store
        local.get 0
        local.get 3
        i32.store offset=4
        br 1 (;@1;)
      end
      local.get 0
      i32.const 0
      i32.store
      local.get 0
      local.get 3
      i32.store offset=4
    end
    local.get 2
    i32.const 16
    i32.add
    global.set $__stack_pointer
  )

Meta

rustc --version --verbose:

rustc 1.92.0-nightly (695857bc3 2025-10-21)
binary: rustc
commit-hash: 695857bc3f72ec4f59c79f323460fe488c38a53f
commit-date: 2025-10-21
host: x86_64-unknown-linux-gnu
release: 1.92.0-nightly
LLVM version: 21.1.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-wasmTarget: WASM (WebAssembly), http://webassembly.org/P-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-libsRelevant to the library team, which will review and decide on the PR/issue.WG-ffi-unwindWorking group: FFI unwind

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions