Skip to content

WebAssembly ABI mismatch between clang and rust #71871

Closed

Description

@tomaka

When I compile this C code to wasm32-wasi:

typedef struct Vector {
    int a;
    int b;
} Vector;

extern int extract_a(Vector v) {
    return v.a;
}

And this Rust code to wasm32-wasi:

#[repr(C)]
struct Vector {
    a: i32,
    b: i32,
}

extern "C" {
    fn extract_a(v: Vector) -> i32;
}

fn main() {
    unsafe {
        extract_a(Vector { a: 5, b: 4 });
    }
}

And try link them together, I'm getting linking errors:

  = note: lld: error: function signature mismatch: extract_a
          >>> defined as (i32, i32) -> i32 in /home/pierre/Projets/wasm-abi-test/target/wasm32-wasi/debug/deps/wasm_abi_test.67xpw7l331r9o5x.rcgu.o
          >>> defined as (i32) -> i32 in /home/pierre/Projets/wasm-abi-test/target/wasm32-wasi/debug/build/wasm-abi-test-9c49ce7f6c5ca031/out/libfoo.a(test.o)

It seems that, according to clang, passing a struct by value should inline the fields, while for Rust it should be passed by pointer.

I uploaded an example project here: https://github.com/tomaka/wasm-abi-test
It can be built with something like:

AR_wasm32_wasi=/path/to/wasi-sdk-10.0/bin/ar CC_wasm32_wasi=/path/to/wasi-sdk-10.0/bin/clang cargo run --target=wasm32-wasi

Rust version: rustc 1.44.0-nightly (38114ff 2020-03-21)

Activity

  1. added
    A-FFIArea: Foreign function interface (FFI)
    O-wasmTarget: WASM (WebAssembly), http://webassembly.org/
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on May 4, 2020
  2. TheBlueMatt commented on Jan 9, 2021

    @TheBlueMatt

    This is mostly tracked at rustwasm/team#291 and would be fixed by #79998.

  3. TheBlueMatt commented on Jan 12, 2021

    @TheBlueMatt

    This should now work for wasm32-wasi (on current git head).

  4. added
    A-ABIArea: Concerning the application binary interface (ABI)
    on Jul 1, 2022
  5. programmerjake commented on Aug 28, 2022

    @programmerjake
    Member

    Note that #83763 changed the default, so only wasm32-unknown-unknown uses the mismatched ABI, all other wasm targets (including custom targets) now default to using the ABI that matches clang:

    // This is a default for backwards-compatibility with the original
    // definition of this target oh-so-long-ago. Once the "wasm" ABI is
    // stable and the wasm-bindgen project has switched to using it then there's
    // no need for this and it can be removed.
    //
    // Currently this is the reason that this target's ABI is mismatched with
    // clang's ABI. This means that, in the limit, you can't merge C and Rust
    // code on this target due to this ABI mismatch.
    options.default_adjusted_cabi = Some(Abi::Wasm);

  6. temeddix commented on Oct 26, 2023

    @temeddix

    There are discussions going on at wasm-bindgen to extend the support to wasm32-wasi in addition to the current wasm32-unknown-unknown.

    In short, wasm-bindgen needs a consistent C ABI between wasm32-unknown-unknown and wasm32-wasi to support both of them.

    Note that #83763 changed the default, so only wasm32-unknown-unknown uses the mismatched ABI, all other wasm targets (including custom targets) now default to using the ABI that matches clang:

    // This is a default for backwards-compatibility with the original
    // definition of this target oh-so-long-ago. Once the "wasm" ABI is
    // stable and the wasm-bindgen project has switched to using it then there's
    // no need for this and it can be removed.
    //
    // Currently this is the reason that this target's ABI is mismatched with
    // clang's ABI. This means that, in the limit, you can't merge C and Rust
    // code on this target due to this ABI mismatch.
    options.default_adjusted_cabi = Some(Abi::Wasm);

    Can we have ABI that matches clang on wasm32-unknown-unknown as well? I can help with this, but would it be a hard task?

  7. bjorn3 commented on Oct 26, 2023

    @bjorn3
    Member

    The change itself would be removing options.default_adjusted_cabi = Some(Abi::Wasm) from the target spec and that's it. Because it breaks older wasm-bindgen versions it will probably require waiting months to years before we can actually make this change. And preferably we would introduce a future compat warning for this change. Either against older wasm-bindgen versions or against any extern "C" function for which changing the abi actually has any effect.

  8. ranile commented on Oct 26, 2023

    @ranile
    Contributor

    I don't see why breaking older versions wasm-bindgen is a blocker when there can be a compatibility warning and it'll take over 12 weeks until stable if the change were to be merged today. Updating wasm-bindgen is as simple as just running cargo update -p wasm-bindgen, we can tell users to run it. wasm-bindgen is also semver 0.x so it makes no stability guarantees

    It is unfortunate that we have to break code (that we never promised stability for) but the longer we wait, the worse the problem gets.

  9. temeddix commented on Oct 26, 2023

    @temeddix

    I think so too, since the users don't need to refactor their code, this change doesn't need to be warned and waited.

  10. bjorn3 commented on Oct 26, 2023

    @bjorn3
    Member

    We need to warn because it will breal everyone who uses an older wasm-bindgen version. We have done plenty of warnings and sometimes even crate version specific workaround in the past to avoid breakage even after a fixed crate version exists.

  11. temeddix commented on Oct 26, 2023

    @temeddix

    We need to warn because it will breal everyone who uses an older wasm-bindgen version.

    May I ask you what things would be broken and users should be aware of?

    The reason this discussion started was basically major modules in std are not working in wasm32-unknown-unknown, making various crates be divided into wasm and non-wasm versions. Fixing this fragmentation in Rust ecosystem as soon as possible would be good, in my opinion. Maybe we can use a version-specific workaround as you mentioned.

    One thing I'm concerned about is that this issue is being solved too slow. It's older than 3 years. I believe we need some momentum for this issue, or it will just be left unsolved even after 2026 or so..

  12. 28 remaining items

  13. added a commit that references this issue on Mar 17, 2024
  14. added a commit that references this issue on Jun 14, 2025
  15. added 2 commits that reference this issue on Jun 15, 2025
  16. added 2 commits that reference this issue on Jun 15, 2025
  17. added a commit that references this issue on Jun 16, 2025
  18. added a commit that references this issue on Jun 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ABIArea: Concerning the application binary interface (ABI)A-FFIArea: Foreign function interface (FFI)C-bugCategory: This is a bug.O-wasmTarget: WASM (WebAssembly), http://webassembly.org/T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions