Skip to content

Commit 3da4281

Browse files
qiulaidongfenggopherbot
authored andcommitted
runtime: Goexit on C-created thread report more useful error message
Fixes #68275 Change-Id: I47b7a2092f1b4d48aebf437db4e329815c956bb9 GitHub-Last-Rev: b89bf3c GitHub-Pull-Request: #69126 Reviewed-on: https://go-review.googlesource.com/c/go/+/609296 Reviewed-by: Tim King <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 77e42fd commit 3da4281

File tree

4 files changed

+26
-0
lines changed

4 files changed

+26
-0
lines changed

src/runtime/panic.go

+2
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,8 @@ func deferreturn() {
614614
// without func main returning. Since func main has not returned,
615615
// the program continues execution of other goroutines.
616616
// If all other goroutines exit, the program crashes.
617+
//
618+
// It crashes if called from a thread not created by the Go runtime.
617619
func Goexit() {
618620
// Create a panic object for Goexit, so we can recognize when it might be
619621
// bypassed by a recover().

src/runtime/proc.go

+3
Original file line numberDiff line numberDiff line change
@@ -4321,6 +4321,9 @@ func gdestroy(gp *g) {
43214321

43224322
if locked && mp.lockedInt != 0 {
43234323
print("runtime: mp.lockedInt = ", mp.lockedInt, "\n")
4324+
if mp.isextra {
4325+
throw("runtime.Goexit called in a thread that was not created by the Go runtime")
4326+
}
43244327
throw("exited a goroutine internally locked to the OS thread")
43254328
}
43264329
gfput(pp, gp)

src/runtime/proc_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -1158,3 +1158,13 @@ func TestBigGOMAXPROCS(t *testing.T) {
11581158
t.Errorf("output:\n%s\nwanted:\nunknown function: NonexistentTest", output)
11591159
}
11601160
}
1161+
1162+
func TestCgoToGoCallGoexit(t *testing.T) {
1163+
if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
1164+
t.Skipf("no pthreads on %s", runtime.GOOS)
1165+
}
1166+
output := runTestProg(t, "testprogcgo", "CgoToGoCallGoexit")
1167+
if !strings.Contains(output, "runtime.Goexit called in a thread that was not created by the Go runtime") {
1168+
t.Fatalf("output should contain %s, got %s", "runtime.Goexit called in a thread that was not created by the Go runtime", output)
1169+
}
1170+
}

src/runtime/testdata/testprogcgo/callback.go

+11
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,21 @@ import (
3838

3939
func init() {
4040
register("CgoCallbackGC", CgoCallbackGC)
41+
register("CgoToGoCallGoexit", CgoToGoCallGoexit)
4142
}
4243

44+
func CgoToGoCallGoexit() {
45+
goexit = true
46+
C.foo()
47+
}
48+
49+
var goexit = false
50+
4351
//export go_callback
4452
func go_callback() {
53+
if goexit {
54+
runtime.Goexit()
55+
}
4556
if e := extraMInUse.Load(); e == 0 {
4657
fmt.Printf("in callback extraMInUse got %d want >0\n", e)
4758
os.Exit(1)

0 commit comments

Comments
 (0)