trunk icon indicating copy to clipboard operation
trunk copied to clipboard

Build failure with Rust 1.82.0 and bundled wasm-opt

Open eric-seppanen opened this issue 1 year ago • 24 comments
trafficstars

After upgrading from Rust 1.81 to 1.82 I discovered that a particular wasm/trunk project no longer builds. It always fails with:

[parse exception: invalid code after misc prefix: 17 (at 0:20646)]
Fatal: error parsing wasm (try --debug for more info)
2024-11-04T23:06:47.941140Z ERROR ❌ error
error from build pipeline

Caused by:
    0: HTML build pipeline failed (1 errors), showing first
    1: error from asset pipeline
    2: running wasm-opt
    3: wasm-opt call to executable '/home/___/.cache/trunk/wasm-opt-version_116/bin/wasm-opt' with args: '["--output=.../wasm_test_2024_b/target/wasm-opt/release/wasm_test_2024_bg.wasm", "-Oz", ".../wasm_test_2024_b/dist/.stage/wasm_test_2024-616af1a08af380ae_bg.wasm"]' returned a bad status: exit status: 1
2024-11-04T23:06:47.941182Z ERROR error from build pipeline
2024-11-04T23:06:47.941184Z  INFO   1: HTML build pipeline failed (1 errors), showing first
2024-11-04T23:06:47.941186Z  INFO   2: error from asset pipeline
2024-11-04T23:06:47.941187Z  INFO   3: running wasm-opt
2024-11-04T23:06:47.941189Z  INFO   4: wasm-opt call to executable '/home/___/.cache/trunk/wasm-opt-version_116/bin/wasm-opt' with args: '["--output=.../wasm_test_2024_b/target/wasm-opt/release/wasm_test_2024_bg.wasm", "-Oz", ".../wasm_test_2024_b/dist/.stage/wasm_test_2024-616af1a08af380ae_bg.wasm"]' returned a bad status: exit status: 1

I built a minimized project that demonstrates the issue here: https://github.com/eric-seppanen/wasm_test_2024

This seems to be a wasm-opt issue, but since wasm-opt is bundled with trunk by default, perhaps it would be a good idea to ship a newer version?

eric-seppanen avatar Nov 04 '24 23:11 eric-seppanen

I investigated a few versions of wasm-opt and found that any version >= 117 works, but they all require an additional CLI flag --enable-bulk-memory.

I'm not sure how to make this happen when using trunk.

So perhaps this is related to #866?

eric-seppanen avatar Nov 04 '24 23:11 eric-seppanen

It might make sense to update the default versions for the different tools: https://github.com/trunk-rs/trunk/blob/306fa0b72990262333725eabe8fdcc66d17bc14c/src/tools.rs#L98-L105

Also https://github.com/trunk-rs/trunk/pull/901 might help.

ctron avatar Nov 05 '24 09:11 ctron

