cgo, GoSlice/GoString from C

1,437 views
Skip to first unread message

Luke Scott

unread,
Sep 4, 2013, 1:54:27 PM9/4/13
to golan...@googlegroups.com
When calling a Go function from C, I need to construct a GoSlice or GoString. _cgo_export.h (on tip) defines these, as well GoInterface, as:

typedef struct { char *p; int n; } GoString;
typedef struct { void *data; int len; int cap; } GoSlice;
typedef struct { void *t; void *v; } GoInterface;

I've been able to successfully construct a GoSlice pass it into the Go function without problems.

Who is responsible for clearing "char *p" or "void *data"? If I am responsible, when? Where - from C free(), or from Go C.free()? After the function call? Does Go make a copy of the memory?

If GoString and GoSlice is allocated to the heap instead of the C function stack, do I need to clear this as well? What if I have a []string that needs to be constructed?

Lastly, how do I construct a []interface{}? The []interface{} needs to contain string, int, uint, bool, and C.object. Would I be better off using unsafe.Pointer with uintptr to transverse the "array" of items (using a union struct, or something)?

Luke

Gustavo Niemeyer

unread,
Sep 4, 2013, 2:05:18 PM9/4/13
to Luke Scott, golan...@googlegroups.com
On Wed, Sep 4, 2013 at 2:54 PM, Luke Scott <lu...@visionlaunchers.com> wrote:
> Who is responsible for clearing "char *p" or "void *data"? If I am
> responsible, when? Where - from C free(), or from Go C.free()? After the
> function call? Does Go make a copy of the memory?

It depends on who allocated the memory.

If Go allocated the memory, it is in an area managed by the garbage
collector, and thus it will be deallocated automatically at some point
after the last reference in Go land is dead. That means you cannot
trust the string to be alive in C land, unless you're sure there's a
reference in Go land to the same string.

If C allocated the memory, it must be explicitly freed. That said, Go
has no idea about whether the memory is there or not.. it will simply
trust it to be there for as long as the string is alive, because
that's the normal behavior with strings it allocates internally. If
you explicitly free the memory backing the string while there is still
a references to in Go land, the program will crash or misbehave
arbitrarily when the string is touched again (and people will be very
angry :-).

Note that this is very implementation dependent. Although these
details are unlikely to change imminently, they can change without
much notice.

> If GoString and GoSlice is allocated to the heap instead of the C function
> stack, do I need to clear this as well? What if I have a []string that needs
> to be constructed?

The details are similar to the above.

> Lastly, how do I construct a []interface{}? The []interface{} needs to
> contain string, int, uint, bool, and C.object. Would I be better off using
> unsafe.Pointer with uintptr to transverse the "array" of items (using a
> union struct, or something)?

I would do that from Go instead of doing it from C.


gustavo @ http://niemeyer.net

Luke Scott

unread,
Sep 4, 2013, 2:21:54 PM9/4/13
to golan...@googlegroups.com, Luke Scott
On Wednesday, September 4, 2013 11:05:18 AM UTC-7, Gustavo Niemeyer wrote:
On Wed, Sep 4, 2013 at 2:54 PM, Luke Scott <lu...@visionlaunchers.com> wrote:
> Who is responsible for clearing "char *p" or "void *data"? If I am
> responsible, when? Where - from C free(), or from Go C.free()? After the
> function call? Does Go make a copy of the memory?

It depends on who allocated the memory.

If Go allocated the memory, it is in an area managed by the garbage
collector, and thus it will be deallocated automatically at some point
after the last reference in Go land is dead. That means you cannot
trust the string to be alive in C land, unless you're sure there's a
reference in Go land to the same string.

If C allocated the memory, it must be explicitly freed. That said, Go
has no idea about whether the memory is there or not.. it will simply
trust it to be there for as long as the string is alive, because
that's the normal behavior with strings it allocates internally. If
you explicitly free the memory backing the string while there is still
a references to in Go land, the program will crash or misbehave
arbitrarily when the string is touched again (and people will be very
angry :-).

I'm calling a Go function from C. In other words the Go function has //export above it and C is calling it. The parameters of that Go function is exported as a GoSlice and/or GoString type. I need to satisfy these arguments.
 
Note that this is very implementation dependent. Although these
details are unlikely to change imminently, they can change without
much notice.

Not too much of a concern as there isn't a lot of code for me to change. I just need to know how to handle it today.
 
> If GoString and GoSlice is allocated to the heap instead of the C function
> stack, do I need to clear this as well? What if I have a []string that needs
> to be constructed?

The details are similar to the above.

> Lastly, how do I construct a []interface{}? The []interface{} needs to
> contain string, int, uint, bool, and C.object. Would I be better off using
> unsafe.Pointer with uintptr to transverse the "array" of items (using a
> union struct, or something)?

I would do that from Go instead of doing it from C.

I'm calling a Go function from C. I need to get a dynamic list of arbitrary types to Go from C.

So if I create a GoSlice backed by a void*, if I free() that void* then Go no longer has access to it. Go will also not clear that memory. If I am passing it by value, will Go make a copy of it if I pass it into another Go function? I'm assuming that I probably should not take a pointer from these C created Go values.

My other option is to pass an array pointer of a C struct that contains a type and do some pointer arithmetic by converting unsafe.Pointer to uintptr.

What is the best approach for what I'm trying to do?

Luke

Gustavo Niemeyer

unread,
Sep 4, 2013, 2:30:09 PM9/4/13
to Luke Scott, golan...@googlegroups.com
On Wed, Sep 4, 2013 at 3:21 PM, Luke Scott <lu...@visionlaunchers.com> wrote:
> I'm calling a Go function from C. In other words the Go function has
> //export above it and C is calling it. The parameters of that Go function is
> exported as a GoSlice and/or GoString type. I need to satisfy these
> arguments.

What I generally do is to declare the Go function in a more C-friendly way.

For example:

//export doSomething
func doSomething(cstr *C.char, clen C.int) {
gostr := C.GoStringN(cstr, clen)
}

This way the Go string is allocated and managed by Go itself.

> I'm calling a Go function from C. I need to get a dynamic list of arbitrary
> types to Go from C.
>
> So if I create a GoSlice backed by a void*, if I free() that void* then Go
> no longer has access to it. Go will also not clear that memory. If I am
> passing it by value, will Go make a copy of it if I pass it into another Go
> function? I'm assuming that I probably should not take a pointer from these
> C created Go values.

Same idea. The whole process is much easier (and safer) if you hand
over the data for Go to do the work, otherwise you'll be fighting the
garbage collector and doing reference counting yourself.


gustavo @ http://niemeyer.net
Reply all
Reply to author
Forward
0 new messages