Can Go pass a stack-allocated object to C?

188 views
Skip to first unread message

Fannie...@arm.com

unread,
Mar 3, 2021, 10:05:12 PM3/3/21
to golang-dev
Hi all,

For the following case, the local variable `cIntArray[0]`, `cIntArray [1]` are stack-allocated objects, but when passing the reference to "cIntArray[0]" to a C function,  the `cIntArray` variable is moved to heap by Go compiler.  

So I have two questions:  one question is why does Go compiler move `cIntArray` to heap? another question is can we pass a stack-allocated object to C function? Thank you.

package main

/*
#include <stdlib.h>
#include <stdio.h>

int test(int* a) {
        for (int i = 0; i < 2; i++) {
                printf("&a[%d]=%lx, a[%d]=%d\n", i, &a[i], i, a[i]);
        }
        return a[0]+a[1];
}*/
import "C"
import "fmt"

func main() {
        var cIntArray [2]C.int
        cIntArray[0] = 100
        cIntArray[1] = 200
        a := C.test(&cIntArray[0])   // cIntArray will be moved to heap.
        fmt.Printf("a=%x\n", a)
}

Fannie

David Chase

unread,
Mar 3, 2021, 11:05:03 PM3/3/21
to Fannie...@arm.com, golang-dev
Go's stacks sometimes get relocated.  The goes-wrong case here might be:

1) stack gets really large, grows as necessary.
2) stack gets small, GC has not noticed yet.
3) you call C function, which for whatever reason takes a little time to run.
4) meanwhile, GC runs, notices that your stack shrank a lot, and moves it into a smaller place.
5) C function runs, but the stack data that it was planning to read may have changed
   (In practice, the old stack is probably left alone for a short while, so maybe your C function
   gets lucky, as long as it is only reading, not writing).

In general, the short answer to "can we pass stack allocated objects to C?" is no.

Changing that answer would require some changes in how the Go runtime manages stacks,
and making that change would soon commit us to keep that change in the future, because
you are already planning to write the code that will run slowly if we reversed the change.

That doesn't mean it won't happen, but it does mean that we're reluctant,
because we don't think we know enough yet to make the commitment.

Depending on your application, maybe you keep a pre-allocated cache of [2]C.int to use
for this purpose?

David


--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-dev/9575684c-39f7-426f-bb40-ad56b0f877b4n%40googlegroups.com.

Robert Engels

unread,
Mar 3, 2021, 11:42:55 PM3/3/21
to David Chase, Fannie...@arm.com, golang-dev
This seems a trivial problem to solve at the expense of making the C call a little slower. Prevent the GC from shrinking stacks when a C call is in progress. 

On Mar 3, 2021, at 10:05 PM, 'David Chase' via golang-dev <golan...@googlegroups.com> wrote:



Matthew Dempsky

unread,
Mar 4, 2021, 12:33:54 AM3/4/21
to Robert Engels, David Chase, Fannie...@arm.com, golang-dev
I think the stack moving is one issue. The other issue is I think C code can pass the Go pointer back into Go code, so escape analysis needs to conservatively assume that might happen and that the C code might retain effectively retain the pointer.

I'm curious what the motivation for wanting the objects to be on the stack is. Is it just a performance concern? Can you just pass the array by value instead? (E.g., wrap in a C struct.)

Fannie...@arm.com

unread,
Mar 4, 2021, 1:59:00 AM3/4/21
to golang-dev
Thank you for your answer.  👍

Fannie...@arm.com

unread,
Mar 4, 2021, 2:06:17 AM3/4/21
to golang-dev
On Thursday, March 4, 2021 at 1:33:54 PM UTC+8 Matthew Dempsky wrote:
I think the stack moving is one issue. The other issue is I think C code can pass the Go pointer back into Go code, so escape analysis needs to conservatively assume that might happen and that the C code might retain effectively retain the pointer.

I'm curious what the motivation for wanting the objects to be on the stack is. Is it just a performance concern? Can you just pass the array by value instead? (E.g., wrap in a C struct.)

No other motivation. It has something to do with something I am doing now. Thank you.

David Chase

unread,
Mar 4, 2021, 9:12:58 AM3/4/21
to golang-dev
I forgot that one, and that is what seals the deal for C.
I've been trying to figure out if we could do any better with native code in Rust; its "type" system lets you make assertions about things like that, so if we were willing to commit to not moving stacks during native calls, and also paid attention to Rust types, perhaps then.
But I would need to learn more about Rust.

Reply all
Reply to author
Forward
0 new messages