]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add test case for issue 38068
authorThan McIntosh <thanm@google.com>
Sun, 17 May 2020 18:36:55 +0000 (14:36 -0400)
committerThan McIntosh <thanm@google.com>
Fri, 29 May 2020 20:31:43 +0000 (20:31 +0000)
New test case for issue 38068, which deals with build reproducibility:
do a pair of compilations, the first with the concurrent back end
turned on, and the second with -c=1, then check to make sure we get
the same output (using a test case that triggers late inlining into
wrapper methods).

Updates #38068.

Change-Id: I4afaf78898706a66985f09d18f6f6f29876c9017
Reviewed-on: https://go-review.googlesource.com/c/go/+/234417
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/reproduciblebuilds_test.go
src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go [new file with mode: 0644]

index 59d1edb9e8d510a409d7cdd8926b20e11e7ec819..8101e440793ee9e529a6318f342a83a0866a19e2 100644 (file)
@@ -60,3 +60,53 @@ func TestReproducibleBuilds(t *testing.T) {
                })
        }
 }
+
+func TestIssue38068(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+       t.Parallel()
+
+       // Compile a small package with and without the concurrent
+       // backend, then check to make sure that the resulting archives
+       // are identical.  Note: this uses "go tool compile" instead of
+       // "go build" since the latter will generate differnent build IDs
+       // if it sees different command line flags.
+       scenarios := []struct {
+               tag     string
+               args    string
+               libpath string
+       }{
+               {tag: "serial", args: "-c=1"},
+               {tag: "concurrent", args: "-c=2"}}
+
+       tmpdir, err := ioutil.TempDir("", "TestIssue38068")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer os.RemoveAll(tmpdir)
+
+       src := filepath.Join("testdata", "reproducible", "issue38068.go")
+       for i := range scenarios {
+               s := &scenarios[i]
+               s.libpath = filepath.Join(tmpdir, s.tag+".a")
+               // Note: use of "-p" required in order for DWARF to be generated.
+               cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-trimpath", "-p=issue38068", "-buildid=", s.args, "-o", s.libpath, src)
+               out, err := cmd.CombinedOutput()
+               if err != nil {
+                       t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
+               }
+       }
+
+       readBytes := func(fn string) []byte {
+               payload, err := ioutil.ReadFile(fn)
+               if err != nil {
+                       t.Fatalf("failed to read executable '%s': %v", fn, err)
+               }
+               return payload
+       }
+
+       b1 := readBytes(scenarios[0].libpath)
+       b2 := readBytes(scenarios[1].libpath)
+       if !bytes.Equal(b1, b2) {
+               t.Fatalf("concurrent and serial builds produced different output")
+       }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go b/src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go
new file mode 100644 (file)
index 0000000..db5ca7d
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2020 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 issue38068
+
+// A type with a couple of inlinable, non-pointer-receiver methods
+// that have params and local variables.
+type A struct {
+       s    string
+       next *A
+       prev *A
+}
+
+// Inlinable, value-received method with locals and parms.
+func (a A) double(x string, y int) string {
+       if y == 191 {
+               a.s = ""
+       }
+       q := a.s + "a"
+       r := a.s + "b"
+       return q + r
+}
+
+// Inlinable, value-received method with locals and parms.
+func (a A) triple(x string, y int) string {
+       q := a.s
+       if y == 998877 {
+               a.s = x
+       }
+       r := a.s + a.s
+       return q + r
+}
+
+type methods struct {
+       m1 func(a *A, x string, y int) string
+       m2 func(a *A, x string, y int) string
+}
+
+// Now a function that makes references to the methods via pointers,
+// which should trigger the wrapper generation.
+func P(a *A, ms *methods) {
+       if a != nil {
+               defer func() { println("done") }()
+       }
+       println(ms.m1(a, "a", 2))
+       println(ms.m2(a, "b", 3))
+}
+
+func G(x *A, n int) {
+       if n <= 0 {
+               println(n)
+               return
+       }
+       // Address-taken local of type A, which will insure that the
+       // compiler's dtypesym() routine will create a method wrapper.
+       var a, b A
+       a.next = x
+       a.prev = &b
+       x = &a
+       G(x, n-2)
+}
+
+var M methods
+
+func F() {
+       M.m1 = (*A).double
+       M.m2 = (*A).triple
+       G(nil, 100)
+}