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.go67
1 files changed, 62 insertions, 5 deletions
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index 82ed015bd..44167e6e9 100644
--- a/misc/cgo/test/callback.go
+++ b/misc/cgo/test/callback.go
@@ -9,16 +9,21 @@ void callback(void *f);
void callGoFoo(void);
void callGoStackCheck(void);
void callPanic(void);
+void callCgoAllocate(void);
+int callGoReturnVal(void);
+int returnAfterGrow(void);
+int returnAfterGrowFromGo(void);
*/
import "C"
import (
- "./backdoor"
"path"
"runtime"
"strings"
"testing"
"unsafe"
+
+ "./backdoor"
)
// nestedCall calls into C, back into Go, and finally to f.
@@ -152,11 +157,13 @@ func testCallbackCallers(t *testing.T) {
n := 0
name := []string{
"test.goCallback",
+ "runtime.call16",
"runtime.cgocallbackg1",
"runtime.cgocallbackg",
"runtime.cgocallback_gofunc",
- "runtime.asmcgocall",
- "runtime.cgocall",
+ "asmcgocall",
+ "runtime.asmcgocall_errno",
+ "runtime.cgocall_errno",
"test._Cfunc_callback",
"test.nestedCall",
"test.testCallbackCallers",
@@ -181,8 +188,12 @@ func testCallbackCallers(t *testing.T) {
if strings.HasPrefix(fname, "_") {
fname = path.Base(f.Name()[1:])
}
- if fname != name[i] {
- t.Errorf("expected function name %s, got %s", name[i], fname)
+ namei := ""
+ if i < len(name) {
+ namei = name[i]
+ }
+ if fname != namei {
+ t.Errorf("stk[%d] = %q, want %q", i, fname, namei)
}
}
}
@@ -200,6 +211,52 @@ func testPanicFromC(t *testing.T) {
C.callPanic()
}
+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.