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.

Reply via email to