From 70fd4e47d73b92fe90e44ac785e2f98f9df0ab67 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 28 Jul 2021 21:09:31 -0700 Subject: runtime: avoid possible preemption when returning from Go to C When returning from Go to C, it was possible for the goroutine to be preempted after calling unlockOSThread. This could happen when there a context function installed by SetCgoTraceback set a non-zero context, leading to a defer call in cgocallbackg1. The defer function wrapper, introduced in 1.17 as part of the regabi support, was not nosplit, and hence was a potential preemption point. If it did get preempted, the G would move to a new M. It would then attempt to return to C code on a different stack, typically leading to a SIGSEGV. Fix this in a simple way by postponing the unlockOSThread until after the other defer. Also check for the failure condition and fail early, rather than waiting for a SIGSEGV. Without the fix to cgocall.go, the test case fails about 50% of the time on my laptop. Fixes #47441 Change-Id: Ib8ca13215bd36cddc2a49e86698824a29c6a68ba Reviewed-on: https://go-review.googlesource.com/c/go/+/338197 Trust: Ian Lance Taylor Reviewed-by: Keith Randall Reviewed-by: Cherry Mui --- src/runtime/crash_cgo_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/runtime/crash_cgo_test.go') diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index 7d25c51aa2..5729942cee 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -282,6 +282,15 @@ func TestCgoTracebackContext(t *testing.T) { } } +func TestCgoTracebackContextPreemption(t *testing.T) { + t.Parallel() + got := runTestProg(t, "testprogcgo", "TracebackContextPreemption") + want := "OK\n" + if got != want { + t.Errorf("expected %q got %v", want, got) + } +} + func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) { t.Parallel() if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") { -- cgit v1.2.3-54-g00ecf