wasmerio / wasmer

🚀 The leading Wasm Runtime supporting WASIX, WASI and Emscripten
https://wasmer.io
MIT License
18.45k stars 789 forks source link

Non-deterministic wrong code generation between LLVM and LLVM with optimizations #4043

Open ethanstanley3 opened 1 year ago

ethanstanley3 commented 1 year ago

Describe the bug

echo "`wasmer -V` | `rustc -V` | `uname -m`"
wasmer 4.0.0 | rustc 1.65.0 | x86_64

Running a specific webassembly module results in non-deterministic wrong code generation between LLVM and LLVM with optimizations enabled. I found that LLVM is consistent with other WebAssembly implementations, including NodeJS.

Steps to reproduce

Here is a zipped rust project to reproduce the bug: load-wasmer.zip

  1. Unzip load-wasmer.zip
  2. Compile with cargo build
  3. Run the test case with ./verify.zsh, which will run both versions and display the outputs

Here are a few outputs I got:

A (LLVM/Optimize) ==> d745ced3
B (LLVM) ==> ed267405
A (LLVM/Optimize) ==> ff2c9b5d
B (LLVM) ==> ed267405
A (LLVM/Optimize) ==> cb060756
B (LLVM) ==> ed267405

Expected behavior

The displayed checksums should be the same and deterministic.

Actual behavior

The displayed checksums are not the same. The checksum for LLVM/Optimize is non-deterministic.

Here is the textual format of the test case. I have reduced it as much as I can. I have noted with comments lines that cannot be reduced while preserving non-determinism and the wrong code generation. An interesting behavior is that a call to a simple function cannot be inlined.

(module
  (func (;0;) (result i32)
    (local i32)
    i32.const 1
    i32.const 2 ;; setting to number greater than 1 introduces non-determinism
    local.set 0
    call 1 ;; cannot inline
    f32.floor ;; cannot delete
    loop (param f32) (result f32) ;; label = @1
      i32.const 1
      i32.const 1
      i32.load offset=93 align=1
      br_if 1 (;@0;)
      drop
      call 1 ;; cannot inline
      f32.sub ;; cannot remove
      local.get 0
      i32.const -1 ;; must be negative or infinite loop
      i32.add
      local.tee 0
      br_if 0 (;@1;)
    end
    f32.store offset=43 align=1
    i32.const 0
    return)
  (func (;1;) (result f32)
    f32.const 0)
  (func (;2;)) ;; Needed for test harness
  (memory (;0;) 1)
  (export "_memory" (memory 0))
  (export "_main" (func 0))
  (export "_crc_globals" (func 2)))

Additional context

This test case is derived from a program created by Wasmlike, an Xsmith-based random program generator. https://www.flux.utah.edu/project/xsmith

ptitSeb commented 1 year ago

Probably linked to https://github.com/wasmerio/wasmer/issues/3323 and https://github.com/wasmerio/wasmer/issues/3190

stale[bot] commented 4 weeks ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.