examples: switches tinygo example to use slice header (#524)

We get undefined behavior, at least in code that re-slices, unless
capacity is set. This ensures the buffer under the string has a capacity
set to the same length as its size. This also shows more explicitly the
problems in TinyGo (ex some type mismatch you have to ignore until
fixed).

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2022-05-04 19:14:04 +08:00
committed by GitHub
parent 72f16d21eb
commit a47cb700ad
3 changed files with 9 additions and 8 deletions

View File

@@ -56,13 +56,14 @@ func _greeting(ptr, size uint32) (ptrSize uint64) {
// ptrToString returns a string from WebAssembly compatible numeric types // ptrToString returns a string from WebAssembly compatible numeric types
// representing its pointer and length. // representing its pointer and length.
func ptrToString(ptr uint32, size uint32) (ret string) { func ptrToString(ptr uint32, size uint32) string {
// Here, we want to get a string represented by the ptr and size. If we // Get a slice view of the underlying bytes in the stream. We use SliceHeader, not StringHeader
// wanted a []byte, we'd use reflect.SliceHeader instead. // as it allows us to fix the capacity to what was allocated.
strHdr := (*reflect.StringHeader)(unsafe.Pointer(&ret)) return *(*string)(unsafe.Pointer(&reflect.SliceHeader{
strHdr.Data = uintptr(ptr) Data: uintptr(ptr),
strHdr.Len = uintptr(size) Len: uintptr(size), // Tinygo requires these as uintptrs even if they are int fields.
return Cap: uintptr(size), // ^^ See https://github.com/tinygo-org/tinygo/issues/1284
}))
} }
// stringToPtr returns a pointer and size pair for the given string in a way // stringToPtr returns a pointer and size pair for the given string in a way

Binary file not shown.

View File

@@ -15,7 +15,7 @@ import (
// loggerFactory implements experimental.FunctionListenerFactory to log all function calls to the console. // loggerFactory implements experimental.FunctionListenerFactory to log all function calls to the console.
type loggerFactory struct{} type loggerFactory struct{}
// Size implements the same method as documented on api.Memory. // NewListener implements the same method as documented on experimental.FunctionListener.
func (f *loggerFactory) NewListener(fnd experimental.FunctionDefinition) experimental.FunctionListener { func (f *loggerFactory) NewListener(fnd experimental.FunctionDefinition) experimental.FunctionListener {
return &logger{funcName: []byte(fnd.ModuleName() + "." + funcName(fnd))} return &logger{funcName: []byte(fnd.ModuleName() + "." + funcName(fnd))}
} }