bytecodealliance / wasm-micro-runtime

WebAssembly Micro Runtime (WAMR)
Apache License 2.0
4.69k stars 583 forks source link

Different output when running a same binary #2829

Open XinyuShe opened 7 months ago

XinyuShe commented 7 months ago

I used the AOT mode of different runtimes to run randomly generated wasm binaries, and the output from WAMR was different from the others. filea262_9.zip

WAMR used a commit from November 24th and the --bounds-checks=1 feature.

root@4252f5ec38df:/a# iwasm --version
iwasm 1.2.3
root@4252f5ec38df:/a# wamrc --version
wamrc 1.2.3
wamrc --bounds-checks=1 -o filea262_9.wasm.aot filea262_9.wasm ; iwasm --heap-size=0 -f main filea262_9.wasm.aot
filea262_9.wasm
-----------------wasmtime-----------------
warning: using `--invoke` with a function that returns values is experimental and may break in the future
0
0
0
0
0
0

-----------------wasmer-----------------
Compiler: cranelift
Target: x86_64-unknown-linux-gnu
✔ File compiled successfully to `filea262_9.wasmu`.
0 0 0 0 0 0

-----------------wamr-----------------
Create AoT compiler with:
  target:        x86_64
  target cpu:    znver3
  target triple: x86_64-unknown-linux-gnu
  cpu features:  
  opt level:     3
  size level:    3
  output format: AoT file
Compile success, filefilea262_9.wasm.aot was generated.
Exception: out of bounds memory access

-----------------wasmedge-----------------
[2023-11-27 10:17:21.279] [info] compile start
[2023-11-27 10:17:21.294] [info] verify start
[2023-11-27 10:17:21.303] [info] optimize start
[2023-11-27 10:17:21.406] [info] codegen start
[2023-11-27 10:17:21.532] [info] output start
[2023-11-27 10:17:21.649] [info] compile done
0
0
0
0
0
0
wenyongh commented 7 months ago

Hi, this issue is a combination of issue #2678 and issue #2773: different nan values are used in wamr and other runtimes and cause different input offset for the v128.load32_zero opcode, for wamr, the input will cause OOB exception thrown when "--bounds-checks=1" is enabled for wamrc, for others, the input won't cause OOB exception. And for wamr, the OOB exception isn't thrown when "--bounds-checks=1" isn't added for wamrc, since the v128.load32_zero bytecode is eliminated as dead code, see #2773.

In function 14, in the below bytecodes:

    end
    i32.const 1
    v128.load16x4_s offset=4187 align=1
    local.get 0
    i32x4.extract_lane 1
    v128.load32_zero offset=2862 align=1

After the execution of some bytecodes, there is an nan in the input operand of the opcode i32x4.extract_lane 1, some other runtimes normalize the nan to 0x7ff80000 and the operand for this opcode is 0x00000000 0x7ff80000 0x00000000 0x7ff80000, and the result is: 2146959360, so the next v128.load32_zero doesn't throw exception. For WAMR, the result is -1 (=UINT32_MAX), after adding 2862, the boundary check fails and throws exception.

And this bytecode is eliminated when "--bounds-checks=1" isn't added for wamrc, we can disable the dead code elimination by setting Volatile for v128 load, and the exception will be thrown again:

diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c
index 8c35c3fe..d859a7e2 100644
--- a/core/iwasm/compilation/aot_emit_memory.c
+++ b/core/iwasm/compilation/aot_emit_memory.c
@@ -299,6 +299,7 @@ fail:
             goto fail;                                                    \
         }                                                                 \
         LLVMSetAlignment(value, 1);                                       \
+        LLVMSetVolatile(value, true);                                       \
     } while (0)

 #define BUILD_TRUNC(value, data_type)                                     \
diff --git a/core/iwasm/compilation/simd/simd_load_store.c b/core/iwasm/compilation/simd/simd_load_store.c
index 0e869727..1be07f7f 100644
--- a/core/iwasm/compilation/simd/simd_load_store.c
+++ b/core/iwasm/compilation/simd/simd_load_store.c
@@ -36,6 +36,7 @@ simd_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 align,
     }

     LLVMSetAlignment(data, 1);
+    LLVMSetVolatile(data, true);