bytecodealliance / bytecodealliance/wit-bindgen
Rust: corrupted argument of function with signature func(record, record, u8, record)
- Dominant language
- Rust
- Stars
- 1.5k
- Forks
- 286
- Avg merge
- 6h 32m
- Merged PRs (30d)
- 19
Description
### Description
```sh
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/run@0.2.0;
}
package wasi:cli@0.2.0 {
interface run {
run: func() -> result;
}
}
```
Below are the Rust source programs of the host and guest components, respectively:
```rust
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(())
}
```
```rust
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](https://github.com/user-attachments/files/18462500/three_records_and_int_corruption.zip)
1. Unzip `three_records_and_int_corruption.zip`
2. 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.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.