examples(allocation): free memory after unmarshalling a result from the guest (#1390)

Signed-off-by: Luca Burgazzoli <lburgazzoli@gmail.com>
This commit is contained in:
Luca Burgazzoli
2023-05-03 01:01:05 +02:00
committed by GitHub
parent c5871c772c
commit b2c11d8dfd
6 changed files with 42 additions and 11 deletions

View File

@@ -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.

View File

@@ -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",

View File

@@ -1,5 +1,8 @@
package main
// #include <stdlib.h>
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))
}

Binary file not shown.