]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix race detector handling of OBLOCK nodes
authorRuss Cox <rsc@golang.org>
Mon, 29 Jun 2015 19:17:14 +0000 (15:17 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 30 Jun 2015 19:25:18 +0000 (19:25 +0000)
Fixes #7561 correctly.
Fixes #9137.

Change-Id: I7f27e199d7101b785a7645f789e8fe41a405a86f
Reviewed-on: https://go-review.googlesource.com/11713
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
src/cmd/compile/internal/gc/order.go
src/cmd/compile/internal/gc/racewalk.go
src/cmd/compile/internal/gc/walk.go
src/runtime/race/race_test.go
src/runtime/race/testdata/mop_test.go

index 7d89a821bc07350c33466decde492731b8598d4f..799a17e18426f890ba2b8df6b0e2da925d2cda73 100644 (file)
@@ -434,6 +434,12 @@ func ordermapassign(n *Node, order *Order) {
                                a = Nod(OAS, m, l.N)
                                typecheck(&a, Etop)
                                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)
                        }
                }
 
index 2664e0cd6d839f74ad62d10e690caf6585b8e06c..a360c4de653ef55aeac77802cc097aa9ffaf6ea9 100644 (file)
@@ -147,27 +147,27 @@ func racewalknode(np **Node, init **NodeList, wr int, skip int) {
                goto ret
 
        case OBLOCK:
-               if n.List == nil {
-                       goto ret
-               }
-
-               switch n.List.N.Op {
-               // Blocks are used for multiple return function calls.
-               // x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]}
-               // We don't want to instrument between the statements because it will
-               // smash the results.
-               case OCALLFUNC, OCALLMETH, OCALLINTER:
-                       racewalknode(&n.List.N, &n.List.N.Ninit, 0, 0)
-
-                       var fini *NodeList
-                       racewalklist(n.List.Next, &fini)
-                       n.List = concat(n.List, fini)
-
-                       // Ordinary block, for loop initialization or inlined bodies.
-               default:
-                       racewalklist(n.List, nil)
+               var out *NodeList
+               for l := n.List; l != nil; l = l.Next {
+                       switch l.N.Op {
+                       case OCALLFUNC, OCALLMETH, OCALLINTER:
+                               racewalknode(&l.N, &out, 0, 0)
+                               out = list(out, l.N)
+                               // Scan past OAS nodes copying results off stack.
+                               // Those must not be instrumented, because the
+                               // instrumentation calls will smash the results.
+                               // The assignments are to temporaries, so they cannot
+                               // be involved in races and need not be instrumented.
+                               for l.Next != nil && l.Next.N.Op == OAS && iscallret(l.Next.N.Right) {
+                                       l = l.Next
+                                       out = list(out, l.N)
+                               }
+                       default:
+                               racewalknode(&l.N, &out, 0, 0)
+                               out = list(out, l.N)
+                       }
                }
-
+               n.List = out
                goto ret
 
        case ODEFER:
index f5ae9fbe21559ba140431b4bd3fb37de68f099a5..626b26fec7f3462676656a6eee7f47ca72ab3c52 100644 (file)
@@ -2127,6 +2127,11 @@ func callnew(t *Type) *Node {
        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 {
        n = outervalue(n)
 
index 37272c751c6bf3758ebf07a7fcdd2e4a133a1cd8..6898e749007c2dfebe766f8902191fc61e0823e7 100644 (file)
@@ -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])
+       }
+}
index 7f95051a8c30d30d6f58fdcbd5352d13d49bb309..d7cbc98f95a2fce6ff22922849fbd053d0f8bcc8 100644 (file)
@@ -1587,6 +1587,110 @@ func TestRaceBlockAs(t *testing.T) {
        <-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) {
        c := make(chan bool, 1)
        x := make([]int, 10)