Skip to content

Commit 95995ce

Browse files
authored
fix: add defer pinner.Unpin() (#1613)
* fix: add defer pinner.Unpin() Signed-off-by: Andrew Steurer <94206073+asteurer@users.noreply.github.com> * feat: add test Signed-off-by: Andrew Steurer <94206073+asteurer@users.noreply.github.com> --------- Signed-off-by: Andrew Steurer <94206073+asteurer@users.noreply.github.com>
1 parent e4406d9 commit 95995ce

4 files changed

Lines changed: 58 additions & 1 deletion

File tree

crates/go/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,10 @@ func {camel}({go_params}) {go_results} {{
13261326

13271327
(
13281328
if abi::guest_export_needs_post_return(resolve, func) {
1329-
format!("{PINNER} := &runtime.Pinner{{}}")
1329+
format!(
1330+
"{PINNER} := &runtime.Pinner{{}}
1331+
defer {PINNER}.Unpin()"
1332+
)
13301333
} else {
13311334
String::new()
13321335
},
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ wasmtime-flags = '-Wcomponent-model-async'
2+
3+
package export_wit_world
4+
5+
import (
6+
"fmt"
7+
"runtime"
8+
9+
test "wit_component/my_test_i"
10+
)
11+
12+
/*
13+
14+
This tests for pinner leaks in generated Go code for async exported
15+
function that return heap-allocated types (strings, lists, etc.). Without
16+
`pinner.Unpin()`, the `runtime.Pinner` object goes out of scope after
17+
the function returns with pinned pointers still alive. When GC finalizes
18+
the Pinner, it panics:
19+
20+
```
21+
panic: runtime error: runtime.Pinner: found leaking pinned pointer;
22+
forgot to call Unpin()?
23+
```
24+
*/
25+
26+
func Run() {
27+
// Perform a heap allocation
28+
got := test.ReturnString()
29+
if got != "hello" {
30+
panic(fmt.Sprintf("expected \"hello\", got %q", got))
31+
}
32+
33+
// Force GC to finalize any leaked Pinners
34+
runtime.GC()
35+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package export_my_test_i
2+
3+
func ReturnString() string {
4+
return "hello"
5+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package my:test;
2+
3+
interface i {
4+
return-string: async func() -> string;
5+
}
6+
7+
world test {
8+
export i;
9+
}
10+
11+
world runner {
12+
import i;
13+
export run: async func();
14+
}

0 commit comments

Comments
 (0)