]> Cypherpunks repositories - gostls13.git/commitdiff
cgo, runtime: diagnose callback on non-Go thread
authorRuss Cox <rsc@golang.org>
Thu, 8 Mar 2012 17:12:40 +0000 (12:12 -0500)
committerRuss Cox <rsc@golang.org>
Thu, 8 Mar 2012 17:12:40 +0000 (12:12 -0500)
Before:
$ go run x.go
signal 11 (core dumped)
$

After:
$ go run x.go
runtime: cgo callback on thread not created by Go.
signal 11 (core dumped)
$

For issue 3068.
Not a fix, but as much of a fix as we can do before Go 1.

R=golang-dev, rogpeppe, gri
CC=golang-dev
https://golang.org/cl/5781047

src/cmd/cgo/out.go
src/pkg/runtime/asm_386.s
src/pkg/runtime/asm_amd64.s
src/pkg/runtime/thread_darwin.c
src/pkg/runtime/thread_freebsd.c
src/pkg/runtime/thread_linux.c
src/pkg/runtime/thread_netbsd.c
src/pkg/runtime/thread_openbsd.c
src/pkg/runtime/thread_plan9.c
src/pkg/runtime/thread_windows.c

index d6447caff694ad3112d26fdac639525a1d65f086..bbadad1bed97c28225fda5a17d448edc8e15d6cf 100644 (file)
@@ -573,8 +573,9 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
                        goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
                }
                fmt.Fprintf(fc, "#pragma dynexport %s %s\n", goname, goname)
-               fmt.Fprintf(fc, "extern void ·%s();\n", goname)
-               fmt.Fprintf(fc, "\nvoid\n")
+               fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
+               fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
+               fmt.Fprintf(fc, "void\n")
                fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
                fmt.Fprintf(fc, "{\n")
                fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
index 6bbec30638bd6bfd47ce34077787d186fc2f839c..da2290210a424eee83dbd88326c59760e3f289ab 100644 (file)
@@ -425,6 +425,14 @@ TEXT runtime·cgocallback(SB),7,$12
        // Save current m->g0->sched.sp on stack and then set it to SP.
        get_tls(CX)
        MOVL    m(CX), BP
+
+       // If m is nil, it is almost certainly because we have been called
+       // on a thread that Go did not create.  We're going to crash as
+       // soon as we try to use m; instead, try to print a nice error and exit.
+       CMPL    BP, $0
+       JNE 2(PC)
+       CALL    runtime·badcallback(SB)
+
        MOVL    m_g0(BP), SI
        PUSHL   (g_sched+gobuf_sp)(SI)
        MOVL    SP, (g_sched+gobuf_sp)(SI)
index 2ea87a779f40d814c6770e7705f732465ab31eea..392ad8c87facd671eef8da94725a2da5c54f8880 100644 (file)
@@ -471,6 +471,14 @@ TEXT runtime·cgocallback(SB),7,$24
        // Save current m->g0->sched.sp on stack and then set it to SP.
        get_tls(CX)
        MOVQ    m(CX), BP
+       
+       // If m is nil, it is almost certainly because we have been called
+       // on a thread that Go did not create.  We're going to crash as
+       // soon as we try to use m; instead, try to print a nice error and exit.
+       CMPQ    BP, $0
+       JNE 2(PC)
+       CALL    runtime·badcallback(SB)
+
        MOVQ    m_g0(BP), SI
        PUSHQ   (g_sched+gobuf_sp)(SI)
        MOVQ    SP, (g_sched+gobuf_sp)(SI)
index 556fb67e842547c49d613330f2ef5bbda8ce226b..bbcdf05ef0140d6604f20f668e3b8e9096ebffec 100644 (file)
@@ -477,3 +477,13 @@ runtime·setprof(bool on)
        else
                runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil);
 }
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+       runtime·write(2, badcallback, sizeof badcallback - 1);
+}
index 77e8bb3dac3a3f8aab1f75661379dc4703a2742f..b848cbadd4475d0533002412161dc08d2b1d16ec 100644 (file)
@@ -195,3 +195,13 @@ runtime·setprof(bool on)
 {
        USED(on);
 }
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+       runtime·write(2, badcallback, sizeof badcallback - 1);
+}
index 6b428440e0131d78e7aa3a8237f4df7c97c3a659..af765d53b93e5c7bb72e08fd904454481de48ae6 100644 (file)
@@ -255,3 +255,13 @@ runtime·setprof(bool on)
 {
        USED(on);
 }
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+       runtime·write(2, badcallback, sizeof badcallback - 1);
+}
index 62e133c449baa25c4e7194dac99a95449dc15f8e..40e4f6ce1c6e3a5c1d7245fb0d9dc53870816ab1 100644 (file)
@@ -213,3 +213,13 @@ runtime·setprof(bool on)
 {
        USED(on);
 }
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+       runtime·write(2, badcallback, sizeof badcallback - 1);
+}
index bee0c5755fa033932a445d4169b7d135065b18c7..e4f95988b0a555b236a0a8177cf5e3e05ee12685 100644 (file)
@@ -213,3 +213,13 @@ runtime·setprof(bool on)
 {
        USED(on);
 }
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+       runtime·write(2, badcallback, sizeof badcallback - 1);
+}
index aaed5050bb8cb41d9505dc303c7f3e0114a0dafd..4ca01b0e668fb9a3ccb4a064ebf8bf413b5dbbff 100644 (file)
@@ -247,3 +247,13 @@ runtime·setprof(bool on)
 {
        USED(on);
 }
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+       runtime·pwrite(2, badcallback, sizeof badcallback - 1, -1LL);
+}
index 1147a05e6a3878eb0cfa376d1f2eb40a782b2691..e75e0c1569e91ca2b63dd6b9b1004b15a91a8040 100644 (file)
@@ -422,3 +422,22 @@ runtime·setprof(bool on)
 {
        USED(on);
 }
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+       uint32 written;
+
+       runtime·stdcall(
+               runtime·WriteFile, 5,
+               runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12), // stderr
+               badcallback,
+               (uintptr)(sizeof badcallback - 1),
+               &written,
+               nil
+       );
+}