Skip to content

Runtime error using f64::sin in wasm32 #128105

Closed
@hexane360

Description

@hexane360

I'm working on a WASM library using wasm_bindgen which wraps ndarray. I have the following basic structure:

pub enum DynArray {
    Float32(ArrayD<f32>),
    Float64(ArrayD<f64>),
    ...
}

impl DynArray {
    pub fn sin(&self) -> DynArray {
        match self {
            DynArray::Float32(arr) => arr.map(|e| e.sin()).into(),
            DynArray::Float64(arr) => arr.map(|e| e.sin()).into(),
            ...
        }
    }
}

i.e. sin() is implemented by first dispatching on type and then mapping.
However, calling sin on a Float64 array results in the following runtime error:

RuntimeError: unreachable
    at wasm_array_bug.wasm.signature_mismatch:sin (5e6ff9aa49a8693eccd3.module.wasm:0x59426)
    at wasm_array_bug.wasm.std::f64::<impl f64>::sin::hb3cd0e4a298bd1b1 (5e6ff9aa49a8693eccd3.module.wasm:0x55d96)
    at wasm_array_bug.wasm.wasm_array_bug::DynArray::sin::{{closure}}::hc86147a10cddb9c5 (5e6ff9aa49a8693eccd3.module.wasm:0x560a6)
    at wasm_array_bug.wasm.ndarray::iterators::to_vec_mapped::{{closure}}::h0f8b6901051cb335 (5e6ff9aa49a8693eccd3.module.wasm:0x414f7)
    at wasm_array_bug.wasm.<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::fold::h83c1cb924c78a7c1 (5e6ff9aa49a8693eccd3.module.wasm:0x31beb)
    at wasm_array_bug.wasm.ndarray::iterators::to_vec_mapped::h2d7cca19531985df (5e6ff9aa49a8693eccd3.module.wasm:0x2c54f)
    at wasm_array_bug.wasm.ndarray::impl_constructors::<impl ndarray::ArrayBase<S,D>>::from_shape_trusted_iter_unchecked::hd85ecc6b56c06e67 (5e6ff9aa49a8693eccd3.module.wasm:0x2b1db)
    at wasm_array_bug.wasm.ndarray::impl_methods::<impl ndarray::ArrayBase<S,D>>::map::h753b54be2654f42f (5e6ff9aa49a8693eccd3.module.wasm:0x35707)
    at wasm_array_bug.wasm.wasm_array_bug::DynArray::sin::h634584090a112859 (5e6ff9aa49a8693eccd3.module.wasm:0x3a986)
    at wasm_array_bug.wasm.wasm_array_bug::sin::h90417ccd7ffb0d96 (5e6ff9aa49a8693eccd3.module.wasm:0x5208f)

This error originates in the implementation of f64::sin().
Interestingly, I don't get the same error for f32. I also don't get the same error if I remove the enum & match:

#[wasm_bindgen]
pub struct Float64Array {
    inner: ArrayD<f64>
}

#[wasm_bindgen]
pub fn sin_float64(arr: &Float64Array) -> Float64Array {
    arr.inner.map(|e| e.sin()).into()
}

This makes me think there's likely some strange miscompilation. For reference, here's the f64::sin() function compiled in the broken case (with enum/match):

  (func $std::f64::<impl f64>::sin::hb3cd0e4a298bd1b1 (;960;) (param $var0 f64) (result f64)
    (local $var1 i32)
    (local $var2 i32)
    (local $var3 i32)
    (local $var4 i32)
    (local $var5 i32)
    (local $var6 f64)
    (local $var7 f64)
    global.get $global0
    local.set $var1
    i32.const 16
    local.set $var2
    local.get $var1
    local.get $var2
    i32.sub
    local.set $var3
    local.get $var3
    global.set $global0
    local.get $var3
    local.get $var0
    f64.store
    local.get $var0
    call $signature_mismatch:sin
    local.set $var6
    local.get $var3
    local.get $var6
    f64.store offset=8
    local.get $var3
    f64.load offset=8
    local.set $var7
    i32.const 16
    local.set $var4
    local.get $var3
    local.get $var4
    i32.add
    local.set $var5
    local.get $var5
    global.set $global0
    local.get $var7
    return
  )

This appears to push $var0 to the stack and then immediately calls $signature_mismatch:sin, which halts.

The working case (without enum/match) compiles to the following:

  (func $std::f64::<impl f64>::sin::hb3cd0e4a298bd1b1 (;743;) (param $var0 f64) (result f64)
    (local $var1 i32)
    (local $var2 i32)
    (local $var3 i32)
    (local $var4 i32)
    (local $var5 i32)
    (local $var6 f64)
    (local $var7 f64)
    global.get $global0
    local.set $var1
    i32.const 16
    local.set $var2
    local.get $var1
    local.get $var2
    i32.sub
    local.set $var3
    local.get $var3
    global.set $global0
    local.get $var3
    local.get $var0
    f64.store
    local.get $var0
    call $sin
    local.set $var6
    local.get $var3
    local.get $var6
    f64.store offset=8
    local.get $var3
    f64.load offset=8
    local.set $var7
    i32.const 16
    local.set $var4
    local.get $var3
    local.get $var4
    i32.add
    local.set $var5
    local.get $var5
    global.set $global0
    local.get $var7
    return
  )

I've uploaded the complete code to reproduce the issue here: https://github.com/hexane360/wasm-array-bug

I'm filing this issue here because it appears to be a miscompilation. It's possible this is actually a problem in wasm-bindgen or wasm-pack. Please let me know and I'll open an issue there instead.

Meta

rustc --version --verbose:

rustc 1.79.0 (129f3b996 2024-06-10)
binary: rustc
commit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081
commit-date: 2024-06-10
host: aarch64-apple-darwin
release: 1.79.0
LLVM version: 18.1.7
  • wasm-pack version 0.12.1
  • wasm-bindgen version 0.2.92

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-gubCategory: the reverse of a compiler bug is generally UBO-wasmTarget: WASM (WebAssembly), http://webassembly.org/

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions