]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/gc: add missing write barrier in append(x, BigStructWithPointers)
authorRuss Cox <rsc@golang.org>
Mon, 18 May 2015 20:54:59 +0000 (16:54 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 19 May 2015 15:28:29 +0000 (15:28 +0000)
Fixes #10897.

Change-Id: I5c2d1f9d26333e2b2a0613ebf496daa465e07c24
Reviewed-on: https://go-review.googlesource.com/10221
Reviewed-by: Austin Clements <austin@google.com>
src/cmd/internal/gc/cgen.go
test/writebarrier.go

index bb022b835123715073df66adc4fe623f92b833d8..002439ce36129ad677b212c1c72ece1baf9c46d4 100644 (file)
@@ -2156,14 +2156,27 @@ func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) {
        }
 }
 
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
+// stkof returns n's offset from SP if n is on the stack
+// (either a local variable or the return value from a function call
+// or the arguments to a function call).
+// If n is not on the stack, stkof returns -1000.
+// If n is on the stack but in an unknown location
+// (due to array index arithmetic), stkof returns +1000.
+//
+// NOTE(rsc): It is possible that the ODOT and OINDEX cases
+// are not relevant here, since it shouldn't be possible for them
+// to be involved in an overlapping copy. Only function results
+// from one call and the arguments to the next can overlap in
+// any non-trivial way. If they can be dropped, then this function
+// becomes much simpler and also more trustworthy.
+// The fact that it works at all today is probably due to the fact
+// that ODOT and OINDEX are irrelevant.
 func stkof(n *Node) int64 {
        switch n.Op {
        case OINDREG:
+               if n.Reg != int16(Thearch.REGSP) {
+                       return -1000 // not on stack
+               }
                return n.Xoffset
 
        case ODOT:
@@ -2172,7 +2185,7 @@ func stkof(n *Node) int64 {
                        break
                }
                off := stkof(n.Left)
-               if off == -1000 || off == 1000 {
+               if off == -1000 || off == +1000 {
                        return off
                }
                return off + n.Xoffset
@@ -2183,13 +2196,13 @@ func stkof(n *Node) int64 {
                        break
                }
                off := stkof(n.Left)
-               if off == -1000 || off == 1000 {
+               if off == -1000 || off == +1000 {
                        return off
                }
                if Isconst(n.Right, CTINT) {
                        return off + t.Type.Width*Mpgetfix(n.Right.Val.U.(*Mpint))
                }
-               return 1000
+               return +1000 // on stack but not sure exactly where
 
        case OCALLMETH, OCALLINTER, OCALLFUNC:
                t := n.Left.Type
@@ -2210,7 +2223,7 @@ func stkof(n *Node) int64 {
 
        // botch - probably failing to recognize address
        // arithmetic on the above. eg INDEX and DOT
-       return -1000
+       return -1000 // not on stack
 }
 
 /*
index b24af9a14d3449abd46b6d5665e6ef91b585a393..9b741a60dfc2acf63a5c1ac43d3b96155221da8a 100644 (file)
@@ -128,3 +128,19 @@ func f13(x []int, y *[]int) {
 func f14(y *[]int) {
        *y = append(*y, 1) // ERROR "write barrier"
 }
+
+type T1 struct {
+       X *int
+}
+
+func f15(x []T1, y T1) []T1 {
+       return append(x, y) // ERROR "write barrier"
+}
+
+type T8 struct {
+       X [8]*int
+}
+
+func f16(x []T8, y T8) []T8 {
+       return append(x, y) // ERROR "write barrier"
+}