Skip to content

rustc disagrees with emcc about WASM struct ABI in parameters #88152

Open

Description

I have the following Rust code, being compiled with cargo +nightly build --target wasm32-unknown-unknown

// in crate "em"

#[repr(C)]
pub struct Options {
    a: u8,
    b: u8
}

#[no_mangle]
pub extern "C" fn take_struct(o: Options) {}

And the following C++ code, compiled with emcc -std=c++17 test.cpp target/wasm32-unknown-unknown/debug/libem.a -ldl -lpthread -lm -g -o main.html --emrun -sWASM=1 (using the emscripten sdk)

# test.cpp 
extern "C" {
    typedef struct Options {
        uint8_t a;
        uint8_t b;
    } Options;
    void take_struct(Options o);
}

int main() {
    Options o;
    take_struct(o);
    return 0;
}

I expected to see this happen: The code would compile without warnings and run fine.

Instead, this happened:

emcc shows up the following warning:

wasm-ld: warning: function signature mismatch: take_struct
>>> defined as (i32) -> void in /tmp/emscripten_temp_qz2pbc3_/test_0.o
>>> defined as (i32, i32) -> void in target/wasm32-unknown-unknown/debug/libem.a(em.zb05z167nruq6bs.rcgu.o)

and running main.html in the browser throws the following error (to be expected based on the warning)

exception thrown: RuntimeError: unreachable,RuntimeError: unreachable
    at signature_mismatch:take_struct (http://localhost:8000/main.wasm:wasm-function[1]:0x165)
    at __original_main (http://localhost:8000/main.wasm:wasm-function[2]:0x1f1)
    at main (http://localhost:8000/main.wasm:wasm-function[3]:0x20e)
    at http://localhost:8000/main.js:1560:22
    at callMain (http://localhost:8000/main.js:2142:15)
    at doRun (http://localhost:8000/main.js:2212:23)
    at http://localhost:8000/main.js:2223:7

Seems like rustc believes that the signature for fn({u8, u8}) should be (i32, i32) -> void, whereas emcc believes it should be (i32) -> void.

A lot of other function signatures work (including returning Option), it's specifically when such a struct is a parameter that this happens.

I'm not sure which side is at fault here, but an incompatibility between Rust and emcc means that it won't be possible to use WASM with C++ programs that embed a little Rust (or vice versa), which seems like a problem worth highlighting. I think there are other ways to compile C++ to WASM via clang that I need to check out next.

Meta

Version info
$ rustc --version --verbose
rustc 1.56.0-nightly (2d2bc94c8 2021-08-15)
binary: rustc
commit-hash: 2d2bc94c8c3aa778e191f80261c726e4777439f1
commit-date: 2021-08-15
host: x86_64-unknown-linux-gnu
release: 1.56.0-nightly
LLVM version: 12.0.1
$ emcc --version
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 2.0.27 (7e538a419c3649f3a540a57beab347aa8f6c6271)
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

cc @fitzgen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.O-emscriptenTarget: 50% off wasm32-unknown-musl. the savings come out of stdio.h, but hey, you get SDL!O-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