Commit 3b6e86f4 authored by Russ Cox's avatar Russ Cox

cmd/compile: fix race detector handling of OBLOCK nodes

Fixes #7561 correctly.
Fixes #9137.

Change-Id: I7f27e199d7101b785a7645f789e8fe41a405a86f
Reviewed-on: https://go-review.googlesource.com/11713Reviewed-by: 's avatarDmitry Vyukov <dvyukov@google.com>
parent 117ddcb8
...@@ -434,6 +434,12 @@ func ordermapassign(n *Node, order *Order) { ...@@ -434,6 +434,12 @@ func ordermapassign(n *Node, order *Order) {
a = Nod(OAS, m, l.N) a = Nod(OAS, m, l.N)
typecheck(&a, Etop) typecheck(&a, Etop)
post = list(post, a) post = list(post, a)
} else if flag_race != 0 && n.Op == OAS2FUNC && !isblank(l.N) {
m = l.N
l.N = ordertemp(m.Type, order, false)
a = Nod(OAS, m, l.N)
typecheck(&a, Etop)
post = list(post, a)
} }
} }
......
...@@ -147,27 +147,27 @@ func racewalknode(np **Node, init **NodeList, wr int, skip int) { ...@@ -147,27 +147,27 @@ func racewalknode(np **Node, init **NodeList, wr int, skip int) {
goto ret goto ret
case OBLOCK: case OBLOCK:
if n.List == nil { var out *NodeList
goto ret for l := n.List; l != nil; l = l.Next {
} switch l.N.Op {
case OCALLFUNC, OCALLMETH, OCALLINTER:
switch n.List.N.Op { racewalknode(&l.N, &out, 0, 0)
// Blocks are used for multiple return function calls. out = list(out, l.N)
// x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]} // Scan past OAS nodes copying results off stack.
// We don't want to instrument between the statements because it will // Those must not be instrumented, because the
// smash the results. // instrumentation calls will smash the results.
case OCALLFUNC, OCALLMETH, OCALLINTER: // The assignments are to temporaries, so they cannot
racewalknode(&n.List.N, &n.List.N.Ninit, 0, 0) // be involved in races and need not be instrumented.
for l.Next != nil && l.Next.N.Op == OAS && iscallret(l.Next.N.Right) {
var fini *NodeList l = l.Next
racewalklist(n.List.Next, &fini) out = list(out, l.N)
n.List = concat(n.List, fini) }
default:
// Ordinary block, for loop initialization or inlined bodies. racewalknode(&l.N, &out, 0, 0)
default: out = list(out, l.N)
racewalklist(n.List, nil) }
} }
n.List = out
goto ret goto ret
case ODEFER: case ODEFER:
......
...@@ -2127,6 +2127,11 @@ func callnew(t *Type) *Node { ...@@ -2127,6 +2127,11 @@ func callnew(t *Type) *Node {
return mkcall1(fn, Ptrto(t), nil, typename(t)) return mkcall1(fn, Ptrto(t), nil, typename(t))
} }
func iscallret(n *Node) bool {
n = outervalue(n)
return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
}
func isstack(n *Node) bool { func isstack(n *Node) bool {
n = outervalue(n) n = outervalue(n)
......
...@@ -173,3 +173,12 @@ func TestIssue8102(t *testing.T) { ...@@ -173,3 +173,12 @@ func TestIssue8102(t *testing.T) {
} }
} }
} }
func TestIssue9137(t *testing.T) {
a := []string{"a"}
i := 0
a[i], a[len(a)-1], a = a[len(a)-1], "", a[:len(a)-1]
if len(a) != 0 || a[:1][0] != "" {
t.Errorf("mangled a: %q %q", a, a[:1])
}
}
...@@ -1587,6 +1587,110 @@ func TestRaceBlockAs(t *testing.T) { ...@@ -1587,6 +1587,110 @@ func TestRaceBlockAs(t *testing.T) {
<-c <-c
} }
func TestRaceBlockCall1(t *testing.T) {
done := make(chan bool)
x, y := 0, 0
go func() {
f := func() (int, int) {
return 42, 43
}
x, y = f()
done <- true
}()
_ = x
<-done
if x != 42 || y != 43 {
panic("corrupted data")
}
}
func TestRaceBlockCall2(t *testing.T) {
done := make(chan bool)
x, y := 0, 0
go func() {
f := func() (int, int) {
return 42, 43
}
x, y = f()
done <- true
}()
_ = y
<-done
if x != 42 || y != 43 {
panic("corrupted data")
}
}
func TestRaceBlockCall3(t *testing.T) {
done := make(chan bool)
var x *int
y := 0
go func() {
f := func() (*int, int) {
i := 42
return &i, 43
}
x, y = f()
done <- true
}()
_ = x
<-done
if *x != 42 || y != 43 {
panic("corrupted data")
}
}
func TestRaceBlockCall4(t *testing.T) {
done := make(chan bool)
x := 0
var y *int
go func() {
f := func() (int, *int) {
i := 43
return 42, &i
}
x, y = f()
done <- true
}()
_ = y
<-done
if x != 42 || *y != 43 {
panic("corrupted data")
}
}
func TestRaceBlockCall5(t *testing.T) {
done := make(chan bool)
var x *int
y := 0
go func() {
f := func() (*int, int) {
i := 42
return &i, 43
}
x, y = f()
done <- true
}()
_ = y
<-done
if *x != 42 || y != 43 {
panic("corrupted data")
}
}
func TestRaceBlockCall6(t *testing.T) {
done := make(chan bool)
x := 0
var y *int
go func() {
f := func() (int, *int) {
i := 43
return 42, &i
}
x, y = f()
done <- true
}()
_ = x
<-done
if x != 42 || *y != 43 {
panic("corrupted data")
}
}
func TestRaceSliceSlice(t *testing.T) { func TestRaceSliceSlice(t *testing.T) {
c := make(chan bool, 1) c := make(chan bool, 1)
x := make([]int, 10) x := make([]int, 10)
......
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