Возврат строкового значения из Си в Go (CGO)
Изучаю внутренности runtime go и наткнулся на 2 интересные функции (первая и вторая). Решил применить, скопировав и изменив чуть чуть их. В итоге получилось вот что:
package main
// void *result() {
// return "test string";
// }
import "C"
import (
"runtime"
"strings"
"unsafe"
)
type stringStruct struct {
str unsafe.Pointer
len int
}
//go:nosplit
func findnull(ptr unsafe.Pointer) int {
const pageSize = 4096
offset := 0
safeLen := int(pageSize - uintptr(ptr)%pageSize)
for {
t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
if i := strings.IndexByte(t, 0); i != -1 {
return offset + i
}
ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
offset += safeLen
safeLen = pageSize
}
}
//go:nosplit
func gostringnocopy(ptr unsafe.Pointer) string {
s := stringStruct{str: ptr, len: findnull(ptr)}
return *(*string)(unsafe.Pointer(&s))
}
func main() {
pointer := C.result()
println(gostringnocopy(pointer))
runtime.KeepAlive(pointer)
}
Цель: попытаться избавиться от выделений malloc при возврате из сишной функции в го (как это происходит при вызове C.GoBytes() и т.д). Но голос внутри подсказывает что это не хорошо.
Скажите пожалуйста, возможно ли применять такой код без опасений со стороны GC (будет ли GC корректно с ним работать c учетом runtime.KeepAlive) ?
P.S. (go build -gcflags "-m -m") показывает 0 "escapes to heap", возможно GC здесь и нет работы))