Thanks very much for your replies. I guess the killer argument is that finalizers are not guaranteed to run! I didnt know that. Just to be clear, Im not intending exposing WrappedString to my clients only standard go strings, everything *should* be freed up when my outer wrapper function exits (e.g. using defer), but there is definitely a high chance of forgetting one of these at some point.
I did start out planning to use the defer approach and trying to find a way to simplify writing these wrappers and avoid memory leaks through programmer error. On the defer approach. Is there any way, in a unit test to check that all CString objects have been freed? e.g. Can I get a list of all existing CString objects and walk it somehow? Thanks again, Andy On Monday, October 17, 2016 at 11:40:24 PM UTC+1, Pietro Gagliardi (andlabs) wrote: > > > On Oct 17, 2016, at 5:03 PM, andrew...@miracl.com <javascript:> 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...@googlegroups.com <javascript:>. > For more options, visit 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.