detached e5b87e9

document memory usage for RegisterFunc (#154)

commit
e5b87e976b386838bf71ee85f2eb03f753bae8b9
author
TotallyGamerJet · · 2023-08-24 23:35 UTC
committer
GitHub · · 2023-08-24 23:35 UTC
parent
1a4ea67
signature
GPG Unverified4AEE18F83AFDEB23 The key is unknown
1 file · +38 -1
M func.go +38 -1
@@ -35,7 +35,7 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
3535 // matches the C function. This also holds true for struct types where the padding
3636 // needs to be ensured to match that of C; RegisterFunc does not verify this.
3737 //
38-// Type Conversions (Go => C)
38+// # Type Conversions (Go <=> C)
3939 //
4040 // string <=> char*
4141 // bool <=> _Bool
@@ -65,6 +65,43 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
6565 // There are some limitations when using RegisterFunc on Linux. First, there is no support for function arguments.
6666 // Second, float32 and float64 arguments and return values do not work when CGO_ENABLED=1. Otherwise, Linux
6767 // has the same feature parity as Darwin.
68+//
69+// # Memory
70+//
71+// In general it is not possible for purego to guarantee the lifetimes of objects returned or received from
72+// calling functions using RegisterFunc. For arguments to a C function is it important that the C function doesn't
73+// hold onto a reference to Go memory. This is the same as the [Cgo rules].
74+//
75+// However, there are some special cases. When passing a string as an argument if the string does not end in a null
76+// terminated byte (\x00) then the string will be copied into memory maintained by purego. The memory is only valid for
77+// that specific call. Therefore, if the C code keeps a reference to that string it may become invalid at some
78+// undefined time. However, if the string does already contain a null-terminated byte then no copy is done.
79+// It is then the responsibility of the caller to ensure the string stays alive as long as it's needed in C memory.
80+// This can be done using runtime.KeepAlive or allocating the string in C memory using malloc. When a C function
81+// returns a null-terminated pointer to char a Go string can be used. Purego will allocate a new string in Go memory
82+// and copy the data over. This string will be garbage collected whenever Go decides it's no longer referenced.
83+// This C created string will not be freed by purego. If the pointer to char is not null-terminated or must continue
84+// to point to C memory (because it's a buffer for example) then use a pointer to byte and then convert that to a slice
85+// using unsafe.Slice. Doing this means that it becomes the responsibility of the caller to care about the lifetime
86+// of the pointer
87+//
88+// # Example
89+//
90+// All functions below call this C function:
91+//
92+// char *foo(char *str);
93+//
94+// // Let purego convert types
95+// var foo func(s string) string
96+// goString := foo("copied")
97+// // Go will garbage collect this string
98+//
99+// // Manually, handle allocations
100+// var foo2 func(b string) *byte
101+// mustFree := foo2("not copied\x00")
102+// defer free(mustFree)
103+//
104+// [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C
68105 func RegisterFunc(fptr interface{}, cfn uintptr) {
69106 fn := reflect.ValueOf(fptr).Elem()
70107 ty := fn.Type()
@@ -35,7 +35,7 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
35 // matches the C function. This also holds true for struct types where the padding35 // matches the C function. This also holds true for struct types where the padding
36 // needs to be ensured to match that of C; RegisterFunc does not verify this.36 // needs to be ensured to match that of C; RegisterFunc does not verify this.
37 //37 //
38-// Type Conversions (Go => C)38+// # Type Conversions (Go <=> C)
39 //39 //
40 // string <=> char*40 // string <=> char*
41 // bool <=> _Bool41 // bool <=> _Bool
@@ -65,6 +65,43 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
65 // There are some limitations when using RegisterFunc on Linux. First, there is no support for function arguments.65 // There are some limitations when using RegisterFunc on Linux. First, there is no support for function arguments.
66 // Second, float32 and float64 arguments and return values do not work when CGO_ENABLED=1. Otherwise, Linux66 // Second, float32 and float64 arguments and return values do not work when CGO_ENABLED=1. Otherwise, Linux
67 // has the same feature parity as Darwin.67 // has the same feature parity as Darwin.
68+//
69+// # Memory
70+//
71+// In general it is not possible for purego to guarantee the lifetimes of objects returned or received from
72+// calling functions using RegisterFunc. For arguments to a C function is it important that the C function doesn't
73+// hold onto a reference to Go memory. This is the same as the [Cgo rules].
74+//
75+// However, there are some special cases. When passing a string as an argument if the string does not end in a null
76+// terminated byte (\x00) then the string will be copied into memory maintained by purego. The memory is only valid for
77+// that specific call. Therefore, if the C code keeps a reference to that string it may become invalid at some
78+// undefined time. However, if the string does already contain a null-terminated byte then no copy is done.
79+// It is then the responsibility of the caller to ensure the string stays alive as long as it's needed in C memory.
80+// This can be done using runtime.KeepAlive or allocating the string in C memory using malloc. When a C function
81+// returns a null-terminated pointer to char a Go string can be used. Purego will allocate a new string in Go memory
82+// and copy the data over. This string will be garbage collected whenever Go decides it's no longer referenced.
83+// This C created string will not be freed by purego. If the pointer to char is not null-terminated or must continue
84+// to point to C memory (because it's a buffer for example) then use a pointer to byte and then convert that to a slice
85+// using unsafe.Slice. Doing this means that it becomes the responsibility of the caller to care about the lifetime
86+// of the pointer
87+//
88+// # Example
89+//
90+// All functions below call this C function:
91+//
92+// char *foo(char *str);
93+//
94+// // Let purego convert types
95+// var foo func(s string) string
96+// goString := foo("copied")
97+// // Go will garbage collect this string
98+//
99+// // Manually, handle allocations
100+// var foo2 func(b string) *byte
101+// mustFree := foo2("not copied\x00")
102+// defer free(mustFree)
103+//
104+// [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C
68 func RegisterFunc(fptr interface{}, cfn uintptr) {105 func RegisterFunc(fptr interface{}, cfn uintptr) {
69 fn := reflect.ValueOf(fptr).Elem()106 fn := reflect.ValueOf(fptr).Elem()
70 ty := fn.Type()107 ty := fn.Type()

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close