]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime: in __tsan_fini tell scheduler we are entering non-Go code
authorIan Lance Taylor <iant@golang.org>
Wed, 19 Apr 2023 21:16:37 +0000 (14:16 -0700)
committerGopher Robot <gobot@golang.org>
Fri, 21 Apr 2023 21:26:05 +0000 (21:26 +0000)
__tsan_fini will call exit which will call destructors which
may in principle call back into Go functions. Prepare the scheduler
by calling entersyscall before __tsan_fini.

Fixes #59711

Change-Id: Ic4df8fba3014bafa516739408ccfc30aba4f22ad
Reviewed-on: https://go-review.googlesource.com/c/go/+/486615
Reviewed-by: Michael Pratt <mpratt@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Ian Lance Taylor <iant@google.com>

src/runtime/crash_cgo_test.go
src/runtime/race.go
src/runtime/testdata/testprogcgo/destructor.c [new file with mode: 0644]
src/runtime/testdata/testprogcgo/destructor.go [new file with mode: 0644]

index c6c018ccdf17f29b98e9ac00b714492e18cadfc8..1d8d874ca162aabd78749980537d535386785f51 100644 (file)
@@ -9,6 +9,7 @@ package runtime_test
 import (
        "fmt"
        "internal/goos"
+       "internal/platform"
        "internal/testenv"
        "os"
        "os/exec"
@@ -777,3 +778,39 @@ func TestCgoSigfwd(t *testing.T) {
                t.Fatalf("expected %q, but got:\n%s", want, got)
        }
 }
+
+func TestDestructorCallback(t *testing.T) {
+       t.Parallel()
+       got := runTestProg(t, "testprogcgo", "DestructorCallback")
+       if want := "OK\n"; got != want {
+               t.Errorf("expected %q, but got:\n%s", want, got)
+       }
+}
+
+func TestDestructorCallbackRace(t *testing.T) {
+       // This test requires building with -race,
+       // so it's somewhat slow.
+       if testing.Short() {
+               t.Skip("skipping test in -short mode")
+       }
+
+       if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
+               t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH)
+       }
+
+       t.Parallel()
+
+       exe, err := buildTestProg(t, "testprogcgo", "-race")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       got, err := testenv.CleanCmdEnv(exec.Command(exe, "DestructorCallback")).CombinedOutput()
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if want := "OK\n"; string(got) != want {
+               t.Errorf("expected %q, but got:\n%s", want, got)
+       }
+}
index f7e99fd9401c2b901159314026c7b690db44fcdc..7c7b78c145065dfd27023c856078c171372b7121 100644 (file)
@@ -407,9 +407,16 @@ func racefini() {
        // already held it's assumed that the first caller exits the program
        // so other calls can hang forever without an issue.
        lock(&raceFiniLock)
+
+       // __tsan_fini will run C atexit functions and C++ destructors,
+       // which can theoretically call back into Go.
+       // Tell the scheduler we entering external code.
+       entersyscall()
+
        // We're entering external code that may call ExitProcess on
        // Windows.
        osPreemptExtEnter(getg().m)
+
        racecall(&__tsan_fini, 0, 0, 0, 0)
 }
 
diff --git a/src/runtime/testdata/testprogcgo/destructor.c b/src/runtime/testdata/testprogcgo/destructor.c
new file mode 100644 (file)
index 0000000..8604d81
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "_cgo_export.h"
+
+static void callDestructorCallback() {
+       GoDestructorCallback();
+}
+
+static void (*destructorFn)(void);
+
+void registerDestructor() {
+       destructorFn = callDestructorCallback;
+}
+
+__attribute__((destructor))
+static void destructor() {
+       if (destructorFn) {
+               destructorFn();
+       }
+}
diff --git a/src/runtime/testdata/testprogcgo/destructor.go b/src/runtime/testdata/testprogcgo/destructor.go
new file mode 100644 (file)
index 0000000..49529f0
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// extern void registerDestructor();
+import "C"
+
+import "fmt"
+
+func init() {
+       register("DestructorCallback", DestructorCallback)
+}
+
+//export GoDestructorCallback
+func GoDestructorCallback() {
+}
+
+func DestructorCallback() {
+       C.registerDestructor()
+       fmt.Println("OK")
+}