Commit 38765eba authored by Dmitry Vyukov's avatar Dmitry Vyukov

runtime/race: don't crash on invalid PCs

Currently raceSymbolizeCode uses funcline, which is internal runtime
function which crashes on incorrect PCs. Use FileLine instead,
it is public and does not crash on invalid data.

Note: FileLine returns "?" file on failure. That string is not NUL-terminated,
so we need to additionally check what FileLine returns.

Fixes #17190

Change-Id: Ic6fbd4f0e68ddd52e9b2dd25e625b50adcb69a98
Reviewed-on: https://go-review.googlesource.com/29714
Run-TryBot: Dmitry Vyukov <dvyukov@google.com>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 9f1c7878
...@@ -91,23 +91,23 @@ func racecallback(cmd uintptr, ctx unsafe.Pointer) { ...@@ -91,23 +91,23 @@ func racecallback(cmd uintptr, ctx unsafe.Pointer) {
} }
func raceSymbolizeCode(ctx *symbolizeCodeContext) { func raceSymbolizeCode(ctx *symbolizeCodeContext) {
f := findfunc(ctx.pc) f := FuncForPC(ctx.pc)
if f == nil { if f != nil {
ctx.fn = &qq[0] file, line := f.FileLine(ctx.pc)
ctx.file = &dash[0] if line != 0 {
ctx.line = 0 ctx.fn = cfuncname(f.raw())
ctx.off = ctx.pc ctx.line = uintptr(line)
ctx.res = 1 ctx.file = &bytes(file)[0] // assume NUL-terminated
return ctx.off = ctx.pc - f.Entry()
ctx.res = 1
return
}
} }
ctx.fn = &qq[0]
ctx.fn = cfuncname(f) ctx.file = &dash[0]
file, line := funcline(f, ctx.pc) ctx.line = 0
ctx.line = uintptr(line) ctx.off = ctx.pc
ctx.file = &bytes(file)[0] // assume NUL-terminated
ctx.off = ctx.pc - f.entry
ctx.res = 1 ctx.res = 1
return
} }
type symbolizeDataContext struct { type symbolizeDataContext struct {
......
...@@ -13,12 +13,17 @@ import ( ...@@ -13,12 +13,17 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"strings" "strings"
"testing" "testing"
) )
func TestOutput(t *testing.T) { func TestOutput(t *testing.T) {
for _, test := range tests { for _, test := range tests {
if test.goos != "" && test.goos != runtime.GOOS {
t.Logf("test %v runs only on %v, skipping: ", test.name, test.goos)
continue
}
dir, err := ioutil.TempDir("", "go-build") dir, err := ioutil.TempDir("", "go-build")
if err != nil { if err != nil {
t.Fatalf("failed to create temp directory: %v", err) t.Fatalf("failed to create temp directory: %v", err)
...@@ -67,11 +72,12 @@ func TestOutput(t *testing.T) { ...@@ -67,11 +72,12 @@ func TestOutput(t *testing.T) {
var tests = []struct { var tests = []struct {
name string name string
run string run string
goos string
gorace string gorace string
source string source string
re string re string
}{ }{
{"simple", "run", "atexit_sleep_ms=0", ` {"simple", "run", "", "atexit_sleep_ms=0", `
package main package main
import "time" import "time"
func main() { func main() {
...@@ -116,7 +122,7 @@ Found 1 data race\(s\) ...@@ -116,7 +122,7 @@ Found 1 data race\(s\)
exit status 66 exit status 66
`}, `},
{"exitcode", "run", "atexit_sleep_ms=0 exitcode=13", ` {"exitcode", "run", "", "atexit_sleep_ms=0 exitcode=13", `
package main package main
func main() { func main() {
done := make(chan bool) done := make(chan bool)
...@@ -130,7 +136,7 @@ func main() { ...@@ -130,7 +136,7 @@ func main() {
} }
`, `exit status 13`}, `, `exit status 13`},
{"strip_path_prefix", "run", "atexit_sleep_ms=0 strip_path_prefix=/main.", ` {"strip_path_prefix", "run", "", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
package main package main
func main() { func main() {
done := make(chan bool) done := make(chan bool)
...@@ -146,7 +152,7 @@ func main() { ...@@ -146,7 +152,7 @@ func main() {
go:7 \+0x[0-9,a-f]+ go:7 \+0x[0-9,a-f]+
`}, `},
{"halt_on_error", "run", "atexit_sleep_ms=0 halt_on_error=1", ` {"halt_on_error", "run", "", "atexit_sleep_ms=0 halt_on_error=1", `
package main package main
func main() { func main() {
done := make(chan bool) done := make(chan bool)
...@@ -163,7 +169,7 @@ func main() { ...@@ -163,7 +169,7 @@ func main() {
exit status 66 exit status 66
`}, `},
{"test_fails_on_race", "test", "atexit_sleep_ms=0", ` {"test_fails_on_race", "test", "", "atexit_sleep_ms=0", `
package main_test package main_test
import "testing" import "testing"
func TestFail(t *testing.T) { func TestFail(t *testing.T) {
...@@ -182,7 +188,7 @@ PASS ...@@ -182,7 +188,7 @@ PASS
Found 1 data race\(s\) Found 1 data race\(s\)
FAIL`}, FAIL`},
{"slicebytetostring_pc", "run", "atexit_sleep_ms=0", ` {"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `
package main package main
func main() { func main() {
done := make(chan string) done := make(chan string)
...@@ -198,4 +204,57 @@ func main() { ...@@ -198,4 +204,57 @@ func main() {
.*/runtime/string\.go:.* .*/runtime/string\.go:.*
main\.main\.func1\(\) main\.main\.func1\(\)
.*/main.go:7`}, .*/main.go:7`},
// Test for http://golang.org/issue/17190
{"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `
package main
/*
#include <pthread.h>
typedef struct cb {
int foo;
} cb;
extern void goCallback();
static inline void *threadFunc(void *p) {
goCallback();
return 0;
}
static inline void startThread(cb* c) {
pthread_t th;
pthread_create(&th, 0, threadFunc, 0);
}
*/
import "C"
import "time"
var racy int
//export goCallback
func goCallback() {
racy++
}
func main() {
var c C.cb
C.startThread(&c)
time.Sleep(time.Second)
racy++
}
`, `==================
WARNING: DATA RACE
Read at 0x[0-9,a-f]+ by main goroutine:
main\.main\(\)
.*/main\.go:34 \+0x[0-9,a-f]+
Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
main\.goCallback\(\)
.*/main\.go:27 \+0x[0-9,a-f]+
main._cgoexpwrap_[0-9a-z]+_goCallback\(\)
.*/_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+
Goroutine [0-9] \(running\) created at:
runtime\.newextram\(\)
.*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
==================`},
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment