]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: dowidth more in the front end
authorJosh Bleecher Snyder <josharian@gmail.com>
Thu, 27 Apr 2017 16:27:52 +0000 (09:27 -0700)
committerJosh Bleecher Snyder <josharian@gmail.com>
Thu, 27 Apr 2017 22:10:32 +0000 (22:10 +0000)
dowidth is fundamentally unsafe to call from the back end;
it will cause data races.

Replace all calls to dowidth in the backend with
assertions that the width has been calculated.

Then fix all the cases in which that was not so,
including the cases from #20145.

Fixes #20145.

Change-Id: Idba3d19d75638851a30ec2ebcdb703c19da3e92b
Reviewed-on: https://go-review.googlesource.com/41970
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/gc/walk.go
src/cmd/compile/internal/types/type.go
test/fixedbugs/issue20145.go [new file with mode: 0644]

index e9f31e68c46c8556a422fbf7df46691512a7532d..08c96c36883ab078d818b4536d4350bd09adafc0 100644 (file)
@@ -642,13 +642,6 @@ func (s *state) stmt(n *Node) {
                        return
                }
 
-               var t *types.Type
-               if n.Right != nil {
-                       t = n.Right.Type
-               } else {
-                       t = n.Left.Type
-               }
-
                // Evaluate RHS.
                rhs := n.Right
                if rhs != nil {
@@ -682,6 +675,23 @@ func (s *state) stmt(n *Node) {
                                }
                        }
                }
+
+               if isblank(n.Left) {
+                       // _ = rhs
+                       // Just evaluate rhs for side-effects.
+                       if rhs != nil {
+                               s.expr(rhs)
+                       }
+                       return
+               }
+
+               var t *types.Type
+               if n.Right != nil {
+                       t = n.Right.Type
+               } else {
+                       t = n.Left.Type
+               }
+
                var r *ssa.Value
                deref := !canSSAType(t)
                if deref {
@@ -1509,8 +1519,8 @@ func (s *state) expr(n *Node) *ssa.Value {
                        return v
                }
 
-               dowidth(from)
-               dowidth(to)
+               from.AssertWidthCalculated()
+               to.AssertWidthCalculated()
                if from.Width != to.Width {
                        s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
                        return nil
@@ -2311,7 +2321,7 @@ func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask)
                return
        }
        t := left.Type
-       dowidth(t)
+       t.AssertWidthCalculated()
        if s.canSSA(left) {
                if deref {
                        s.Fatalf("can SSA LHS %v but not RHS %s", left, right)
@@ -3085,7 +3095,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
                }
                rcvr = s.newValue1(ssa.OpIData, types.Types[TUINTPTR], i)
        }
-       dowidth(fn.Type)
+       fn.Type.AssertWidthCalculated()
        stksize := fn.Type.ArgWidth() // includes receiver
 
        // Run all argument assignments. The arg slots have already
@@ -3341,7 +3351,7 @@ func (s *state) canSSA(n *Node) bool {
 
 // canSSA reports whether variables of type t are SSA-able.
 func canSSAType(t *types.Type) bool {
-       dowidth(t)
+       t.AssertWidthCalculated()
        if t.Width > int64(4*Widthptr) {
                // 4*Widthptr is an arbitrary constant. We want it
                // to be at least 3*Widthptr so slices can be registerized.
@@ -4962,8 +4972,7 @@ func (e *ssafn) namedAuto(name string, typ ssa.Type, pos src.XPos) ssa.GCNode {
        n.Esc = EscNever
        n.Name.Curfn = e.curfn
        e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
-
-       dowidth(t)
+       t.AssertWidthCalculated()
        return n
 }
 
index 3622b9af579cfb175e6f62607230210470f1d0df..764374aa2681317fc9786eeb18121d26fe84e0be 100644 (file)
@@ -1621,6 +1621,7 @@ OpSwitch:
                                        continue
                                }
                                as[i] = assignconv(n, t.Elem(), "append")
+                               checkwidth(as[i].Type) // ensure width is calculated for backend
                        }
                }
 
@@ -1691,6 +1692,7 @@ OpSwitch:
        case OCONV:
                ok |= Erv
                saveorignode(n)
+               checkwidth(n.Type) // ensure width is calculated for backend
                n.Left = typecheck(n.Left, Erv)
                n.Left = convlit1(n.Left, n.Type, true, noReuse)
                t := n.Left.Type
@@ -3307,6 +3309,9 @@ func typecheckas(n *Node) {
        if n.Left.Typecheck() == 0 {
                n.Left = typecheck(n.Left, Erv|Easgn)
        }
+       if !isblank(n.Left) {
+               checkwidth(n.Left.Type) // ensure width is calculated for backend
+       }
 }
 
 func checkassignto(src *types.Type, dst *Node) {
index cd41a24c091183c854f11b766927b488be5e9f20..1196421d7c97a339f57d4f48e1b96938b8a298b3 100644 (file)
@@ -2611,7 +2611,7 @@ func vmatch1(l *Node, r *Node) bool {
 }
 
 // paramstoheap returns code to allocate memory for heap-escaped parameters
-// and to copy non-result prameters' values from the stack.
+// and to copy non-result parameters' values from the stack.
 func paramstoheap(params *types.Type) []*Node {
        var nn []*Node
        for _, t := range params.Fields().Slice() {
index b0be122d0ae8545ff892fcd58e053011c3e86dba..62041454caca8ab600b1845b975f59e964527671 100644 (file)
@@ -849,6 +849,13 @@ func (t *Type) WidthCalculated() bool {
        return t.Align > 0
 }
 
+// AssertWidthCalculated calls Fatalf if t's width has not yet been calculated.
+func (t *Type) AssertWidthCalculated() {
+       if !t.WidthCalculated() {
+               Fatalf("width not calculated: %v", t)
+       }
+}
+
 // ArgWidth returns the total aligned argument size for a function.
 // It includes the receiver, parameters, and results.
 func (t *Type) ArgWidth() int64 {
@@ -857,12 +864,12 @@ func (t *Type) ArgWidth() int64 {
 }
 
 func (t *Type) Size() int64 {
-       Dowidth(t)
+       t.AssertWidthCalculated()
        return t.Width
 }
 
 func (t *Type) Alignment() int64 {
-       Dowidth(t)
+       t.AssertWidthCalculated()
        return int64(t.Align)
 }
 
diff --git a/test/fixedbugs/issue20145.go b/test/fixedbugs/issue20145.go
new file mode 100644 (file)
index 0000000..67ba5ae
--- /dev/null
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 20145: some func types weren't dowidth-ed by the front end,
+// leading to races in the backend.
+
+package p
+
+func f() {
+       _ = (func())(nil)
+}