wasm-micro-runtime
wasm-micro-runtime copied to clipboard
Different output when running a same binary
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
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);