Commit 75d77956 authored by Russ Cox's avatar Russ Cox

runtime/cgo: make compatible with race detector

Some routines run without and m or g and cannot invoke the
race detector runtime. They must be opaque to the runtime.
That used to be true because they were written in C.
Now that they are written in Go, disable the race detector
annotations for those functions explicitly.

Add test.

Fixes #10874.

Change-Id: Ia8cc28d51e7051528f9f9594b75634e6bb66a785
Reviewed-on: https://go-review.googlesource.com/12534Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 0acecb71
...@@ -809,6 +809,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { ...@@ -809,6 +809,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName) fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName) fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName) fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "\tfn := %s\n", goname) fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
// The indirect here is converting from a Go function pointer to a C function pointer. // The indirect here is converting from a Go function pointer to a C function pointer.
......
...@@ -660,6 +660,7 @@ var ( ...@@ -660,6 +660,7 @@ var (
nosplit bool nosplit bool
nowritebarrier bool nowritebarrier bool
systemstack bool systemstack bool
norace bool
) )
var debuglive int var debuglive int
......
...@@ -1390,6 +1390,7 @@ xfndcl: ...@@ -1390,6 +1390,7 @@ xfndcl:
$$.Nbody = $3; $$.Nbody = $3;
$$.Func.Endlineno = lineno; $$.Func.Endlineno = lineno;
$$.Noescape = noescape; $$.Noescape = noescape;
$$.Func.Norace = norace;
$$.Func.Nosplit = nosplit; $$.Func.Nosplit = nosplit;
$$.Func.Nowritebarrier = nowritebarrier; $$.Func.Nowritebarrier = nowritebarrier;
$$.Func.Systemstack = systemstack; $$.Func.Systemstack = systemstack;
...@@ -1579,6 +1580,7 @@ xdcl_list: ...@@ -1579,6 +1580,7 @@ xdcl_list:
} }
nointerface = false nointerface = false
noescape = false noescape = false
norace = false
nosplit = false nosplit = false
nowritebarrier = false nowritebarrier = false
systemstack = false systemstack = false
......
...@@ -1612,6 +1612,11 @@ func getlinepragma() int { ...@@ -1612,6 +1612,11 @@ func getlinepragma() int {
return c return c
} }
if verb == "go:norace" {
norace = true
return c
}
if verb == "go:nosplit" { if verb == "go:nosplit" {
nosplit = true nosplit = true
return c return c
......
...@@ -42,6 +42,7 @@ func ispkgin(pkgs []string) bool { ...@@ -42,6 +42,7 @@ func ispkgin(pkgs []string) bool {
return false return false
} }
// TODO(rsc): Remove. Put //go:norace on forkAndExecInChild instead.
func isforkfunc(fn *Node) bool { func isforkfunc(fn *Node) bool {
// Special case for syscall.forkAndExecInChild. // Special case for syscall.forkAndExecInChild.
// In the child, this function must not acquire any locks, because // In the child, this function must not acquire any locks, because
...@@ -52,7 +53,7 @@ func isforkfunc(fn *Node) bool { ...@@ -52,7 +53,7 @@ func isforkfunc(fn *Node) bool {
} }
func racewalk(fn *Node) { func racewalk(fn *Node) {
if ispkgin(omit_pkgs) || isforkfunc(fn) { if ispkgin(omit_pkgs) || isforkfunc(fn) || fn.Func.Norace {
return return
} }
......
...@@ -169,6 +169,7 @@ type Func struct { ...@@ -169,6 +169,7 @@ type Func struct {
Endlineno int32 Endlineno int32
Norace bool // func must not have race detector annotations
Nosplit bool // func should not execute on separate stack Nosplit bool // func should not execute on separate stack
Nowritebarrier bool // emit compiler error instead of write barrier Nowritebarrier bool // emit compiler error instead of write barrier
Dupok bool // duplicate definitions ok Dupok bool // duplicate definitions ok
......
This diff is collapsed.
...@@ -822,6 +822,14 @@ func (t *tester) raceTest() error { ...@@ -822,6 +822,14 @@ func (t *tester) raceTest() error {
if err := t.dirCmd("src", "go", "test", "-race", "-short", "flag", "os/exec").Run(); err != nil { if err := t.dirCmd("src", "go", "test", "-race", "-short", "flag", "os/exec").Run(); err != nil {
return err return err
} }
if t.cgoEnabled {
env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
cmd := t.dirCmd("misc/cgo/test", "go", "test", "-race", "-short")
cmd.Env = env
if err := cmd.Run(); err != nil {
return err
}
}
if t.extLink() { if t.extLink() {
// Test with external linking; see issue 9133. // Test with external linking; see issue 9133.
if err := t.dirCmd("src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", "flag", "os/exec").Run(); err != nil { if err := t.dirCmd("src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", "flag", "os/exec").Run(); err != nil {
......
...@@ -37,6 +37,7 @@ var _runtime_cgo_panic_internal byte ...@@ -37,6 +37,7 @@ var _runtime_cgo_panic_internal byte
//go:cgo_export_static _cgo_panic //go:cgo_export_static _cgo_panic
//go:cgo_export_dynamic _cgo_panic //go:cgo_export_dynamic _cgo_panic
//go:nosplit //go:nosplit
//go:norace
func _cgo_panic(a unsafe.Pointer, n int32) { func _cgo_panic(a unsafe.Pointer, n int32) {
_runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_panic_internal), a, uintptr(n)) _runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_panic_internal), a, uintptr(n))
} }
......
...@@ -164,6 +164,7 @@ func signal_ignore(s uint32) { ...@@ -164,6 +164,7 @@ func signal_ignore(s uint32) {
// This runs on a foreign stack, without an m or a g. No stack split. // This runs on a foreign stack, without an m or a g. No stack split.
//go:nosplit //go:nosplit
//go:norace
func badsignal(sig uintptr) { func badsignal(sig uintptr) {
cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
} }
......
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