]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fail silently if we unwind over sigpanic into C code
authorAustin Clements <austin@google.com>
Tue, 30 Jan 2018 21:03:51 +0000 (16:03 -0500)
committerAustin Clements <austin@google.com>
Wed, 31 Jan 2018 02:13:21 +0000 (02:13 +0000)
If we're running C code and the code panics, the runtime will inject a
call to sigpanic into the C code just like it would into Go code.
However, the return PC from this sigpanic will be in C code. We used
to silently abort the traceback if we didn't recognize a return PC, so
this went by quietly. Now we're much louder because in general this is
a bad thing. However, in this one particular case, it's fine, so if
we're in cgo and are looking at the return PC of sigpanic, silence the
debug output.

Fixes #23576.

Change-Id: I03d0c14d4e4d25b29b1f5804f5e9ccc4f742f876
Reviewed-on: https://go-review.googlesource.com/90896
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/runtime/crash_cgo_test.go
src/runtime/testdata/testprogcgo/sigpanic.go [new file with mode: 0644]
src/runtime/traceback.go

index 8993a75ad3fb1080d6d0459fc1d6b77692a43647..3b9fedc7a43a6182e71d01a10f6b504cbf65e07d 100644 (file)
@@ -481,3 +481,24 @@ func TestSigStackSwapping(t *testing.T) {
                t.Errorf("expected %q got %v", want, got)
        }
 }
+
+func TestCgoTracebackSigpanic(t *testing.T) {
+       // Test unwinding over a sigpanic in C code without a C
+       // symbolizer. See issue #23576.
+       if runtime.GOOS == "windows" {
+               // On Windows if we get an exception in C code, we let
+               // the Windows exception handler unwind it, rather
+               // than injecting a sigpanic.
+               t.Skip("no sigpanic in C on windows")
+       }
+       t.Parallel()
+       got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
+       want := "runtime.sigpanic"
+       if !strings.Contains(got, want) {
+               t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
+       }
+       nowant := "unexpected return pc"
+       if strings.Contains(got, nowant) {
+               t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got)
+       }
+}
diff --git a/src/runtime/testdata/testprogcgo/sigpanic.go b/src/runtime/testdata/testprogcgo/sigpanic.go
new file mode 100644 (file)
index 0000000..cb46030
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2018 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 crash.
+// We want to test unwinding from sigpanic into C code (without a C symbolizer).
+
+/*
+#cgo CFLAGS: -O0
+
+char *pnil;
+
+static int f1(void) {
+       *pnil = 0;
+       return 0;
+}
+*/
+import "C"
+
+func init() {
+       register("TracebackSigpanic", TracebackSigpanic)
+}
+
+func TracebackSigpanic() {
+       C.f1()
+}
index 0d5b06a1f03f9ac69c92fae6e337109d64ff4d33..2261942ab49e8892b43c9b4b03556bedfaed3c84 100644 (file)
@@ -286,7 +286,15 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                                // In that context it is okay to stop early.
                                // But if callback is set, we're doing a garbage collection and must
                                // get everything, so crash loudly.
-                               if callback != nil || printing {
+                               doPrint := printing
+                               if doPrint && gp.m.incgo && f.entry == sigpanicPC {
+                                       // We can inject sigpanic
+                                       // calls directly into C code,
+                                       // in which case we'll see a C
+                                       // return PC. Don't complain.
+                                       doPrint = false
+                               }
+                               if callback != nil || doPrint {
                                        print("runtime: unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n")
                                        tracebackHexdump(gp.stack, &frame, lrPtr)
                                }