> On Oct 17, 2016, at 5:03 PM, andrew.sm...@miracl.com wrote:
> 
> Hi,
> 
> When using cgo its my understanding that strings created with C.CString must 
> be freed with C.free, but yet numeric types do not need to be explicitly 
> freed.

Yes. This is because strings in C are not first class objects like they are in 
Go. In C, a string is an array of bytes that ends with a byte whose value is 0, 
represented as '\0' in C and '\000' in Go.

When you create a string using the "..." syntax, the string is made part of the 
executable data. You cannot legally modify these strings, and they do not need 
to be freed. All other strings need to be stored in a buffer large enough for 
all those bytes (plus the extra null byte). This is analogous to manipulating a 
slice in Go. If the string is created at compile time (such as being stored in 
a char[512] or so), you don't have to worry about managing the memory. But a 
string created at runtime must be explicitly allocated, and since C does not 
have a garbage collector, must be explicitly freed as well.

> 
> Firstly, is CString a special case here, or are there other types that need 
> to be explicitly freed as well?

C.CString() is the most obvious case. C.CBytes() (new in 1.7) also counts, as 
does anything else allocated with the standard C malloc(), calloc(), and 
realloc() functions, either directly or indirectly.

> 
> Secondly, Im writing a lot of wrappers to cgo functions that will requiring 
> converting go 'string' arguments in the outer function, into C.String 
> arguments in the cgo inner function. Im looking for a simple way to ensure 
> that I dont create any memory leaks. In view of this I have an idea to wrap 
> the CString in a go struct and set the finalizer to free the CString :
> 
> // -------------------------------------- wrapped.go 
> --------------------------------------
> 
> package golasso
> 
> import (
>         // #include <stdlib.h>
>         "C"
>         "fmt"
>         "runtime"
>         "unsafe"
> )
> 
> type WrappedString struct {
>         s *C.char
> }
> 
> func FreeWrappedString(s *WrappedString) {
>         fmt.Print("Freeing WrappedString")
>         C.free(unsafe.Pointer(s.s))
> }
> 
> func NewWrappedString(s string) WrappedString {
>         wrappedString := WrappedString{s: C.CString(s)}
>         runtime.SetFinalizer(&wrappedString, FreeWrappedString)
>         return wrappedString
> }
> 
> 
> // --------------------------------------
> 
> func simulatedCCall(s *C.char) {
> 
>         fmt.Print("simulated C call")
> 
> }
> 
> // -------------------------------------- wrapped_test.go 
> --------------------------------------
> package golasso
> 
> import (
>         "runtime"
>         "testing"
> )
> 
> func TestWrapped(t *testing.T) {
>         simulatedCCall(NewWrappedString("fred").s)
>         t.Logf("simulated C call")
>         runtime.GC()
> }
> 
> 
> 
> 
> 
> 

I'm not sure what your question is. Idiomatic cgo code just uses defer though:

        cstr := C.CString(str)
        defer C.free(unsafe.Pointer(cstr))

> NB: I do realise that, in a production scenario, it might be a long time 
> before the GC runs and therefore a long time before the GC calls the 
> finalizer to free the CString. Im not so worried about this, as my primary 
> concern is ensuring that *every* CString is definitely going to be freed at 
> some point, and therefore I have no *true* memory leaks.
> 
> What are the pros/cons of this? Is it even correct? Is there an easier way to 
> achieve this?
> 

Finalizers are not guaranteed to run, even during a garbage collect. You may 
accidentally be letting your C string escape to the heap without knowing it. 
I'm not sure why we even have finalizers, or why they're public API.

Exposing C strings outside your package isn't really a good idea anyway. 
Convert when necessary to keep things safer.

> Andy
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to golang-nuts+unsubscr...@googlegroups.com 
> <mailto:golang-nuts+unsubscr...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout 
> <https://groups.google.com/d/optout>.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to