]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: Goexit on C-created thread report more useful error message
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Wed, 11 Sep 2024 06:33:42 +0000 (13:33 +0700)
committerGopher Robot <gobot@golang.org>
Wed, 11 Sep 2024 17:05:32 +0000 (17:05 +0000)
This reverts CL 609296, with the fix for failing builders.

Fixes #68275

Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-nocgo,gotip-darwin-amd64-nocgo,gotip-linux-ppc64_power10,gotip-linux-ppc64_power8
Change-Id: I0f539ee7b0be720642eee8885946edccd9c6e04e
Reviewed-on: https://go-review.googlesource.com/c/go/+/612335
Reviewed-by: Tim King <taking@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: qiu laidongfeng2 <2645477756@qq.com>
src/runtime/crash_cgo_test.go
src/runtime/panic.go
src/runtime/proc.go
src/runtime/testdata/testprogcgo/callback.go

index d164a070477d2928442589da0a1db1e4ce09aeff..e9b449ab8889037a57048172b1e47cc84c16980f 100644 (file)
@@ -859,3 +859,13 @@ func TestStackSwitchCallback(t *testing.T) {
                t.Errorf("expected %q, got %v", want, got)
        }
 }
+
+func TestCgoToGoCallGoexit(t *testing.T) {
+       if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
+               t.Skipf("no pthreads on %s", runtime.GOOS)
+       }
+       output := runTestProg(t, "testprogcgo", "CgoToGoCallGoexit")
+       if !strings.Contains(output, "runtime.Goexit called in a thread that was not created by the Go runtime") {
+               t.Fatalf("output should contain %s, got %s", "runtime.Goexit called in a thread that was not created by the Go runtime", output)
+       }
+}
index bd1ea096aa2a013de74c713b3eaeed4c6a3a262a..ed08bf4f3008974ac7c1e15ee32116ea877dc1d0 100644 (file)
@@ -614,6 +614,8 @@ func deferreturn() {
 // without func main returning. Since func main has not returned,
 // the program continues execution of other goroutines.
 // If all other goroutines exit, the program crashes.
+//
+// It crashes if called from a thread not created by the Go runtime.
 func Goexit() {
        // Create a panic object for Goexit, so we can recognize when it might be
        // bypassed by a recover().
index c4db86225df2615f901a1bbc636bd108e5504136..0909d138ff774e1bc82bbb5a46c6b0da6df797f9 100644 (file)
@@ -4321,6 +4321,9 @@ func gdestroy(gp *g) {
 
        if locked && mp.lockedInt != 0 {
                print("runtime: mp.lockedInt = ", mp.lockedInt, "\n")
+               if mp.isextra {
+                       throw("runtime.Goexit called in a thread that was not created by the Go runtime")
+               }
                throw("exited a goroutine internally locked to the OS thread")
        }
        gfput(pp, gp)
index 319572fe1090348714b5b1c1b24c894663debbdd..39993f13a678a518b964210119f338de944e9c5b 100644 (file)
@@ -38,10 +38,21 @@ import (
 
 func init() {
        register("CgoCallbackGC", CgoCallbackGC)
+       register("CgoToGoCallGoexit", CgoToGoCallGoexit)
 }
 
+func CgoToGoCallGoexit() {
+       goexit = true
+       C.foo()
+}
+
+var goexit = false
+
 //export go_callback
 func go_callback() {
+       if goexit {
+               runtime.Goexit()
+       }
        if e := extraMInUse.Load(); e == 0 {
                fmt.Printf("in callback extraMInUse got %d want >0\n", e)
                os.Exit(1)