teyahb8 opened issue #11391:
Test Case
wasm file: wasm-shrunken_test779339.txt
wat code:
(module (type (;0;) (func (result v128 v128 v128 v128 v128 v128 v128))) (memory (;0;) 65536 65536) (export "main" (func 0)) (func (;0;) (type 0) (result v128 v128 v128 v128 v128 v128 v128) (local v128) v128.const i32x4 0x269b302c 0x33ff2555 0x3d332eb9 0x6150b21b local.set 0 f32.const 0x1.91780cp+106 (;=127230580000000000000000000000000;) f32x4.splat local.get 0 local.get 0 i32x4.sub local.tee 0 drop local.get 0 local.get 0 local.get 0 local.get 0 i8x16.eq f64x2.min i32.const 1 i32x4.shr_s local.tee 0 f32x4.ne local.get 0 i32.const 1 i32x4.shr_s i64x2.sub local.get 0 i8x16.extract_lane_s 1 v128.load64_zero offset=4424 align=1 f32.const 0x1.abb8e2p+62 (;=7705158000000000000;) f32x4.splat i32.const 9009 v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 v128.store8_lane offset=818 0 local.get 0 local.get 0 drop local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 drop i32.const 1 if ;; label = @1 local.get 0 v128.const i32x4 0xd4913b28 0xfd94f22d 0x28f70108 0x2ee6c557 i8x16.ne local.set 0 local.get 0 local.set 0 local.get 0 local.set 0 loop ;; label = @2 i32.const 0 i32.const 0 v128.load8x8_s offset=7845 align=1 local.tee 0 drop i32.const 0 if (result v128) ;; label = @3 loop ;; label = @4 nop local.get 0 v128.const i32x4 0x4412d00e 0x91b9105c 0x3f5d100c 0x4888c991 i32x4.extmul_low_i16x8_s local.set 0 local.get 0 local.set 0 nop block ;; label = @5 i32.const 0 br_if 0 (;@5;) i32.const 0 br_if 0 (;@5;) nop local.get 0 local.set 0 end local.get 0 local.set 0 local.get 0 local.set 0 local.get 0 local.set 0 block ;; label = @5 block ;; label = @6 block ;; label = @7 block ;; label = @8 local.get 0 drop i32.const 0 br_table 1 (;@7;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 2 (;@6;) 0 (;@8;) end i32.const 0 br_if 2 (;@5;) nop nop br 2 (;@5;) end local.get 0 local.set 0 local.get 0 local.set 0 local.get 0 local.get 0 f64x2.sub local.set 0 br 1 (;@5;) end nop local.get 0 drop local.get 0 v128.const i32x4 0x7d1f37e7 0x275466b3 0x4ed3def7 0x4ae48eda i32.const 0 select local.set 0 local.get 0 v128.const i32x4 0x6d311927 0x418c5fa1 0xfd0e4ac7 0x91fbcd1d local.get 0 drop i32.const 1 select local.set 0 end i32.const 0 local.get 0 v128.store16_lane offset=5390 align=1 0 nop nop local.get 0 drop i32.const 0 br_if 0 (;@4;) end i32.const 0 v128.load32_zero offset=1480 align=1 else local.get 0 end local.tee 0 v128.const i32x4 0xa3dc3f3f 0x11c29a13 0xba0ce1ed 0x49567075 i8x16.min_u local.tee 0 v128.store32_lane offset=9763 align=1 1 i32.const 1 br_if 0 (;@2;) end i32.const 7345 local.get 0 v128.store32_lane offset=4669 align=1 0 i32.const 1 local.get 0 v128.store64_lane offset=3353 align=1 1 end i32.const 0 local.get 0 local.tee 0 v128.store32_lane offset=9577 align=1 0 drop drop drop drop drop block ;; label = @1 block ;; label = @2 block ;; label = @3 i32.const 1 br_if 0 (;@3;) local.get 0 local.get 0 i64x2.bitmask v128.load8_splat offset=9328 f32x4.le drop i32.const 0 br_if 1 (;@2;) br 2 (;@1;) end local.get 0 drop i32.const 0 br_if 1 (;@1;) end i32.const 0 local.get 0 v128.store64_lane offset=333 align=1 1 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 local.get 0 return end local.get 0 drop v128.const i32x4 0x04ef3aa8 0x144a0479 0x7d6f0c6b 0x86e20f80 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 return ) )Steps to Reproduce
- Run:
wasmtime -W all-proposals=y --invoke main test.wasmExpected Results
Based on wasmer (llvm backed), wamr (AOT mode), and wasmedge, the output is:
out of boundsexceptionActual Results
Wasmtime hangs indefinitely
Versions and Environment
Wasmtime version or commit: wasmtime 37.0.0 (3cbeb24bc 2025-08-06)
Operating system: Ubuntu 22.04
Architecture: x86_64
Extra Info
Can you please confirm? Thanks in advance.
teyahb8 added the bug label to Issue #11391.
cfallin commented on issue #11391:
@teyahb8, a request: could you invest a little more time into your bug reporting? While we're thankful for reports in general, you are following a pattern we have seen a bunch of times before, where someone points a new fuzzer at Wasmtime and generates a bunch of reports with minimal effort to bottom out root causes. This is problematic when combined with incomplete filtering or misunderstanding of the spec on your end (see e.g. your recent #11387): it creates significant cost for core maintainers in a way that is not balanced. In particular, the social contract of open-source dictates that you spend effort to reduce the bug, write up your understanding of the issue and why you think the results are incorrect.
So: would you mind minimizing this further? Could you note which load or store you believe should go out of bounds that doesn't? Thanks!
(We should probably have some documentation on "how to be a responsible citizen when fuzzing Wasmtime"...)
cfallin commented on issue #11391:
Actually, I was bothered enough by this to reduce it for you -- this sequence leads up to a load that goes out of bounds when using Pulley (
wasmtime run --target pulley64) but not x86-64:v128.const i32x4 0x269b302c 0x33ff2555 0x3d332eb9 0x6150b21b local.set 0 f32.const 0x1.91780cp+106 (;=127230580000000000000000000000000;) f32x4.splat local.get 0 local.get 0 i32x4.sub local.tee 0 drop local.get 0 local.get 0 local.get 0 local.get 0 i8x16.eq f64x2.min i32.const 1 i32x4.shr_s local.tee 0 f32x4.ne local.get 0 i32.const 1 i32x4.shr_s i64x2.sub local.get 0 i8x16.extract_lane_s 1 v128.load64_zero offset=4424 align=1which I manually reduced to
v128.const i32x4 0 0 0 0 v128.const i8x16 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff f64x2.min i32.const 1 i32x4.shr_s i8x16.extract_lane_s 1 v128.load64_zero offset=4424 align=1Note that this is performing a floating-point operation on v128 bits that (interpreted as
f64x2) are NaNs, so Wasm permits nondeterminism. On x86-64, our implementation off64x2.min(0x00000000000000000000000000000000, 0xffffffffffffffffffffffffffffffff)returns0xfff8000000000000fff8000000000000, while Pulley64's returns0xffffffffffffffffffffffffffffffff. The second argument is a NaN, and the result is a NaN, so both are correct. Neither are actually canonical; with-W nan-canonicalization=y, we get0x7ff80000000000007ff8000000000000.With the all-ones (
0xfffff...) result, the arithmetic shift-right-by-1 gives a bottom 32 bits of0xffffffff(sign bit smeared), the signed extract-lane gives a scalar i32 result of0xffffffff, and this load goes out of bounds (with the 4424-byte offset) in a 4GiB memory. With the x86-64 result with a NaN payload of all zeroes (also legal), we get a result from the extract-lane of0, and we are in-bounds. Note that with NaN canonicalization enabled, the load is also in-bounds.The "hangs indefinitely" is a red herring: it is the result of the rest of your randomly-generated fuzz case, which has loops and a bunch of other junk that will never terminate. The relevant question is whether the initial load traps.
Because the behavior is dependent on particular NaN payload bits, and a particular (non-canonical) NaN behavior of x86-64 causes the load to trap, this is a perfectly allowable execution, and not a bug.
Note the effort put in to analyze the bug here -- please do similar for any future fuzzbugs you file, and please note the sources of nondeterminism in Wasm and account for them in your infrastructure! You have already hit two (NaNs here, and stack depth in #11387 and #11390); the third to watch out for is whether
memory.growsucceeds, which is allowed to depend on host resource availability.
cfallin closed issue #11391:
Test Case
wasm file: wasm-shrunken_test779339.txt
wat code:
(module (type (;0;) (func (result v128 v128 v128 v128 v128 v128 v128))) (memory (;0;) 65536 65536) (export "main" (func 0)) (func (;0;) (type 0) (result v128 v128 v128 v128 v128 v128 v128) (local v128) v128.const i32x4 0x269b302c 0x33ff2555 0x3d332eb9 0x6150b21b local.set 0 f32.const 0x1.91780cp+106 (;=127230580000000000000000000000000;) f32x4.splat local.get 0 local.get 0 i32x4.sub local.tee 0 drop local.get 0 local.get 0 local.get 0 local.get 0 i8x16.eq f64x2.min i32.const 1 i32x4.shr_s local.tee 0 f32x4.ne local.get 0 i32.const 1 i32x4.shr_s i64x2.sub local.get 0 i8x16.extract_lane_s 1 v128.load64_zero offset=4424 align=1 f32.const 0x1.abb8e2p+62 (;=7705158000000000000;) f32x4.splat i32.const 9009 v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 v128.store8_lane offset=818 0 local.get 0 local.get 0 drop local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 drop i32.const 1 if ;; label = @1 local.get 0 v128.const i32x4 0xd4913b28 0xfd94f22d 0x28f70108 0x2ee6c557 i8x16.ne local.set 0 local.get 0 local.set 0 local.get 0 local.set 0 loop ;; label = @2 i32.const 0 i32.const 0 v128.load8x8_s offset=7845 align=1 local.tee 0 drop i32.const 0 if (result v128) ;; label = @3 loop ;; label = @4 nop local.get 0 v128.const i32x4 0x4412d00e 0x91b9105c 0x3f5d100c 0x4888c991 i32x4.extmul_low_i16x8_s local.set 0 local.get 0 local.set 0 nop block ;; label = @5 i32.const 0 br_if 0 (;@5;) i32.const 0 br_if 0 (;@5;) nop local.get 0 local.set 0 end local.get 0 local.set 0 local.get 0 local.set 0 local.get 0 local.set 0 block ;; label = @5 block ;; label = @6 block ;; label = @7 block ;; label = @8 local.get 0 drop i32.const 0 br_table 1 (;@7;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 2 (;@6;) 0 (;@8;) end i32.const 0 br_if 2 (;@5;) nop nop br 2 (;@5;) end local.get 0 local.set 0 local.get 0 local.set 0 local.get 0 local.get 0 f64x2.sub local.set 0 br 1 (;@5;) end nop local.get 0 drop local.get 0 v128.const i32x4 0x7d1f37e7 0x275466b3 0x4ed3def7 0x4ae48eda i32.const 0 select local.set 0 local.get 0 v128.const i32x4 0x6d311927 0x418c5fa1 0xfd0e4ac7 0x91fbcd1d local.get 0 drop i32.const 1 select local.set 0 end i32.const 0 local.get 0 v128.store16_lane offset=5390 align=1 0 nop nop local.get 0 drop i32.const 0 br_if 0 (;@4;) end i32.const 0 v128.load32_zero offset=1480 align=1 else local.get 0 end local.tee 0 v128.const i32x4 0xa3dc3f3f 0x11c29a13 0xba0ce1ed 0x49567075 i8x16.min_u local.tee 0 v128.store32_lane offset=9763 align=1 1 i32.const 1 br_if 0 (;@2;) end i32.const 7345 local.get 0 v128.store32_lane offset=4669 align=1 0 i32.const 1 local.get 0 v128.store64_lane offset=3353 align=1 1 end i32.const 0 local.get 0 local.tee 0 v128.store32_lane offset=9577 align=1 0 drop drop drop drop drop block ;; label = @1 block ;; label = @2 block ;; label = @3 i32.const 1 br_if 0 (;@3;) local.get 0 local.get 0 i64x2.bitmask v128.load8_splat offset=9328 f32x4.le drop i32.const 0 br_if 1 (;@2;) br 2 (;@1;) end local.get 0 drop i32.const 0 br_if 1 (;@1;) end i32.const 0 local.get 0 v128.store64_lane offset=333 align=1 1 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 local.get 0 return end local.get 0 drop v128.const i32x4 0x04ef3aa8 0x144a0479 0x7d6f0c6b 0x86e20f80 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 return ) )Steps to Reproduce
- Run:
wasmtime -W all-proposals=y --invoke main test.wasmExpected Results
Based on wasmer (llvm backed), wamr (AOT mode), and wasmedge, the output is:
out of boundsexceptionActual Results
Wasmtime hangs indefinitely
Versions and Environment
Wasmtime version or commit: wasmtime 37.0.0 (3cbeb24bc 2025-08-06)
Operating system: Ubuntu 22.04
Architecture: x86_64
Extra Info
Can you please confirm? Thanks in advance.
cfallin closed issue #11391:
Test Case
wasm file: wasm-shrunken_test779339.txt
wat code:
(module (type (;0;) (func (result v128 v128 v128 v128 v128 v128 v128))) (memory (;0;) 65536 65536) (export "main" (func 0)) (func (;0;) (type 0) (result v128 v128 v128 v128 v128 v128 v128) (local v128) v128.const i32x4 0x269b302c 0x33ff2555 0x3d332eb9 0x6150b21b local.set 0 f32.const 0x1.91780cp+106 (;=127230580000000000000000000000000;) f32x4.splat local.get 0 local.get 0 i32x4.sub local.tee 0 drop local.get 0 local.get 0 local.get 0 local.get 0 i8x16.eq f64x2.min i32.const 1 i32x4.shr_s local.tee 0 f32x4.ne local.get 0 i32.const 1 i32x4.shr_s i64x2.sub local.get 0 i8x16.extract_lane_s 1 v128.load64_zero offset=4424 align=1 f32.const 0x1.abb8e2p+62 (;=7705158000000000000;) f32x4.splat i32.const 9009 v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 v128.store8_lane offset=818 0 local.get 0 local.get 0 drop local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 drop i32.const 1 if ;; label = @1 local.get 0 v128.const i32x4 0xd4913b28 0xfd94f22d 0x28f70108 0x2ee6c557 i8x16.ne local.set 0 local.get 0 local.set 0 local.get 0 local.set 0 loop ;; label = @2 i32.const 0 i32.const 0 v128.load8x8_s offset=7845 align=1 local.tee 0 drop i32.const 0 if (result v128) ;; label = @3 loop ;; label = @4 nop local.get 0 v128.const i32x4 0x4412d00e 0x91b9105c 0x3f5d100c 0x4888c991 i32x4.extmul_low_i16x8_s local.set 0 local.get 0 local.set 0 nop block ;; label = @5 i32.const 0 br_if 0 (;@5;) i32.const 0 br_if 0 (;@5;) nop local.get 0 local.set 0 end local.get 0 local.set 0 local.get 0 local.set 0 local.get 0 local.set 0 block ;; label = @5 block ;; label = @6 block ;; label = @7 block ;; label = @8 local.get 0 drop i32.const 0 br_table 1 (;@7;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 3 (;@5;) 2 (;@6;) 0 (;@8;) end i32.const 0 br_if 2 (;@5;) nop nop br 2 (;@5;) end local.get 0 local.set 0 local.get 0 local.set 0 local.get 0 local.get 0 f64x2.sub local.set 0 br 1 (;@5;) end nop local.get 0 drop local.get 0 v128.const i32x4 0x7d1f37e7 0x275466b3 0x4ed3def7 0x4ae48eda i32.const 0 select local.set 0 local.get 0 v128.const i32x4 0x6d311927 0x418c5fa1 0xfd0e4ac7 0x91fbcd1d local.get 0 drop i32.const 1 select local.set 0 end i32.const 0 local.get 0 v128.store16_lane offset=5390 align=1 0 nop nop local.get 0 drop i32.const 0 br_if 0 (;@4;) end i32.const 0 v128.load32_zero offset=1480 align=1 else local.get 0 end local.tee 0 v128.const i32x4 0xa3dc3f3f 0x11c29a13 0xba0ce1ed 0x49567075 i8x16.min_u local.tee 0 v128.store32_lane offset=9763 align=1 1 i32.const 1 br_if 0 (;@2;) end i32.const 7345 local.get 0 v128.store32_lane offset=4669 align=1 0 i32.const 1 local.get 0 v128.store64_lane offset=3353 align=1 1 end i32.const 0 local.get 0 local.tee 0 v128.store32_lane offset=9577 align=1 0 drop drop drop drop drop block ;; label = @1 block ;; label = @2 block ;; label = @3 i32.const 1 br_if 0 (;@3;) local.get 0 local.get 0 i64x2.bitmask v128.load8_splat offset=9328 f32x4.le drop i32.const 0 br_if 1 (;@2;) br 2 (;@1;) end local.get 0 drop i32.const 0 br_if 1 (;@1;) end i32.const 0 local.get 0 v128.store64_lane offset=333 align=1 1 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000 local.get 0 return end local.get 0 drop v128.const i32x4 0x04ef3aa8 0x144a0479 0x7d6f0c6b 0x86e20f80 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 local.get 0 return ) )Steps to Reproduce
- Run:
wasmtime -W all-proposals=y --invoke main test.wasmExpected Results
Based on wasmer (llvm backed), wamr (AOT mode), and wasmedge, the output is:
out of boundsexceptionActual Results
Wasmtime hangs indefinitely
Versions and Environment
Wasmtime version or commit: wasmtime 37.0.0 (3cbeb24bc 2025-08-06)
Operating system: Ubuntu 22.04
Architecture: x86_64
Extra Info
Can you please confirm? Thanks in advance.
fitzgen commented on issue #11391:
(We should probably have some documentation on "how to be a responsible citizen when fuzzing Wasmtime"...)
@cfallin yes, we really should, good idea. I can start whipping some initial docs up.
@teyahb8 a good place to start with regards to the above is https://blog.regehr.org/archives/2037
teyahb8 commented on issue #11391:
@cfallin @fitzgen Thanks for the helpful feedback. I appreciate the time and effort it takes to triage issues. I understand the frustration that can arise from receiving vague or low-effort reports (especially from fuzzing), but I want to stress that this was not submitted with bad intent or without care. I tried my best to reduce the test case from thousands of lines with
wasm-tools shrinkmodulo our time-budget (I can share the original test case, if you want to verify). But, I agree that further reduction was warranted to localize the issue. Thanks for steering the discussion in the right direction regardless.Your investigations clarified the root cause and have helped me better understand how NaN nondeterminism, variable stack size limits, and platform-specific behavior can influence Wasm execution. If these non-determinisms are well-documented somewhere, I will appreciate a pointer. Following in the footsteps of prior work, we are currently working on a research paper aimed at understanding how to build effective fuzzing infrastructure for WebAssembly runtimes, and this discussion has been both timely and insightful. So again, thank you for your time — and we welcome any constructive feedback as we move forward.
fitzgen commented on issue #11391:
I can start whipping some initial docs up.
PR adding docs for running responsible external fuzz campaigns in https://github.com/bytecodealliance/wasmtime/pull/11397
@teyahb8 please give that a once over and feel free to review and give feedback if anything is ambiguous or could be improved from your point of view. Thanks!
Thanks for the helpful feedback. I appreciate the time and effort it takes to triage issues. I understand the frustration that can arise from receiving vague or low-effort reports (especially from fuzzing), but I want to stress that this was not submitted with bad intent or without care. I tried my best to reduce the test case from thousands of lines with
wasm-tools shrinkmodulo our time-budget (I can share the original test case, if you want to verify). But, I agree that further reduction was warranted to localize the issue. Thanks for steering the discussion in the right direction regardless.For sure. We recognize that your intentions are good, we just need to make sure that this campaign becomes a positive experience for all parties involved :)
Your investigations clarified the root cause and have helped me better understand how NaN nondeterminism, variable stack size limits, and platform-specific behavior can influence Wasm execution. If these non-determinisms are well-documented somewhere, I will appreciate a pointer. Following in the footsteps of prior work, we are currently working on a research paper aimed at understanding how to build effective fuzzing infrastructure for WebAssembly runtimes, and this discussion has been both timely and insightful. So again, thank you for your time — and we welcome any constructive feedback as we move forward.
This page in our book documents how to tune Wasmtime for deterministic Wasm execution, which also lists various places that non-determinism can crop up. This is linked from the new docs I wrote up and linked the PR to above.
The
WebAssembly/designrepo also has a page on non-determinism.We also do fairly extensive fuzzing internally, including differential fuzzing between a variety of engines, so we have some helpers for checking whether an error is deterministic or not that might be useful for you:
- https://github.com/bytecodealliance/wasmtime/blob/4cbea5e8b8f4aafa91a1526995eb2361f1e5183e/crates/fuzzing/src/oracles.rs#L539
- https://github.com/search?q=repo%3Abytecodealliance%2Fwasmtime+is_non_deterministic_error&type=code
We also do some special configuration of Wasmtime specifically when doing differential fuzzing so that we get more-deterministic results across engines: https://github.com/bytecodealliance/wasmtime/blob/main/crates/fuzzing/src/generators/config.rs#L33
In general, I'd love to hear more about the new areas you are exploring with your research and give my perspective as a practitioner and maintainer. We do a lot of fuzzing already and have lots of ideas about how to further improve our fuzzing and things we wish were better exercised but aren't sure how best to do that, etc... If you don't want to discuss that kind of thing in this issue thread, fee free to either reach out on our Zulip chat or send me an email (email address in git log).
Thanks!
teyahb8 commented on issue #11391:
@fitzgen Thanks for sharing all these immensely helpful resources. I read your writeup and I think it sums up the expectations very well. Again, thanks for a productive response.
Last updated: Dec 06 2025 at 07:03 UTC