Stream: git-wasmtime

Topic: wasmtime / issue #10418 differential fuzzbug: Wide arithm...


view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 11:44):

saulecabrera added the fuzz-bug label to Issue #10418.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 11:44):

saulecabrera added the bug label to Issue #10418.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 11:44):

saulecabrera opened issue #10418:

For the following program:

(module
  (type (;0;) (func (param i32) (result i64)))
  (global (;0;) (mut i32) i32.const 0)
  (global (;1;) (mut i64) i64.const 0)
  (global (;2;) (mut i32) i32.const 0)
  (export " " (func 0))
  (func (;0;) (type 0) (param i32) (result i64)
    i32.const 0
    if ;; label = @1
      unreachable
    end
    global.get 2
    global.set 2
    i64.const 288230376151711744
    i64.const 288230376151711744
    i64.mul_wide_s
    i32.wrap_i64
    global.get 0
    i32.xor
    global.set 0
    global.get 1
    i64.xor
  )
)

When invoked via:

cargo run -- run -Wwide-arithmetic=y --invoke " " index.wat 0

The result, using -Ccompiler=cranelift or -Ccompiler=winch or --target=pulley64 is consistently the same: 0. However, when invoked via:

wasm_cli --invoke " " index.wat 0

The result is 4503599627370496

Reducing a bit further, it seems the the problem is the ordering of the return values from i64.mul_wide_s

Consider:

(module
  (type (;0;) (func (param i32) (result i64)))
  (global (;0;) (mut i32) i32.const 0)
  (global (;1;) (mut i64) i64.const 0)
  (global (;2;) (mut i32) i32.const 0)
  (export " " (func 0))
  (func (;0;) (type 0) (param i32) (result i64)
    i32.const 0
    if ;; label = @1
      unreachable
    end
    global.get 2
    global.set 2
    i64.const 288230376151711744
    i64.const 288230376151711744
    i64.mul_wide_s
    drop
  )
)

The result for Wasmtime (using any of the compilers or pulley) is: 0.
Using wasmi the result is: 4503599627370496

Which clearly suggests that there's a discrepancy on how the results of i64.mul_wide_s are handled in wasmi. According to the consistent results in Wasmtime, I'm tempted to suggest that this probably a bug in wasmi itself, however, I'm opening this issue here first for confirmation.

cc @alexcrichton @Robbepop

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 11:46):

Robbepop commented on issue #10418:

Since the wide-arithmetic support in Wasmi is fairly new it likely is a bug in Wasmi. Going to inspect it as soon as I find time.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 11:46):

saulecabrera edited issue #10418:

For the following program:

(module
  (type (;0;) (func (param i32) (result i64)))
  (global (;0;) (mut i32) i32.const 0)
  (global (;1;) (mut i64) i64.const 0)
  (global (;2;) (mut i32) i32.const 0)
  (export " " (func 0))
  (func (;0;) (type 0) (param i32) (result i64)
    i32.const 0
    if ;; label = @1
      unreachable
    end
    global.get 2
    global.set 2
    i64.const 288230376151711744
    i64.const 288230376151711744
    i64.mul_wide_s
    i32.wrap_i64
    global.get 0
    i32.xor
    global.set 0
    global.get 1
    i64.xor
  )
)

When invoked via:

cargo run -- run -Wwide-arithmetic=y --invoke " " index.wat 0

The result, using -Ccompiler=cranelift or -Ccompiler=winch or --target=pulley64 is consistently the same: 0. However, when invoked via:

wasmi_cli --invoke " " index.wat 0

The result is 4503599627370496

Reducing a bit further, it seems the the problem is the ordering of the return values from i64.mul_wide_s

Consider:

(module
  (type (;0;) (func (param i32) (result i64)))
  (global (;0;) (mut i32) i32.const 0)
  (global (;1;) (mut i64) i64.const 0)
  (global (;2;) (mut i32) i32.const 0)
  (export " " (func 0))
  (func (;0;) (type 0) (param i32) (result i64)
    i32.const 0
    if ;; label = @1
      unreachable
    end
    global.get 2
    global.set 2
    i64.const 288230376151711744
    i64.const 288230376151711744
    i64.mul_wide_s
    drop
  )
)

The result for Wasmtime (using any of the compilers or pulley) is: 0.
Using wasmi the result is: 4503599627370496

Which clearly suggests that there's a discrepancy on how the results of i64.mul_wide_s are handled in wasmi. According to the consistent results in Wasmtime, I'm tempted to suggest that this probably a bug in wasmi itself, however, I'm opening this issue here first for confirmation.

cc @alexcrichton @Robbepop

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 11:50):

Robbepop edited a comment on issue #10418:

Since the wide-arithmetic support in Wasmi is fairly new it likely is a bug in Wasmi. Going to inspect it as soon as I find time.
From my understanding the drop instructions drops the high 64-bits of the result.
288230376151711744^2 ~= 8,30767497e34 and 8,30767497e34 / 2^64 = 4503599627370496

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 11:51):

