diff -ur go-orig/src/pkg/runtime/cgocall.c go/src/pkg/runtime/cgocall.c --- go-orig/src/pkg/runtime/cgocall.c 2014-08-13 12:49:45.000000000 +0900 +++ go/src/pkg/runtime/cgocall.c 2014-08-18 22:32:59.520976303 +0900 @@ -234,14 +234,24 @@ void runtime·cgocallbackg(void) { + uintptr saved_sp, saved_pc; + if(g != m->curg) { runtime·prints("runtime: bad g in cgocallback"); runtime·exit(2); } + // entersyscall saves the caller's SP to allow the GC to trace the Go + // stack. However, since we're returning to an earlier stack frame and + // need to pair with the entersyscall() call made by cgocall, we must + // save the syscallsp and syscallpc and restore them before returning. + saved_sp = g->syscallsp; + saved_pc = g->syscallpc; runtime·exitsyscall(); // coming out of cgo call runtime·cgocallbackg1(); runtime·entersyscall(); // going back to cgo call + g->syscallsp = saved_sp; + g->syscallpc = saved_pc; } void diff -ur go-orig/src/pkg/runtime/proc.c go/src/pkg/runtime/proc.c --- go-orig/src/pkg/runtime/proc.c 2014-08-13 12:49:45.000000000 +0900 +++ go/src/pkg/runtime/proc.c 2014-08-18 22:24:38.735585033 +0900 @@ -1588,13 +1588,16 @@ // from the low-level system calls used by the runtime. #pragma textflag NOSPLIT void -runtime·exitsyscall(void) +·exitsyscall(int32 dummy) { m->locks++; // see comment in entersyscall if(g->isbackground) // do not consider blocked scavenger for deadlock detection incidlelocked(-1); + if(runtime·getcallersp(&dummy) > g->syscallsp) + runtime·throw("runtime: exitsyscall called with invalid syscall frame"); + g->waitsince = 0; if(exitsyscallfast()) { // There's a cpu for us, so we can run.