Commit 9b73238d authored by Russ Cox's avatar Russ Cox

cgo, runtime: diagnose callback on non-Go thread

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
parent 9b7b574e
...@@ -573,8 +573,9 @@ func (p *Package) writeExports(fgo2, fc, fm *os.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 goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
} }
fmt.Fprintf(fc, "#pragma dynexport %s %s\n", goname, goname) fmt.Fprintf(fc, "#pragma dynexport %s %s\n", goname, goname)
fmt.Fprintf(fc, "extern void ·%s();\n", goname) fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
fmt.Fprintf(fc, "\nvoid\n") 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, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "{\n") fmt.Fprintf(fc, "{\n")
fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname) fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
......
...@@ -425,6 +425,14 @@ TEXT runtime·cgocallback(SB),7,$12 ...@@ -425,6 +425,14 @@ TEXT runtime·cgocallback(SB),7,$12
// Save current m->g0->sched.sp on stack and then set it to SP. // Save current m->g0->sched.sp on stack and then set it to SP.
get_tls(CX) get_tls(CX)
MOVL m(CX), BP 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 MOVL m_g0(BP), SI
PUSHL (g_sched+gobuf_sp)(SI) PUSHL (g_sched+gobuf_sp)(SI)
MOVL SP, (g_sched+gobuf_sp)(SI) MOVL SP, (g_sched+gobuf_sp)(SI)
......
...@@ -471,6 +471,14 @@ TEXT runtime·cgocallback(SB),7,$24 ...@@ -471,6 +471,14 @@ TEXT runtime·cgocallback(SB),7,$24
// Save current m->g0->sched.sp on stack and then set it to SP. // Save current m->g0->sched.sp on stack and then set it to SP.
get_tls(CX) get_tls(CX)
MOVQ m(CX), BP 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 MOVQ m_g0(BP), SI
PUSHQ (g_sched+gobuf_sp)(SI) PUSHQ (g_sched+gobuf_sp)(SI)
MOVQ SP, (g_sched+gobuf_sp)(SI) MOVQ SP, (g_sched+gobuf_sp)(SI)
......
...@@ -477,3 +477,13 @@ runtime·setprof(bool on) ...@@ -477,3 +477,13 @@ runtime·setprof(bool on)
else else
runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil); 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);
}
...@@ -195,3 +195,13 @@ runtime·setprof(bool on) ...@@ -195,3 +195,13 @@ runtime·setprof(bool on)
{ {
USED(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);
}
...@@ -255,3 +255,13 @@ runtime·setprof(bool on) ...@@ -255,3 +255,13 @@ runtime·setprof(bool on)
{ {
USED(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);
}
...@@ -213,3 +213,13 @@ runtime·setprof(bool on) ...@@ -213,3 +213,13 @@ runtime·setprof(bool on)
{ {
USED(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);
}
...@@ -213,3 +213,13 @@ runtime·setprof(bool on) ...@@ -213,3 +213,13 @@ runtime·setprof(bool on)
{ {
USED(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);
}
...@@ -247,3 +247,13 @@ runtime·setprof(bool on) ...@@ -247,3 +247,13 @@ runtime·setprof(bool on)
{ {
USED(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);
}
...@@ -422,3 +422,22 @@ runtime·setprof(bool on) ...@@ -422,3 +422,22 @@ runtime·setprof(bool on)
{ {
USED(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
);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment