bytecodealliance / bytecodealliance/wit-bindgen

Rust: corrupted argument of function with signature func(record, record, u8, record)

Open
#1,134 2 comments 0 reactions 0 assignees View on GitHub
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.