Robbepop edited a comment on issue #10418:

Since the wide-arithmetic support in Wasmi is fairly new it likely is a bug in Wasmi. Going to inspect it as soon as I find time.

From my understanding the drop instructions drops the high 64-bits of the result.
288230376151711744^2 ~= 8,30767497e34 and 8,30767497e34 / 2^64 = 4503599627370496

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 14:28):

alexcrichton commented on issue #10418:

@Robbepop this program:

fn main() {
    let a = 288230376151711744_i64;
    let b = 288230376151711744_i64;
    println!("{a} * {b} = {}", a.wrapping_mul(b));
    println!("{a:#x} * {b:#x} = {:#x}", a.wrapping_mul(b));
    let a = i128::from(a);
    let b = i128::from(b);
    println!("{a} * {b} = {}", a.wrapping_mul(b));
    println!("{a:#x} * {b:#x} = {:#x}", a.wrapping_mul(b));
}

prints

288230376151711744 * 288230376151711744 = 0
0x400000000000000 * 0x400000000000000 = 0x0
288230376151711744 * 288230376151711744 = 83076749736557242056487941267521536
0x400000000000000 * 0x400000000000000 = 0x100000000000000000000000000000

so I think it's expected that the low bits are all zero?

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 14:45):

Robbepop commented on issue #10418:

@alexcrichton indeed, it seems that Wasmi const-eval for wide-arithmetic is off here. Sorry about that!

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2025 at 15:07):

alexcrichton closed issue #10418:

For the following program:

(module
  (type (;0;) (func (param i32) (result i64)))
  (global (;0;) (mut i32) i32.const 0)
  (global (;1;) (mut i64) i64.const 0)
  (global (;2;) (mut i32) i32.const 0)
  (export " " (func 0))
  (func (;0;) (type 0) (param i32) (result i64)
    i32.const 0
    if ;; label = @1
      unreachable
    end
    global.get 2
    global.set 2
    i64.const 288230376151711744
    i64.const 288230376151711744
    i64.mul_wide_s
    i32.wrap_i64
    global.get 0
    i32.xor
    global.set 0
    global.get 1
    i64.xor
  )
)

When invoked via:

cargo run -- run -Wwide-arithmetic=y --invoke " " index.wat 0

The result, using -Ccompiler=cranelift or -Ccompiler=winch or --target=pulley64 is consistently the same: 0. However, when invoked via:

wasmi_cli --invoke " " index.wat 0

The result is 4503599627370496

Reducing a bit further, it seems the the problem is the ordering of the return values from i64.mul_wide_s

Consider:

(module
  (type (;0;) (func (param i32) (result i64)))
  (global (;0;) (mut i32) i32.const 0)
  (global (;1;) (mut i64) i64.const 0)
  (global (;2;) (mut i32) i32.const 0)
  (export " " (func 0))
  (func (;0;) (type 0) (param i32) (result i64)
    i32.const 0
    if ;; label = @1
      unreachable
    end
    global.get 2
    global.set 2
    i64.const 288230376151711744
    i64.const 288230376151711744
    i64.mul_wide_s
    drop
  )
)

The result for Wasmtime (using any of the compilers or pulley) is: 0.
Using wasmi the result is: 4503599627370496

Which clearly suggests that there's a discrepancy on how the results of i64.mul_wide_s are handled in wasmi. According to the consistent results in Wasmtime, I'm tempted to suggest that this probably a bug in wasmi itself, however, I'm opening this issue here first for confirmation.

cc @alexcrichton @Robbepop

view this post on Zulip Wasmtime GitHub notifications bot (Mar 20 2025 at 08:09):

Robbepop commented on issue #10418:

@saulecabrera @alexcrichton The bug has been fixed in Wasmi yesterday and today I released Wasmi v0.42.1 that includes this fix. So technically Wasmtime fuzzing could use v0.42.1 again with wide-arithmetic enabled if you feel like it makes sense. Not sure so I didn't create a PR, yet.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 20 2025 at 08:09):

Robbepop edited a comment on issue #10418:

@saulecabrera @alexcrichton The bug has been fixed in Wasmi yesterday and today I released Wasmi v0.42.1 that includes this fix. So technically Wasmtime fuzzing could use v0.42.1 again with wide-arithmetic enabled if you feel like it makes sense. Not sure so I didn't create a PR, yet.

The fix was trivial: https://github.com/wasmi-labs/wasmi/pull/1397

view this post on Zulip Wasmtime GitHub notifications bot (Mar 20 2025 at 14:55):

alexcrichton commented on issue #10418:

Thanks! Opened up https://github.com/bytecodealliance/wasmtime/pull/10430 to re-enable


Last updated: Apr 17 2025 at 10:03 UTC