bytecodealliance / bytecodealliance/go-modules

Corrupted function argument of type list<list<string>>

Open
#348 5 comments 0 reactions 1 assignee Claimed by @ydnar View on GitHub
Dominant language
Go
Stars
148
Forks
20
PR merge metrics
No merged PRs in 30d

Description

### Description

```sh
echo "`wit-bindgen-go version` | `tinygo version` | `wasmtime --version` | `uname -m`"
wit-bindgen-go version v0.6.2 | tinygo version 0.37.0 darwin/arm64 (using go version go1.24.3 and LLVM version 19.1.2) | wasmtime 32.0.0 (d3054950c 2025-04-21) | arm64
```

A function argument of type `list>` is corrupted when passed between two components created using `wit-bindgen-go`.

The components, `host` and `guest`, target the WIT worlds defined below:
```
world guest {
... wasi imports ...

export foo: func(name: list>);
}
world host {
... wasi imports...

import foo: func(name: list>);

export wasi:cli/run@0.2.0;
}
```

Below is the implementation of `run` in `host`:
```go
func main() {
string0 := ...long string literal...
string1 := ...long string literal...

name0 := cm.ToList([]string{string0})
name1 := cm.ToList([]string{string1})

name := cm.ToList([]cm.List[string]{name0, name1})

println("Host:")

el0 := name.Slice()[0]
println("name[0]: len =", el0.Len(), "ptr =", el0.Data())

el1 := name.Slice()[1]
println("name[1]: len =", el1.Len(), "ptr =", el1.Data())

Host.Foo(name)
}
```
And the implementation of `foo` in `guest`:
```go
Guest.Exports.Foo = func(name cm.List[cm.List[string]]) {
println("Guest:")

el0 := name.Slice()[0]
println("name[0]: len =", el0.Len(), "ptr =", el0.Data())

el1 := name.Slice()[1]
println("name[1]: len =", el1.Len(), "ptr =", el1.Data())
}
```

Component Model bindings are generated using `wit-bindgen-go v0.6.2`. The components are compiled with TinyGo and executed with Wasmtime.

### Steps to reproduce

Here is a zipped directory that reproduces the bug: [test-case.zip](https://github.com/user-attachments/files/20236423/test-case.zip)

1. Unzip `test-case.zip`
2. `cd go-list-list-string`
3. Build and run with `./verify.sh`

### Expected behavior

The following message should be written to standard output:
```
Host:
name[0]: len = 0x00000001 ptr = ...
name[1]: len = 0x00000001 ptr = ...
Guest:
name[0]: len = 0x00000001 ptr = ...
name[1]: len = 0x00000001 ptr = ...
```

Specifically, the lengths printed by each component should be the same.

### Actual behavior

The length of `name[0]` printed by `guest` is incorrect.

I get the following output:
```
Host:
name[0]: len = 0x00000001 ptr = 0x0004f570
name[1]: len = 0x00000001 ptr = 0x0004f590
Guest:
name[0]: len = 0xc22490c3 ptr = 0x0d87c35d
name[1]: len = 0x00000001 ptr = 0x00027560
```

Notes:
- The string literals were reduced as much as possible in an earlier version of the test case, but can likely be further reduced in the attached test case.
- The buggy behavior disappears if `-gc leaking` is passed to TinyGo.

### Additional context

The Go programs are derived from a test case produced by a differential testing framework for WIT binding generators. The WIT definitions are derived from a test case produced by `wit-smith`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.