wasm-bindgen output missing an export for one method of two with the same name

Created on 3 May 2019  路  3Comments  路  Source: rustwasm/wasm-bindgen

Describe the Bug

wasm-bindgen generated javascript contained an export named '__wbg_buffer_24f0cc96e872e2fe' but not one named '__wbg_buffer_85e60d809f6cd4e8', and the generated wasm references both.

Steps to Reproduce

Check out this commit: https://github.com/kyren/gfx/commit/043fec9bd77f0cfdad430a823df29c1ab824e84e

If you have nix you can run ./web_test/build.sh, otherwise just do the steps in the script:

cd to 'examples' and run:
cargo build --release --target=wasm32-unknown-unknown --bin quad --features gl

then cd .. and run wasm-bindgen like so:
wasm-bindgen --target no-modules --no-typescript --out-dir ./web_test ./target/release/wasm32-unknown-unknown/release/quad.wasm

Serve the web_test folder (serve.py serves on port 4000 if you have nix) and load index.html, and you will see:

LinkError: import object field '__wbg_buffer_85e60d809f6cd4e8' is not a Function

Expected Behavior

Definitions for both __wbg_buffer_85e60d809f6cd4e8 and __wbg_buffer_24f0cc96e872e2fe should be included in the exported javascript, or the wasm should only reference the exported one.

Actual Behavior

When building in release, there is a missing function definition and a javascript "LinkError". Also there is a somewhat misleading error message:

`WebAssembly.instantiateStreaming` failed. Assuming this is because your server does not serve wasm with `application/wasm` MIME type`

(It does say "Assuming", but it still threw me off for a bit).

Additional Context

This only happens in release, and according to IRC discussions with @alexcrichton it seems to be linker related and potentially a rustc bug? Enabling LTO apparently is a workaround, as is compiling with the 'cdylib' crate type instead of 'bin'.

bug

Most helpful comment

Thanks for the heads up! I think this is fixed to the best of our ability so I'm gonna close this.

All 3 comments

For some follow-up, this should be fixed upstream in rust-lang/rust at https://github.com/rust-lang/rust/pull/60526.

The bug here is sort of subtle but has to do with the linker. The problem is that the __wbindgen_describe_* symbol for the WebAssembly::Memory::buffer API was missing from the final wasm binary, so wasm-bindgen didn't generate bindings for that method. (this is the __wbg_buffer_85e60d809f6cd4e8 symbol, the __wbg_buffer_24f0cc96e872e2fe is a buffer property accessor for a differnet type).

The WebAssembly::Memory::buffer API is "special" because it's only called internally by js-sys and it's also in a different object file codegen-wise. Because of ThinLTO in release mode the code for the method itself is inlined into Uint8Array::view, which means that the object file containing the descriptor for the __wbg_buffer_85e60d809f6cd4e8 is never actually referenced directly.

Linkers don't actually include object files in archives unless a symbol is referenced, so the archive of js-sys didn't have its object file included which contained the descriptor for __wbg_buffer_85e60d809f6cd4e8. Typically this is handled by passing flags to the linker in the cdylib crate type to export more symbols than lld would otherwise, but these flags weren't passed for the binary crate type.

The fix in https://github.com/rust-lang/rust/pull/60526 is to pass the flags for all crate types, meaning that even for the binary crate type we'll forcibly export the descriptor symbols.

Just a heads up, the fix has just reached stable :tada:

Thanks for the heads up! I think this is fixed to the best of our ability so I'm gonna close this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MarcAntoine-Arnaud picture MarcAntoine-Arnaud  路  3Comments

hunterlester picture hunterlester  路  4Comments

bantic picture bantic  路  4Comments

derekdreery picture derekdreery  路  3Comments

fitzgen picture fitzgen  路  4Comments