From 2ad486f0b01e2221872e1e2c116ad292b47a4a28 Mon Sep 17 00:00:00 2001 From: Luca Burgazzoli Date: Tue, 2 May 2023 14:14:40 +0200 Subject: [PATCH] examples(allocation): free memory after unmarshalling a result from the guest --- examples/allocation/tinygo/README.md | 2 +- examples/allocation/tinygo/greet.go | 14 +++++++++++++- examples/allocation/tinygo/testdata/greet.go | 17 ++++++++++++++++- .../allocation/tinygo/testdata/greet.wasm | Bin 54293 -> 54254 bytes .../integration_test/vs/bench_allocation.go | 17 +++++++++++------ internal/integration_test/vs/runtime.go | 3 +-- 6 files changed, 42 insertions(+), 11 deletions(-) diff --git a/examples/allocation/tinygo/README.md b/examples/allocation/tinygo/README.md index 7e2f9cbcd74..6e340f265b6 100644 --- a/examples/allocation/tinygo/README.md +++ b/examples/allocation/tinygo/README.md @@ -12,6 +12,6 @@ go >> Hello, wazero! Under the covers, [greet.go](testdata/greet.go) does a few things of interest: * Uses `unsafe.Pointer` to change a Go pointer to a numeric type. * Uses `reflect.StringHeader` to build back a string from a pointer, len pair. -* Relies on TinyGo not eagerly freeing pointers returned. +* Relies on CGO to allocate memory used to pass data from TinyGo to host. See https://wazero.io/languages/tinygo/ for more tips. diff --git a/examples/allocation/tinygo/greet.go b/examples/allocation/tinygo/greet.go index 09e1831b017..22d76d64c5c 100644 --- a/examples/allocation/tinygo/greet.go +++ b/examples/allocation/tinygo/greet.go @@ -90,9 +90,21 @@ func main() { if err != nil { log.Panicln(err) } - // Note: This pointer is still owned by TinyGo, so don't try to free it! + greetingPtr := uint32(ptrSize[0] >> 32) greetingSize := uint32(ptrSize[0]) + + // This pointer is managed by TinyGo, but TinyGo is unaware of external usage. + // So, we have to free it when finished + if greetingPtr != 0 { + defer func() { + _, err := free.Call(ctx, uint64(greetingPtr)) + if err != nil { + log.Panicln(err) + } + }() + } + // The pointer is a linear memory offset, which is where we write the name. if bytes, ok := mod.Memory().Read(greetingPtr, greetingSize); !ok { log.Panicf("Memory.Read(%d, %d) out of range of memory size %d", diff --git a/examples/allocation/tinygo/testdata/greet.go b/examples/allocation/tinygo/testdata/greet.go index d858ab38fe2..2eb717d5652 100644 --- a/examples/allocation/tinygo/testdata/greet.go +++ b/examples/allocation/tinygo/testdata/greet.go @@ -1,5 +1,8 @@ package main +// #include +import "C" + import ( "fmt" "reflect" @@ -53,7 +56,7 @@ func _greet(ptr, size uint32) { func _greeting(ptr, size uint32) (ptrSize uint64) { name := ptrToString(ptr, size) g := greeting(name) - ptr, size = stringToPtr(g) + ptr, size = stringToLeakedPtr(g) return (uint64(ptr) << uint64(32)) | uint64(size) } @@ -77,3 +80,15 @@ func stringToPtr(s string) (uint32, uint32) { unsafePtr := uintptr(unsafe.Pointer(ptr)) return uint32(unsafePtr), uint32(len(buf)) } + +// stringToLeakedPtr returns a pointer and size pair for the given string in a way +// compatible with WebAssembly numeric types. The pointer is not automatically +// managed by TinyGo hence it must be freed by the host. +func stringToLeakedPtr(s string) (uint32, uint32) { + size := C.ulong(len(s)) + ptr := unsafe.Pointer(C.malloc(size)) + + copy(unsafe.Slice((*byte)(ptr), size), []byte(s)) + + return uint32(uintptr(ptr)), uint32(len(s)) +} diff --git a/examples/allocation/tinygo/testdata/greet.wasm b/examples/allocation/tinygo/testdata/greet.wasm index 12efdc1fa2d4b444f1412f4f9de54c0a6d3a6159..6a7fa97869035863d6a1e667bc231392334ce9b9 100755 GIT binary patch delta 4487 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 m>(k9wPF! 0 { + } else { return results[0], nil } - return 0, nil } func (m *wazeroModule) WriteMemory(offset uint32, bytes []byte) error {