Rust: corrupted argument of function with signature func(record, record, u8, record) #1134
Description
Description
echo "`wit-bindgen -V` | `rustc -V` | `wasmtime -V` | `uname -m`"
wit-bindgen-cli 0.37.0 | rustc 1.83.0 (90b35a623 2024-11-26) | wasmtime 28.0.1 (1bdf2c2b5 2025-01-14) | arm64
The value of a function argument is corrupted when a host component calls a function of a guest component. The signature of the function is foo: func(a: rec, b: rec, x4: u8, d: rec)
, where rec is defined as follows:
record rec {
x: s8,
f2: string,
}
The value of foo
's third argument, x4
, is corrupted and overwritten by the value of d.x
. The host and guest components are compiled from Rust source programs using the wit-bindgen
crate and the wasm32-wasip2
target. The two components implement the WIT worlds defined below:
package ns:pkg;
world guest {
record rec {
x: s8,
f2: string,
}
export foo: func(a: rec, b: rec, x4: u8, d: rec);
}
world host {
record rec {
x: s8,
f2: string,
}
import foo: func(a: rec, b: rec, x4: u8, d: rec);
export wasi:cli/[email protected];
}
package wasi:[email protected] {
interface run {
run: func() -> result;
}
}
Below are the Rust source programs of the host and guest components, respectively:
fn run() -> Result<(),()> {
let default_rec = Rec {
x: 0, // can be anything
f2: "".to_string(), // ^
};
let x4: u8 = 1; // this value should be printed, but isn't (can be anything)
let special_rec = Rec {
x: -1, // this field is magically converted to typeof(x4) and printed instead
f2: "".to_string(), // can be anything
};
println!("Sending: {x4}");
foo(
&default_rec,
&default_rec,
x4, // prints x4
&special_rec
);
Ok(())
}
fn foo(_a: Rec, _b: Rec, x4: u8, _d: Rec) {
println!("Received: {x4}");
}
Host and guest components are created from the source programs above using the Rust toolchain. The components are composed using wac
. The resulting component is executed by Wasmtime. The value of x4
is printed before and after being passed as an argument to foo
.
Steps to reproduce
Here is a zipped directory that reproduces the bug:
three_records_and_int_corruption.zip
- Unzip
three_records_and_int_corruption.zip
- Build and run with
./verify.sh
Expected behavior
The printed values should match:
Sending: 1
Received: 1
Actual behavior
The printed values don't match:
Sending: 1
Received: 255
Notes:
Various modifications to the test case eliminate the unexpected behavior. For example, renaming the fields of rec
, changing the number/types of foo
's parameters, or renaming foo
's third parameter can cause the printed values to match.
Additional context
The Rust source programs are derived from programs generated by a differential testing framework for wit-bindgen. The wit definitions are derived from a test case produced by wit-smith.