mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: fix cgo signals detection
CL 64070 removed lockOSThread from the cgocall path, but didn't update the signal-in-cgo detection in sighandler. As a result, signals that arrive during a cgo call are treated like they arrived during Go execution, breaking the traceback. Update the cgo detection to fix the backtrace. Fixes #47522 Change-Id: I61d77ba6465f55e3e6187246d79675ba8467ec23 Reviewed-on: https://go-review.googlesource.com/c/go/+/339989 Trust: Michael Pratt <mpratt@google.com> Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
parent
3a0cd11214
commit
091db6392d
5 changed files with 100 additions and 4 deletions
|
|
@ -536,6 +536,29 @@ func TestCgoTracebackSigpanic(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCgoPanicCallback(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
got := runTestProg(t, "testprogcgo", "PanicCallback")
|
||||||
|
t.Log(got)
|
||||||
|
want := "panic: runtime error: invalid memory address or nil pointer dereference"
|
||||||
|
if !strings.Contains(got, want) {
|
||||||
|
t.Errorf("did not see %q in output", want)
|
||||||
|
}
|
||||||
|
want = "panic_callback"
|
||||||
|
if !strings.Contains(got, want) {
|
||||||
|
t.Errorf("did not see %q in output", want)
|
||||||
|
}
|
||||||
|
want = "PanicCallback"
|
||||||
|
if !strings.Contains(got, want) {
|
||||||
|
t.Errorf("did not see %q in output", want)
|
||||||
|
}
|
||||||
|
// No runtime errors like "runtime: unexpected return pc".
|
||||||
|
nowant := "runtime: "
|
||||||
|
if strings.Contains(got, nowant) {
|
||||||
|
t.Errorf("did not see %q in output", want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test that C code called via cgo can use large Windows thread stacks
|
// Test that C code called via cgo can use large Windows thread stacks
|
||||||
// and call back in to Go without crashing. See issue #20975.
|
// and call back in to Go without crashing. See issue #20975.
|
||||||
//
|
//
|
||||||
|
|
@ -603,6 +626,28 @@ func TestSegv(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAbortInCgo(t *testing.T) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "plan9", "windows":
|
||||||
|
// N.B. On Windows, C abort() causes the program to exit
|
||||||
|
// without going through the runtime at all.
|
||||||
|
t.Skipf("no signals on %s", runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
got := runTestProg(t, "testprogcgo", "Abort")
|
||||||
|
t.Log(got)
|
||||||
|
want := "SIGABRT"
|
||||||
|
if !strings.Contains(got, want) {
|
||||||
|
t.Errorf("did not see %q in output", want)
|
||||||
|
}
|
||||||
|
// No runtime errors like "runtime: unknown pc".
|
||||||
|
nowant := "runtime: "
|
||||||
|
if strings.Contains(got, nowant) {
|
||||||
|
t.Errorf("did not see %q in output", want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestEINTR tests that we handle EINTR correctly.
|
// TestEINTR tests that we handle EINTR correctly.
|
||||||
// See issue #20400 and friends.
|
// See issue #20400 and friends.
|
||||||
func TestEINTR(t *testing.T) {
|
func TestEINTR(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -688,9 +688,11 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
||||||
}
|
}
|
||||||
|
|
||||||
print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
|
print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
|
||||||
if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
|
if _g_.m.incgo && gp == _g_.m.g0 && _g_.m.curg != nil {
|
||||||
print("signal arrived during cgo execution\n")
|
print("signal arrived during cgo execution\n")
|
||||||
gp = _g_.m.lockedg.ptr()
|
// Switch to curg so that we get a traceback of the Go code
|
||||||
|
// leading up to the cgocall, which switched from curg to g0.
|
||||||
|
gp = _g_.m.curg
|
||||||
}
|
}
|
||||||
if sig == _SIGILL || sig == _SIGFPE {
|
if sig == _SIGILL || sig == _SIGFPE {
|
||||||
// It would be nice to know how long the instruction is.
|
// It would be nice to know how long the instruction is.
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,11 @@ func winthrow(info *exceptionrecord, r *context, gp *g) {
|
||||||
print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
|
print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
|
||||||
|
|
||||||
print("PC=", hex(r.ip()), "\n")
|
print("PC=", hex(r.ip()), "\n")
|
||||||
if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
|
if _g_.m.incgo && gp == _g_.m.g0 && _g_.m.curg != nil {
|
||||||
if iscgo {
|
if iscgo {
|
||||||
print("signal arrived during external code execution\n")
|
print("signal arrived during external code execution\n")
|
||||||
}
|
}
|
||||||
gp = _g_.m.lockedg.ptr()
|
gp = _g_.m.curg
|
||||||
}
|
}
|
||||||
print("\n")
|
print("\n")
|
||||||
|
|
||||||
|
|
|
||||||
29
src/runtime/testdata/testprogcgo/panic.go
vendored
Normal file
29
src/runtime/testdata/testprogcgo/panic.go
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// This program will crash.
|
||||||
|
// We want to test unwinding from a cgo callback.
|
||||||
|
|
||||||
|
/*
|
||||||
|
void panic_callback();
|
||||||
|
|
||||||
|
static void call_callback(void) {
|
||||||
|
panic_callback();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
register("PanicCallback", PanicCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export panic_callback
|
||||||
|
func panic_callback() {
|
||||||
|
var i *int
|
||||||
|
*i = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
func PanicCallback() {
|
||||||
|
C.call_callback()
|
||||||
|
}
|
||||||
20
src/runtime/testdata/testprogcgo/sigthrow.go
vendored
Normal file
20
src/runtime/testdata/testprogcgo/sigthrow.go
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2021 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
|
||||||
|
|
||||||
|
// This program will abort.
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
register("Abort", Abort)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Abort() {
|
||||||
|
C.abort()
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue