]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: mark unused values as invalid to prevent problems in expandCalls
authorDavid Chase <drchase@google.com>
Fri, 2 Apr 2021 16:33:23 +0000 (12:33 -0400)
committerDavid Chase <drchase@google.com>
Fri, 2 Apr 2021 17:58:59 +0000 (17:58 +0000)
Leftover values that have been replaced can cause problems in later
passes (within expandCalls).  For example, a struct select that
itself yields a struct will have a problematic rewrite, if the chance
is presented.

Updates #40724.

Change-Id: I1b445c47c301c3705f7fc0a9d39f1f5c84f4e190
Reviewed-on: https://go-review.googlesource.com/c/go/+/306869
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/compile/internal/ssa/expand_calls.go
test/abi/zombie_struct_select.go [new file with mode: 0644]

index a5fe6f4d29c5dd769e1b84d61728ce36d44fd40d..b6683d076df16e4b239909d9ebcb3307af5c9370 100644 (file)
@@ -941,6 +941,11 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
 // stores (or later, register movement).  Extra args for interface and closure calls are ignored,
 // but removed.
 func (x *expandState) rewriteArgs(v *Value, firstArg int) (*Value, []*Value) {
+       if x.debug {
+               x.indent(3)
+               defer x.indent(-3)
+               x.Printf("rewriteArgs(%s; %d)\n", v.LongString(), firstArg)
+       }
        // Thread the stores on the memory arg
        aux := v.Aux.(*AuxCall)
        pos := v.Pos.WithNotStmt()
@@ -969,7 +974,7 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) (*Value, []*Value) {
                                aOffset = aux.OffsetOfArg(auxI)
                        }
                        if x.debug {
-                               x.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset)
+                               x.Printf("...storeArg %s, %v, %d\n", a.LongString(), aType, aOffset)
                        }
                        rc.init(aRegs, aux.abiInfo, result, x.sp)
                        mem = x.storeArgOrLoad(pos, v.Block, a, mem, aType, aOffset, 0, rc)
@@ -1056,6 +1061,7 @@ func expandCalls(f *Func) {
                        }
                }
                if isBlockMultiValueExit(b) {
+                       x.indent(3)
                        // Very similar to code in rewriteArgs, but results instead of args.
                        v := b.Controls[0]
                        m0 := v.MemoryArg()
@@ -1063,7 +1069,12 @@ func expandCalls(f *Func) {
                        aux := f.OwnAux
                        pos := v.Pos.WithNotStmt()
                        allResults := []*Value{}
+                       if x.debug {
+                               x.Printf("multiValueExit rewriting %s\n", v.LongString())
+                       }
+                       var oldArgs []*Value
                        for j, a := range v.Args[:len(v.Args)-1] {
+                               oldArgs = append(oldArgs, a)
                                i := int64(j)
                                auxType := aux.TypeOfResult(i)
                                auxBase := b.NewValue2A(v.Pos, OpLocalAddr, types.NewPtr(auxType), aux.NameOfResult(i), x.sp, mem)
@@ -1101,6 +1112,18 @@ func expandCalls(f *Func) {
                        v.AddArg(mem)
                        v.Type = types.NewResults(append(abi.RegisterTypes(aux.abiInfo.OutParams()), types.TypeMem))
                        b.SetControl(v)
+                       for _, a := range oldArgs {
+                               if a.Uses == 0 {
+                                       if x.debug {
+                                               x.Printf("...marking %v unused\n", a.LongString())
+                                       }
+                                       a.reset(OpInvalid)
+                               }
+                       }
+                       if x.debug {
+                               x.Printf("...multiValueExit new result %s\n", v.LongString())
+                       }
+                       x.indent(-3)
                }
        }
 
diff --git a/test/abi/zombie_struct_select.go b/test/abi/zombie_struct_select.go
new file mode 100644 (file)
index 0000000..d0cab98
--- /dev/null
@@ -0,0 +1,36 @@
+// run
+
+// Copyright 2021 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.
+
+package main
+
+type patchlist struct {
+       head, tail uint32
+}
+
+type frag struct {
+       i   uint32
+       out patchlist
+}
+
+//go:noinline
+//go:registerparams
+func patch(l patchlist, i uint32) {
+}
+
+//go:noinline
+//go:registerparams
+func badbad(f1, f2 frag) frag {
+       // concat of failure is failure
+       if f1.i == 0 || f2.i == 0 { // internal compiler error: 'badbad': incompatible OpArgIntReg [4]: v42 and v26
+               return frag{}
+       }
+       patch(f1.out, f2.i)
+       return frag{f1.i, f2.out}
+}
+
+func main() {
+       badbad(frag{i: 2}, frag{i: 3})
+}