Возврат строкового значения из Си в 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 здесь и нет работы))


Ответы (0 шт):