After some more experimentation, This problem seems specific to wasm-bindgen/wasm-bindgen-cli 0.2.95 (0.2.93 works; 0.2.94 was yanked but I think it's also broken). But the problem is only triggered by a build with rust 1.82.0.

I don't think it matters what Trunk's default wasm-bindgen version is-- the version of wasm-bindgen-cli has to match the version of the wasm-bindgen library crate. It looks like Trunk does this matching automatically, so the failure appears when my project uses wasm-bindgen >= 0.2.94.

eric-seppanen avatar Nov 05 '24 18:11 eric-seppanen

I have the same problem

Finished `release` profile [optimized] target(s) in 6.89s

[parse exception: invalid code after misc prefix: 17 (at 0:564976)] Fatal: error parsing wasm (try --debug for more info) 2024-11-08T02:11:23.262311Z ERROR ❌ error error from build pipeline

rustc 1.82.0 (f6e511eec 2024-10-15) trunk 0.21.4

kunhualqk avatar Nov 08 '24 02:11 kunhualqk

As you're using trunk 0.21.4, you should be able to use the new data-wasm-opt-param flag. If you find some reasonable settings that "just work", we could add them as a default, as we now also have the version available internally.

ctron avatar Nov 08 '24 07:11 ctron

Or maybe we need to bump the default version of wasm-opt.

ctron avatar Nov 08 '24 07:11 ctron

Also note that this will be fixed in the next release of wasm-bindgen, which won't emit table.fill instructions by default when it encounters the wasm metadata output by rustc 1.82.

eric-seppanen avatar Nov 11 '24 18:11 eric-seppanen

As you're using trunk 0.21.4, you should be able to use the new data-wasm-opt-param flag. If you find some reasonable settings that "just work", we could add them as a default, as we now also have the version available internally.

I had this issue and resolved it for myself with the following:

  • trunk 0.21.4
  • wasm-opt 119 via https://github.com/WebAssembly/binaryen/releases/tag/version_119
  • data-wasm-opt-params="--enable-bulk-memory" on the failing component

I admit I do not know what bulk memory or table.fill instructions are, perhaps there are consequences to this that I am unaware of.

isosphere avatar Nov 11 '24 21:11 isosphere

Thanks for the summary. That is super helpful. Now that we have internal APIs for the tools in place, would it make sense to auto-enable --enable-bulk-memory in case the wasm-opt version 119 or higher?

ctron avatar Nov 12 '24 12:11 ctron

Note that rustc doesn't enable bulk memory by default, so to me the safest default would be to track whatever rustc is doing. Enabling bulk memory instructions by default could affect compatibility with existing runtimes.

The reason we're having problems with rust 1.82.0 is because of a bug in wasm-bindgen 0.2.94-0.2.95: wasm-bindgen notices that rustc has enabled new target features, and accidentally enables bulk memory on its output as a side-effect. This will no longer be the case in wasm-bindgen 0.2.96.

eric-seppanen avatar Nov 12 '24 18:11 eric-seppanen

What should happen in the long term? A few possibilities I can think of:

  1. By default enable the most common set of target features when calling wasm-opt. This is hard to do as this set is changing across rustc versions and there are runtime compatibility hazards in enabling the wrong thing.
  2. Require trunk users to specify a set of wasm-opt flags that match their runtime capabilities and their rustc output. This gives users the power to solve their own problems, but many users won't know what settings to use, which makes the tools harder to use correctly.
  3. Automatically detect what rustc is doing, and try to configure wasm-opt the same way. Ideally wasm-opt would be doing this itself[^1], but if that's not going to happen then this might be a kindness to users who just want things to work without needing a deep dive into webassembly proposals and rustc target-features. Perhaps this is possible by reading the "target-features" section of the wasm output?

Is wasm-opt necessary for trunk to work? Perhaps if wasm-opt is going to need such careful configuration it should be an optional step in the build process (for users that don't want the deep dive).

[^1]: wasm-opt has a deprecated flag --detect-features but I can't find any documentation on whether this functionality ever existed or still exists. Maybe more research is needed here?

eric-seppanen avatar Nov 12 '24 18:11 eric-seppanen

Thanks for this thread! It's super helpful.

Is it possible to specify default wasm-opt version through the configuration file? From a quick look at the documentation and code it appears not, but maybe I missed something.

For others, this might be helpful: I managed to get things working by cloning the trunk, then patching trunk/src/tools.rs changing the default version to 119 and adding data-wasm-opt-params="--enable-bulk-memory" as proposed by @isosphere.

One thing I noted is data-wasm-opt-params="--enable-bulk-memory" seems to not work if you've set data-wasm-opt="s".

troels-im avatar Nov 19 '24 10:11 troels-im

I guess the answer to all of this is: PRs welcome :wink:

ctron avatar Nov 19 '24 10:11 ctron

@troelsfr the wasm-opt version is configurable already through Trunk.toml https://github.com/trunk-rs/trunk/blob/4c9d85f6f04a31a272c71db8df12e142c76311fb/Trunk.toml

I'm using:

[tools]
wasm_opt = "version_119"

and this on my html:

<link data-trunk rel="rust" data-bin="some-app-name" data-wasm-opt="z"
        data-wasm-opt-params="--enable-bulk-memory" />

hmacias-avaya avatar Nov 19 '24 11:11 hmacias-avaya

Sorry for not reading the docs careful enough! And thanks a lot for pointing me to the right place!

troels-im avatar Nov 19 '24 12:11 troels-im

Also note that this will be fixed in the next release of wasm-bindgen, which won't emit table.fill instructions by default when it encounters the wasm metadata output by rustc 1.82.

It doesn't seem like this got fixed in the meantime, see our CI run in https://github.com/yewstack/yew/actions/runs/13441890205/job/37558138060. This hits the same issue with

trunk v0.21.7
wasm-bindgen v0.2.100

Is there a way to set this data-wasm-opt-params for all projects in a workspace?

WorldSEnder avatar Feb 20 '25 23:02 WorldSEnder

Also note that this will be fixed in the next release of wasm-bindgen, which won't emit table.fill instructions by default when it encounters the wasm metadata output by rustc 1.82.

It doesn't seem like this got fixed in the meantime

That's surprising. I saw the problem go away when updating to wasm-bindgen 0.2.96, and since then we have also updated to 0.2.100 and the problem has not reappeared for us.

I'm not sure what to look for in that github actions link; can you point out what the failure is?

eric-seppanen avatar Feb 21 '25 00:02 eric-seppanen

Example error for completeness (doesn't get marked as a build failure in the log for unrelated reasons - the relevant step is "Build examples"):

  [parse exception: invalid code after misc prefix: 17 (at 0:104693)]
  Fatal: error parsing wasm (try --debug for more info)
  2025-02-20T18:18:00.800687Z ERROR ❌ error
  error from build pipeline
  
  Caused by:
      0: HTML build pipeline failed (1 errors), showing first
      1: error from asset pipeline
      2: running wasm-opt
      3: wasm-opt call to executable '/home/runner/.cache/trunk/wasm-opt-version_116/bin/wasm-opt' with args: '["--output=/home/runner/work/yew/yew/target/wasm-opt/release/webgl_bg.wasm", "-O", "/home/runner/work/yew/yew/dist/webgl/.stage/webgl-1ebcba5a5bedf01f_bg.wasm"]' returned a bad status: exit status: 1
  2025-02-20T18:18:00.800710Z ERROR error from build pipeline
  2025-02-20T18:18:00.800713Z  INFO   1: HTML build pipeline failed (1 errors), showing first
  2025-02-20T18:18:00.800716Z  INFO   2: error from asset pipeline
  2025-02-20T18:18:00.800717Z  INFO   3: running wasm-opt
  2025-02-20T18:18:00.800718Z  INFO   4: wasm-opt call to executable '/home/runner/.cache/trunk/wasm-opt-version_116/bin/wasm-opt' with args: '["--output=/home/runner/work/yew/yew/target/wasm-opt/release/webgl_bg.wasm", "-O", "/home/runner/work/yew/yew/dist/webgl/.stage/webgl-1ebcba5a5bedf01f_bg.wasm"]' returned a bad status: exit status: 1

Maybe this got "revived" by 1.87.0-nightly?

WorldSEnder avatar Feb 21 '25 00:02 WorldSEnder

Yeah, looks like LLVM20 turned on bulk memory instructions: https://github.com/rust-lang/rust/issues/137315

eric-seppanen avatar Feb 21 '25 00:02 eric-seppanen

Should we consider always bundling the newest wasm_opt?

We can get the latest wasm_opt version using GitHub API by:

curl https://api.github.com/repos/WebAssembly/binaryen/releases/latest | jq -r ".tag_name"

or if we want to do it in Rust (at runtime?):

#[derive(Deserialize)]
struct GitHubRelease {
    tag_name: String,
}

pub fn get_latest_wasm_opt_version() -> String {
    let url = "https://api.github.com/repos/WebAssembly/binaryen/releases/latest";
    let client = reqwest::blocking::Client::new();

    // github api requires a user agent
    // https://docs.github.com/en/rest/using-the-rest-api/troubleshooting-the-rest-api?apiVersion=2022-11-28#user-agent-required
    let req_builder = client.get(url).header("User-Agent", "trunk-wasm-opt-checker");

    // Send the request
    let res = req_builder
        .send()
        .expect("Failed to send request to GitHub API");

    if !res.status().is_success() {
        // Get more details about the error
        let status = res.status();
        let error_text = res
            .text()
            .unwrap_or_else(|_| "Could not read error response".to_string());

        panic!(
            "GitHub API request failed with status: {}. Details: {}",
            status, error_text
        );
    }

    let release: GitHubRelease = res.json().expect("Failed to parse GitHub API response");
    release.tag_name
}

Madoshakalaka avatar Mar 02 '25 14:03 Madoshakalaka

Does the latest version of wasm_opt fix this issue? It doesn't seem to fix it for me, or I'm doing something wrong. I'm using rust nightly 1.88, wasm-opt version_123 and wasm-bindgen 0.2.100. I can only get it working by disabling the -nontrapping-fptoint feature when compiling and pass --enable-bulk-memory to wasm-opt, which goes against what is said here https://github.com/trunk-rs/trunk/pull/967. Is what I'm doing the right way to do it? This is my project: build script:

RUSTFLAGS="-C target-feature=-nontrapping-fptoint" trunk build --release

index.html:

<link
    data-trunk
    rel="rust"
    data-wasm-opt="4"
    data-wasm-opt-params="--enable-bulk-memory"
/>

Cargo.toml:

[profile.release]
codegen-units = 1
lto = true 
panic = "abort" 
strip = true      

.cargo/config.toml:

[unstable]
build-std = ["std", "panic_abort"]
build-std-features = ["panic_immediate_abort"]
trim-paths = true

lucascompython avatar Apr 19 '25 13:04 lucascompython

If wasm-opt is going to be full of usability paper cuts, I wonder if trunk should just disable it by default.

It seems like a bad tradeoff to force people to debug a wasm code optimizer before they ever get their first project working.

eric-seppanen avatar Apr 21 '25 18:04 eric-seppanen

I'm not using nightly but this works for me even after changing to wasm_opt version_123. I'm using wasm-bindgen 0.2.95 in case that matters.

hmacias-avaya avatar Apr 22 '25 06:04 hmacias-avaya

Original

Running into this same issue for a simple trunk and yew setup. None of the solutions given help, guess I just won't allow for release mode builds for now?

Update

After some experimenting, it looked like some package I had installed way back in 2020 had installed an ancient version of wasm-opt: 17115192 Apr 28 2020 /usr/local/bin/wasm-opt

$ which wasm-opt
/usr/local/bin/wasm-opt

$ wasm-opt --version
wasm-opt version 93 (version_93)

I wasn't able to determine who/what installed it, so I renamed the bin found here and it correctly found the most recent version from cargo install. This fixed it for me 100%!

SeedyROM avatar May 20 '25 04:05 SeedyROM