summaryrefslogtreecommitdiff
path: root/misc/cgo/test/callback.go
diff options
context:
space:
mode:
Diffstat (limited to 'misc/cgo/test/callback.go')
-rw-r--r--misc/cgo/test/callback.go45
1 files changed, 45 insertions, 0 deletions
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index a7f1a3ecd..44167e6e9 100644
--- a/misc/cgo/test/callback.go
+++ b/misc/cgo/test/callback.go
@@ -10,6 +10,9 @@ void callGoFoo(void);
void callGoStackCheck(void);
void callPanic(void);
void callCgoAllocate(void);
+int callGoReturnVal(void);
+int returnAfterGrow(void);
+int returnAfterGrowFromGo(void);
*/
import "C"
@@ -212,6 +215,48 @@ func testAllocateFromC(t *testing.T) {
C.callCgoAllocate() // crashes or exits on failure
}
+// Test that C code can return a value if it calls a Go function that
+// causes a stack copy.
+func testReturnAfterGrow(t *testing.T) {
+ // Use a new goroutine so that we get a small stack.
+ c := make(chan int)
+ go func() {
+ c <- int(C.returnAfterGrow())
+ }()
+ if got, want := <-c, 123456; got != want {
+ t.Errorf("got %d want %d", got, want)
+ }
+}
+
+// Test that we can return a value from Go->C->Go if the Go code
+// causes a stack copy.
+func testReturnAfterGrowFromGo(t *testing.T) {
+ // Use a new goroutine so that we get a small stack.
+ c := make(chan int)
+ go func() {
+ c <- int(C.returnAfterGrowFromGo())
+ }()
+ if got, want := <-c, 129*128/2; got != want {
+ t.Errorf("got %d want %d", got, want)
+ }
+}
+
+//export goReturnVal
+func goReturnVal() (r C.int) {
+ // Force a stack copy.
+ var f func(int) int
+ f = func(i int) int {
+ var buf [256]byte
+ use(buf[:])
+ if i == 0 {
+ return 0
+ }
+ return i + f(i-1)
+ }
+ r = C.int(f(128))
+ return
+}
+
func testCallbackStack(t *testing.T) {
// Make cgo call and callback with different amount of stack stack available.
// We do not do any explicit checks, just ensure that it does not crash.