|
| @@ -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 padding | 35 | | // 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 <=> _Bool | 41 | | // 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, Linux | 66 | | // 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() |