summaryrefslogtreecommitdiff
path: root/libgo/misc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2018-01-09 01:23:08 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-01-09 01:23:08 +0000
commit1a2f01efa63036a5104f203a4789e682c0e0915d (patch)
tree373e15778dc8295354584e1f86915ae493b604ff /libgo/misc
parent8799df67f2dab88f9fda11739c501780a85575e2 (diff)
libgo: update to Go1.10beta1
Update the Go library to the 1.10beta1 release. Requires a few changes to the compiler for modifications to the map runtime code, and to handle some nowritebarrier cases in the runtime. Reviewed-on: https://go-review.googlesource.com/86455 gotools/: * Makefile.am (go_cmd_vet_files): New variable. (go_cmd_buildid_files, go_cmd_test2json_files): New variables. (s-zdefaultcc): Change from constants to functions. (noinst_PROGRAMS): Add vet, buildid, and test2json. (cgo$(EXEEXT)): Link against $(LIBGOTOOL). (vet$(EXEEXT)): New target. (buildid$(EXEEXT)): New target. (test2json$(EXEEXT)): New target. (install-exec-local): Install all $(noinst_PROGRAMS). (uninstall-local): Uninstasll all $(noinst_PROGRAMS). (check-go-tool): Depend on $(noinst_PROGRAMS). Copy down objabi.go. (check-runtime): Depend on $(noinst_PROGRAMS). (check-cgo-test, check-carchive-test): Likewise. (check-vet): New target. (check): Depend on check-vet. Look at cmd_vet-testlog. (.PHONY): Add check-vet. * Makefile.in: Rebuild. From-SVN: r256365
Diffstat (limited to 'libgo/misc')
-rw-r--r--libgo/misc/cgo/errors/errors_test.go161
-rw-r--r--libgo/misc/cgo/errors/issue13635.go24
-rw-r--r--libgo/misc/cgo/errors/ptr_test.go (renamed from libgo/misc/cgo/errors/ptr.go)198
-rw-r--r--libgo/misc/cgo/errors/src/err1.go (renamed from libgo/misc/cgo/errors/err1.go)0
-rw-r--r--libgo/misc/cgo/errors/src/err2.go (renamed from libgo/misc/cgo/errors/err2.go)0
-rw-r--r--libgo/misc/cgo/errors/src/err3.go (renamed from libgo/misc/cgo/errors/err3.go)0
-rw-r--r--libgo/misc/cgo/errors/src/err4.go15
-rw-r--r--libgo/misc/cgo/errors/src/issue11097a.go (renamed from libgo/misc/cgo/errors/issue11097a.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue11097b.go (renamed from libgo/misc/cgo/errors/issue11097b.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue13129.go (renamed from libgo/misc/cgo/errors/issue13129.go)2
-rw-r--r--libgo/misc/cgo/errors/src/issue13423.go (renamed from libgo/misc/cgo/errors/issue13423.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue13467.go15
-rw-r--r--libgo/misc/cgo/errors/src/issue13635.go24
-rw-r--r--libgo/misc/cgo/errors/src/issue13830.go (renamed from libgo/misc/cgo/errors/issue13830.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue14669.go (renamed from libgo/misc/cgo/errors/issue14669.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue16116.go (renamed from libgo/misc/cgo/errors/issue16116.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue16591.go (renamed from libgo/misc/cgo/errors/issue16591.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue18452.go (renamed from libgo/misc/cgo/errors/issue18452.go)4
-rw-r--r--libgo/misc/cgo/errors/src/issue18889.go (renamed from libgo/misc/cgo/errors/issue18889.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue7757.go (renamed from libgo/misc/cgo/errors/issue7757.go)0
-rw-r--r--libgo/misc/cgo/errors/src/issue8442.go (renamed from libgo/misc/cgo/errors/issue8442.go)0
-rw-r--r--libgo/misc/cgo/errors/src/long_double_size.go16
-rw-r--r--libgo/misc/cgo/errors/src/malloc.go (renamed from libgo/misc/cgo/errors/malloc.go)0
-rw-r--r--libgo/misc/cgo/errors/test.bash75
-rw-r--r--libgo/misc/cgo/life/main.go5
-rw-r--r--libgo/misc/cgo/stdio/chain.go2
-rw-r--r--libgo/misc/cgo/stdio/fib.go2
-rw-r--r--libgo/misc/cgo/stdio/hello.go2
-rw-r--r--libgo/misc/cgo/test/cgo_test.go6
-rw-r--r--libgo/misc/cgo/test/issue18720.go30
-rw-r--r--libgo/misc/cgo/test/issue19832.go16
-rw-r--r--libgo/misc/cgo/test/issue20910.c19
-rw-r--r--libgo/misc/cgo/test/issue20910.go19
-rw-r--r--libgo/misc/cgo/test/issue21668.go13
-rw-r--r--libgo/misc/cgo/test/issue21708.go16
-rw-r--r--libgo/misc/cgo/test/issue21809.go45
-rw-r--r--libgo/misc/cgo/test/issue21897.go56
-rw-r--r--libgo/misc/cgo/test/issue21897b.go13
-rw-r--r--libgo/misc/cgo/test/issue22958.go24
-rw-r--r--libgo/misc/cgo/test/issue6907.go33
-rw-r--r--libgo/misc/cgo/test/issue6907export.go30
-rw-r--r--libgo/misc/cgo/test/issue6907export_c.c11
-rw-r--r--libgo/misc/cgo/test/issue7978.go9
-rw-r--r--libgo/misc/cgo/testcarchive/carchive_test.go28
-rw-r--r--libgo/misc/cgo/testcshared/cshared_test.go479
-rw-r--r--libgo/misc/cgo/testcshared/test.bash193
-rw-r--r--libgo/misc/cgo/testplugin/src/host/host.go32
-rw-r--r--libgo/misc/cgo/testplugin/src/issue18584/main.go23
-rw-r--r--libgo/misc/cgo/testplugin/src/issue18584/plugin.go19
-rw-r--r--libgo/misc/cgo/testplugin/src/issue19418/main.go29
-rw-r--r--libgo/misc/cgo/testplugin/src/issue19418/plugin.go7
-rw-r--r--libgo/misc/cgo/testplugin/src/issue19529/plugin.go15
-rw-r--r--libgo/misc/cgo/testplugin/src/issue22175/main.go28
-rw-r--r--libgo/misc/cgo/testplugin/src/issue22175/plugin1.go21
-rw-r--r--libgo/misc/cgo/testplugin/src/issue22175/plugin2.go9
-rw-r--r--libgo/misc/cgo/testplugin/src/issue22295.pkg/main.go28
-rw-r--r--libgo/misc/cgo/testplugin/src/issue22295.pkg/plugin.go16
-rw-r--r--libgo/misc/cgo/testplugin/src/plugin1/plugin1.go20
-rw-r--r--libgo/misc/cgo/testplugin/src/plugin2/plugin2.go16
-rw-r--r--libgo/misc/cgo/testplugin/test.bash69
-rw-r--r--libgo/misc/cgo/testplugin/unnamed1/main.go (renamed from libgo/misc/cgo/testplugin/unnamed1.go)0
-rw-r--r--libgo/misc/cgo/testplugin/unnamed2/main.go (renamed from libgo/misc/cgo/testplugin/unnamed2.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/cc_test.go441
-rw-r--r--libgo/misc/cgo/testsanitizers/cshared_test.go74
-rw-r--r--libgo/misc/cgo/testsanitizers/msan_test.go55
-rw-r--r--libgo/misc/cgo/testsanitizers/src/msan.go (renamed from libgo/misc/cgo/testsanitizers/msan.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/msan2.go (renamed from libgo/misc/cgo/testsanitizers/msan2.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/msan2_cmsan.go38
-rw-r--r--libgo/misc/cgo/testsanitizers/src/msan3.go (renamed from libgo/misc/cgo/testsanitizers/msan3.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/msan4.go (renamed from libgo/misc/cgo/testsanitizers/msan4.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/msan5.go (renamed from libgo/misc/cgo/testsanitizers/msan5.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/msan_fail.go (renamed from libgo/misc/cgo/testsanitizers/msan_fail.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/msan_shared.go (renamed from libgo/misc/cgo/testsanitizers/msan_shared.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan.go (renamed from libgo/misc/cgo/testsanitizers/tsan.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan10.go (renamed from libgo/misc/cgo/testsanitizers/tsan10.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan11.go (renamed from libgo/misc/cgo/testsanitizers/tsan11.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan12.go (renamed from libgo/misc/cgo/testsanitizers/tsan12.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan2.go (renamed from libgo/misc/cgo/testsanitizers/tsan2.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan3.go (renamed from libgo/misc/cgo/testsanitizers/tsan3.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan4.go (renamed from libgo/misc/cgo/testsanitizers/tsan4.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan5.go (renamed from libgo/misc/cgo/testsanitizers/tsan5.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan6.go (renamed from libgo/misc/cgo/testsanitizers/tsan6.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan7.go (renamed from libgo/misc/cgo/testsanitizers/tsan7.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan8.go (renamed from libgo/misc/cgo/testsanitizers/tsan8.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan9.go (renamed from libgo/misc/cgo/testsanitizers/tsan9.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/src/tsan_shared.go (renamed from libgo/misc/cgo/testsanitizers/tsan_shared.go)0
-rw-r--r--libgo/misc/cgo/testsanitizers/test.bash233
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan_test.go56
-rw-r--r--libgo/misc/cgo/testshared/shared_test.go139
-rw-r--r--libgo/misc/cgo/testshared/src/depBase/dep.go2
-rw-r--r--libgo/misc/cgo/testshared/src/exe/exe.go2
-rw-r--r--libgo/misc/cgo/testshared/src/global/main.go71
-rw-r--r--libgo/misc/cgo/testshared/src/globallib/global.go17
93 files changed, 2306 insertions, 739 deletions
diff --git a/libgo/misc/cgo/errors/errors_test.go b/libgo/misc/cgo/errors/errors_test.go
new file mode 100644
index 00000000000..118187f23b8
--- /dev/null
+++ b/libgo/misc/cgo/errors/errors_test.go
@@ -0,0 +1,161 @@
+// 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.
+
+package errorstest
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func path(file string) string {
+ return filepath.Join("src", file)
+}
+
+func check(t *testing.T, file string) {
+ t.Run(file, func(t *testing.T) {
+ t.Parallel()
+
+ contents, err := ioutil.ReadFile(path(file))
+ if err != nil {
+ t.Fatal(err)
+ }
+ var errors []*regexp.Regexp
+ for i, line := range bytes.Split(contents, []byte("\n")) {
+ if bytes.HasSuffix(line, []byte("ERROR HERE")) {
+ re := regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf("%s:%d:", file, i+1)))
+ errors = append(errors, re)
+ continue
+ }
+
+ frags := bytes.SplitAfterN(line, []byte("ERROR HERE: "), 2)
+ if len(frags) == 1 {
+ continue
+ }
+ re, err := regexp.Compile(string(frags[1]))
+ if err != nil {
+ t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1])
+ continue
+ }
+ errors = append(errors, re)
+ }
+ if len(errors) == 0 {
+ t.Fatalf("cannot find ERROR HERE")
+ }
+ expect(t, file, errors)
+ })
+}
+
+func expect(t *testing.T, file string, errors []*regexp.Regexp) {
+ dir, err := ioutil.TempDir("", filepath.Base(t.Name()))
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ dst := filepath.Join(dir, strings.TrimSuffix(file, ".go"))
+ cmd := exec.Command("go", "build", "-gcflags=-L", "-o="+dst, path(file)) // TODO(gri) no need for -gcflags=-L if go tool is adjusted
+ out, err := cmd.CombinedOutput()
+ if err == nil {
+ t.Errorf("expected cgo to fail but it succeeded")
+ }
+
+ lines := bytes.Split(out, []byte("\n"))
+ for _, re := range errors {
+ found := false
+ for _, line := range lines {
+ if re.Match(line) {
+ t.Logf("found match for %#q: %q", re, line)
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("expected error output to contain %#q", re)
+ }
+ }
+
+ if t.Failed() {
+ t.Logf("actual output:\n%s", out)
+ }
+}
+
+func sizeofLongDouble(t *testing.T) int {
+ cmd := exec.Command("go", "run", path("long_double_size.go"))
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out)
+ }
+
+ i, err := strconv.Atoi(strings.TrimSpace(string(out)))
+ if err != nil {
+ t.Fatalf("long_double_size.go printed invalid size: %s", out)
+ }
+ return i
+}
+
+func TestReportsTypeErrors(t *testing.T) {
+ for _, file := range []string{
+ "err1.go",
+ "err2.go",
+ "err3.go",
+ "issue7757.go",
+ "issue8442.go",
+ "issue11097a.go",
+ "issue11097b.go",
+ "issue13129.go",
+ "issue13423.go",
+ "issue13467.go",
+ "issue13635.go",
+ "issue13830.go",
+ "issue16116.go",
+ "issue16591.go",
+ "issue18452.go",
+ "issue18889.go",
+ } {
+ check(t, file)
+ }
+
+ if sizeofLongDouble(t) > 8 {
+ check(t, "err4.go")
+ }
+}
+
+func TestToleratesOptimizationFlag(t *testing.T) {
+ for _, cflags := range []string{
+ "",
+ "-O",
+ } {
+ cflags := cflags
+ t.Run(cflags, func(t *testing.T) {
+ t.Parallel()
+
+ cmd := exec.Command("go", "build", path("issue14669.go"))
+ cmd.Env = append(os.Environ(), "CGO_CFLAGS="+cflags)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out)
+ }
+ })
+ }
+}
+
+func TestMallocCrashesOnNil(t *testing.T) {
+ t.Parallel()
+
+ cmd := exec.Command("go", "run", path("malloc.go"))
+ out, err := cmd.CombinedOutput()
+ if err == nil {
+ t.Logf("%#q:\n%s", strings.Join(cmd.Args, " "), out)
+ t.Fatalf("succeeded unexpectedly")
+ }
+}
diff --git a/libgo/misc/cgo/errors/issue13635.go b/libgo/misc/cgo/errors/issue13635.go
deleted file mode 100644
index 0ce2b1e83a1..00000000000
--- a/libgo/misc/cgo/errors/issue13635.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2015 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 13635: used to output error about C.unsignedchar.
-// This test tests all such types.
-
-package pkg
-
-import "C"
-
-func main() {
- var (
- _ C.uchar = "uc" // ERROR HERE
- _ C.schar = "sc" // ERROR HERE
- _ C.ushort = "us" // ERROR HERE
- _ C.uint = "ui" // ERROR HERE
- _ C.ulong = "ul" // ERROR HERE
- _ C.longlong = "ll" // ERROR HERE
- _ C.ulonglong = "ull" // ERROR HERE
- _ C.complexfloat = "cf" // ERROR HERE
- _ C.complexdouble = "cd" // ERROR HERE
- )
-}
diff --git a/libgo/misc/cgo/errors/ptr.go b/libgo/misc/cgo/errors/ptr_test.go
index 3e117666bff..d295a5849db 100644
--- a/libgo/misc/cgo/errors/ptr.go
+++ b/libgo/misc/cgo/errors/ptr_test.go
@@ -4,20 +4,18 @@
// Tests that cgo detects invalid pointer passing at runtime.
-package main
+package errorstest
import (
"bufio"
"bytes"
"fmt"
- "io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
- "runtime"
"strings"
- "sync"
+ "testing"
)
// ptrTest is the tests without the boilerplate.
@@ -344,7 +342,7 @@ var ptrTests = []ptrTest{
fail: false,
},
{
- // Issue #21306.
+ // Test preemption while entering a cgo call. Issue #21306.
name: "preempt-during-call",
c: `void f() {}`,
imports: []string{"runtime", "sync"},
@@ -353,219 +351,145 @@ var ptrTests = []ptrTest{
},
}
-func main() {
- os.Exit(doTests())
+func TestPointerChecks(t *testing.T) {
+ for _, pt := range ptrTests {
+ pt := pt
+ t.Run(pt.name, func(t *testing.T) {
+ testOne(t, pt)
+ })
+ }
}
-func doTests() int {
- gopath, err := ioutil.TempDir("", "cgoerrors")
+func testOne(t *testing.T, pt ptrTest) {
+ t.Parallel()
+
+ gopath, err := ioutil.TempDir("", filepath.Base(t.Name()))
if err != nil {
- fmt.Fprintln(os.Stderr, err)
- return 2
+ t.Fatal(err)
}
defer os.RemoveAll(gopath)
- if err := os.MkdirAll(filepath.Join(gopath, "src"), 0777); err != nil {
- fmt.Fprintln(os.Stderr, err)
- return 2
- }
-
- workers := runtime.NumCPU() + 1
-
- var wg sync.WaitGroup
- c := make(chan int)
- errs := make(chan int)
- for i := 0; i < workers; i++ {
- wg.Add(1)
- go func() {
- worker(gopath, c, errs)
- wg.Done()
- }()
- }
-
- for i := range ptrTests {
- c <- i
- }
- close(c)
-
- go func() {
- wg.Wait()
- close(errs)
- }()
-
- tot := 0
- for e := range errs {
- tot += e
- }
- return tot
-}
-
-func worker(gopath string, c, errs chan int) {
- e := 0
- for i := range c {
- if !doOne(gopath, i) {
- e++
- }
- }
- if e > 0 {
- errs <- e
- }
-}
-
-func doOne(gopath string, i int) bool {
- t := &ptrTests[i]
-
- dir := filepath.Join(gopath, "src", fmt.Sprintf("dir%d", i))
- if err := os.Mkdir(dir, 0777); err != nil {
- fmt.Fprintln(os.Stderr, err)
- return false
+ src := filepath.Join(gopath, "src")
+ if err := os.Mkdir(src, 0777); err != nil {
+ t.Fatal(err)
}
- name := filepath.Join(dir, fmt.Sprintf("t%d.go", i))
+ name := filepath.Join(src, fmt.Sprintf("%s.go", filepath.Base(t.Name())))
f, err := os.Create(name)
if err != nil {
- fmt.Fprintln(os.Stderr, err)
- return false
+ t.Fatal(err)
}
b := bufio.NewWriter(f)
fmt.Fprintln(b, `package main`)
fmt.Fprintln(b)
fmt.Fprintln(b, `/*`)
- fmt.Fprintln(b, t.c)
+ fmt.Fprintln(b, pt.c)
fmt.Fprintln(b, `*/`)
fmt.Fprintln(b, `import "C"`)
fmt.Fprintln(b)
- for _, imp := range t.imports {
+ for _, imp := range pt.imports {
fmt.Fprintln(b, `import "`+imp+`"`)
}
- if len(t.imports) > 0 {
+ if len(pt.imports) > 0 {
fmt.Fprintln(b)
}
- if len(t.support) > 0 {
- fmt.Fprintln(b, t.support)
+ if len(pt.support) > 0 {
+ fmt.Fprintln(b, pt.support)
fmt.Fprintln(b)
}
fmt.Fprintln(b, `func main() {`)
- fmt.Fprintln(b, t.body)
+ fmt.Fprintln(b, pt.body)
fmt.Fprintln(b, `}`)
if err := b.Flush(); err != nil {
- fmt.Fprintf(os.Stderr, "flushing %s: %v\n", name, err)
- return false
+ t.Fatalf("flushing %s: %v", name, err)
}
if err := f.Close(); err != nil {
- fmt.Fprintf(os.Stderr, "closing %s: %v\n", name, err)
- return false
+ t.Fatalf("closing %s: %v", name, err)
}
- for _, e := range t.extra {
- if err := ioutil.WriteFile(filepath.Join(dir, e.name), []byte(e.contents), 0644); err != nil {
- fmt.Fprintf(os.Stderr, "writing %s: %v\n", e.name, err)
- return false
+ for _, e := range pt.extra {
+ if err := ioutil.WriteFile(filepath.Join(src, e.name), []byte(e.contents), 0644); err != nil {
+ t.Fatalf("writing %s: %v", e.name, err)
}
}
- ok := true
+ args := func(cmd *exec.Cmd) string {
+ return strings.Join(cmd.Args, " ")
+ }
cmd := exec.Command("go", "build")
- cmd.Dir = dir
+ cmd.Dir = src
cmd.Env = addEnv("GOPATH", gopath)
buf, err := cmd.CombinedOutput()
if err != nil {
- fmt.Fprintf(os.Stderr, "test %s failed to build: %v\n%s", t.name, err, buf)
- return false
+ t.Logf("%#q:\n%s", args(cmd), buf)
+ t.Fatalf("failed to build: %v", err)
}
- exe := filepath.Join(dir, filepath.Base(dir))
+ exe := filepath.Join(src, filepath.Base(src))
cmd = exec.Command(exe)
- cmd.Dir = dir
+ cmd.Dir = src
- if t.expensive {
+ if pt.expensive {
cmd.Env = cgocheckEnv("1")
buf, err := cmd.CombinedOutput()
if err != nil {
- var errbuf bytes.Buffer
- if t.fail {
- fmt.Fprintf(&errbuf, "test %s marked expensive but failed when not expensive: %v\n", t.name, err)
+ t.Logf("%#q:\n%s", args(cmd), buf)
+ if pt.fail {
+ t.Fatalf("test marked expensive, but failed when not expensive: %v", err)
} else {
- fmt.Fprintf(&errbuf, "test %s failed unexpectedly with GODEBUG=cgocheck=1: %v\n", t.name, err)
+ t.Errorf("failed unexpectedly with GODEBUG=cgocheck=1: %v", err)
}
- reportTestOutput(&errbuf, t.name, buf)
- os.Stderr.Write(errbuf.Bytes())
- ok = false
}
cmd = exec.Command(exe)
- cmd.Dir = dir
+ cmd.Dir = src
}
- if t.expensive {
+ if pt.expensive {
cmd.Env = cgocheckEnv("2")
}
buf, err = cmd.CombinedOutput()
-
- if t.fail {
+ if pt.fail {
if err == nil {
- var errbuf bytes.Buffer
- fmt.Fprintf(&errbuf, "test %s did not fail as expected\n", t.name)
- reportTestOutput(&errbuf, t.name, buf)
- os.Stderr.Write(errbuf.Bytes())
- ok = false
+ t.Logf("%#q:\n%s", args(cmd), buf)
+ t.Fatalf("did not fail as expected")
} else if !bytes.Contains(buf, []byte("Go pointer")) {
- var errbuf bytes.Buffer
- fmt.Fprintf(&errbuf, "test %s output does not contain expected error (failed with %v)\n", t.name, err)
- reportTestOutput(&errbuf, t.name, buf)
- os.Stderr.Write(errbuf.Bytes())
- ok = false
+ t.Logf("%#q:\n%s", args(cmd), buf)
+ t.Fatalf("did not print expected error (failed with %v)", err)
}
} else {
if err != nil {
- var errbuf bytes.Buffer
- fmt.Fprintf(&errbuf, "test %s failed unexpectedly: %v\n", t.name, err)
- reportTestOutput(&errbuf, t.name, buf)
- os.Stderr.Write(errbuf.Bytes())
- ok = false
+ t.Logf("%#q:\n%s", args(cmd), buf)
+ t.Fatalf("failed unexpectedly: %v", err)
}
- if !t.expensive && ok {
+ if !pt.expensive {
// Make sure it passes with the expensive checks.
cmd := exec.Command(exe)
- cmd.Dir = dir
+ cmd.Dir = src
cmd.Env = cgocheckEnv("2")
buf, err := cmd.CombinedOutput()
if err != nil {
- var errbuf bytes.Buffer
- fmt.Fprintf(&errbuf, "test %s failed unexpectedly with expensive checks: %v\n", t.name, err)
- reportTestOutput(&errbuf, t.name, buf)
- os.Stderr.Write(errbuf.Bytes())
- ok = false
+ t.Logf("%#q:\n%s", args(cmd), buf)
+ t.Fatalf("failed unexpectedly with expensive checks: %v", err)
}
}
}
- if t.fail && ok {
+ if pt.fail {
cmd = exec.Command(exe)
- cmd.Dir = dir
+ cmd.Dir = src
cmd.Env = cgocheckEnv("0")
buf, err := cmd.CombinedOutput()
if err != nil {
- var errbuf bytes.Buffer
- fmt.Fprintf(&errbuf, "test %s failed unexpectedly with GODEBUG=cgocheck=0: %v\n", t.name, err)
- reportTestOutput(&errbuf, t.name, buf)
- os.Stderr.Write(errbuf.Bytes())
- ok = false
+ t.Logf("%#q:\n%s", args(cmd), buf)
+ t.Fatalf("failed unexpectedly with GODEBUG=cgocheck=0: %v", err)
}
}
-
- return ok
-}
-
-func reportTestOutput(w io.Writer, name string, buf []byte) {
- fmt.Fprintf(w, "=== test %s output ===\n", name)
- fmt.Fprintf(w, "%s", buf)
- fmt.Fprintf(w, "=== end of test %s output ===\n", name)
}
func cgocheckEnv(val string) []string {
diff --git a/libgo/misc/cgo/errors/err1.go b/libgo/misc/cgo/errors/src/err1.go
index 61bbcd29577..61bbcd29577 100644
--- a/libgo/misc/cgo/errors/err1.go
+++ b/libgo/misc/cgo/errors/src/err1.go
diff --git a/libgo/misc/cgo/errors/err2.go b/libgo/misc/cgo/errors/src/err2.go
index 3ab410bbaac..3ab410bbaac 100644
--- a/libgo/misc/cgo/errors/err2.go
+++ b/libgo/misc/cgo/errors/src/err2.go
diff --git a/libgo/misc/cgo/errors/err3.go b/libgo/misc/cgo/errors/src/err3.go
index 609e1a0b748..609e1a0b748 100644
--- a/libgo/misc/cgo/errors/err3.go
+++ b/libgo/misc/cgo/errors/src/err3.go
diff --git a/libgo/misc/cgo/errors/src/err4.go b/libgo/misc/cgo/errors/src/err4.go
new file mode 100644
index 00000000000..8e5f78e987b
--- /dev/null
+++ b/libgo/misc/cgo/errors/src/err4.go
@@ -0,0 +1,15 @@
+// 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.
+
+package main
+
+/*
+long double x = 0;
+*/
+import "C"
+
+func main() {
+ _ = C.x // ERROR HERE
+ _ = C.x
+}
diff --git a/libgo/misc/cgo/errors/issue11097a.go b/libgo/misc/cgo/errors/src/issue11097a.go
index 028d10ce5cb..028d10ce5cb 100644
--- a/libgo/misc/cgo/errors/issue11097a.go
+++ b/libgo/misc/cgo/errors/src/issue11097a.go
diff --git a/libgo/misc/cgo/errors/issue11097b.go b/libgo/misc/cgo/errors/src/issue11097b.go
index b00f24fc103..b00f24fc103 100644
--- a/libgo/misc/cgo/errors/issue11097b.go
+++ b/libgo/misc/cgo/errors/src/issue11097b.go
diff --git a/libgo/misc/cgo/errors/issue13129.go b/libgo/misc/cgo/errors/src/issue13129.go
index f7ad7a7e149..057bce4b829 100644
--- a/libgo/misc/cgo/errors/issue13129.go
+++ b/libgo/misc/cgo/errors/src/issue13129.go
@@ -10,5 +10,5 @@ import "C"
func main() {
var x C.ushort
- x = int(0) // ERROR HERE
+ x = int(0) // ERROR HERE: C\.ushort
}
diff --git a/libgo/misc/cgo/errors/issue13423.go b/libgo/misc/cgo/errors/src/issue13423.go
index fc191572376..fc191572376 100644
--- a/libgo/misc/cgo/errors/issue13423.go
+++ b/libgo/misc/cgo/errors/src/issue13423.go
diff --git a/libgo/misc/cgo/errors/src/issue13467.go b/libgo/misc/cgo/errors/src/issue13467.go
new file mode 100644
index 00000000000..e061880ddab
--- /dev/null
+++ b/libgo/misc/cgo/errors/src/issue13467.go
@@ -0,0 +1,15 @@
+// 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.
+
+package p
+
+/*
+static int transform(int x) { return x; }
+*/
+import "C"
+
+func F() {
+ var x rune = '✈'
+ var _ rune = C.transform(x) // ERROR HERE: C\.int
+}
diff --git a/libgo/misc/cgo/errors/src/issue13635.go b/libgo/misc/cgo/errors/src/issue13635.go
new file mode 100644
index 00000000000..3f38f5df4b5
--- /dev/null
+++ b/libgo/misc/cgo/errors/src/issue13635.go
@@ -0,0 +1,24 @@
+// Copyright 2015 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 13635: used to output error about C.unsignedchar.
+// This test tests all such types.
+
+package pkg
+
+import "C"
+
+func main() {
+ var (
+ _ C.uchar = "uc" // ERROR HERE: C\.uchar
+ _ C.schar = "sc" // ERROR HERE: C\.schar
+ _ C.ushort = "us" // ERROR HERE: C\.ushort
+ _ C.uint = "ui" // ERROR HERE: C\.uint
+ _ C.ulong = "ul" // ERROR HERE: C\.ulong
+ _ C.longlong = "ll" // ERROR HERE: C\.longlong
+ _ C.ulonglong = "ull" // ERROR HERE: C\.ulonglong
+ _ C.complexfloat = "cf" // ERROR HERE: C\.complexfloat
+ _ C.complexdouble = "cd" // ERROR HERE: C\.complexdouble
+ )
+}
diff --git a/libgo/misc/cgo/errors/issue13830.go b/libgo/misc/cgo/errors/src/issue13830.go
index ac20c82b81b..ac20c82b81b 100644
--- a/libgo/misc/cgo/errors/issue13830.go
+++ b/libgo/misc/cgo/errors/src/issue13830.go
diff --git a/libgo/misc/cgo/errors/issue14669.go b/libgo/misc/cgo/errors/src/issue14669.go
index 04d2bcb631d..04d2bcb631d 100644
--- a/libgo/misc/cgo/errors/issue14669.go
+++ b/libgo/misc/cgo/errors/src/issue14669.go
diff --git a/libgo/misc/cgo/errors/issue16116.go b/libgo/misc/cgo/errors/src/issue16116.go
index 1e01cab844e..1e01cab844e 100644
--- a/libgo/misc/cgo/errors/issue16116.go
+++ b/libgo/misc/cgo/errors/src/issue16116.go
diff --git a/libgo/misc/cgo/errors/issue16591.go b/libgo/misc/cgo/errors/src/issue16591.go
index 10eb8403cf8..10eb8403cf8 100644
--- a/libgo/misc/cgo/errors/issue16591.go
+++ b/libgo/misc/cgo/errors/src/issue16591.go
diff --git a/libgo/misc/cgo/errors/issue18452.go b/libgo/misc/cgo/errors/src/issue18452.go
index 36ef7f54e12..0386d768927 100644
--- a/libgo/misc/cgo/errors/issue18452.go
+++ b/libgo/misc/cgo/errors/src/issue18452.go
@@ -13,6 +13,6 @@ import (
func a() {
fmt.Println("Hello, world!")
- C.function_that_does_not_exist() // line 16
- C.pi // line 17
+ C.function_that_does_not_exist() // ERROR HERE
+ C.pi // ERROR HERE
}
diff --git a/libgo/misc/cgo/errors/issue18889.go b/libgo/misc/cgo/errors/src/issue18889.go
index bba6b8f9bb1..bba6b8f9bb1 100644
--- a/libgo/misc/cgo/errors/issue18889.go
+++ b/libgo/misc/cgo/errors/src/issue18889.go
diff --git a/libgo/misc/cgo/errors/issue7757.go b/libgo/misc/cgo/errors/src/issue7757.go
index 0426e9fb7ef..0426e9fb7ef 100644
--- a/libgo/misc/cgo/errors/issue7757.go
+++ b/libgo/misc/cgo/errors/src/issue7757.go
diff --git a/libgo/misc/cgo/errors/issue8442.go b/libgo/misc/cgo/errors/src/issue8442.go
index 60477ad345e..60477ad345e 100644
--- a/libgo/misc/cgo/errors/issue8442.go
+++ b/libgo/misc/cgo/errors/src/issue8442.go
diff --git a/libgo/misc/cgo/errors/src/long_double_size.go b/libgo/misc/cgo/errors/src/long_double_size.go
new file mode 100644
index 00000000000..8b797f886ae
--- /dev/null
+++ b/libgo/misc/cgo/errors/src/long_double_size.go
@@ -0,0 +1,16 @@
+// 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.
+
+package main
+
+/*
+const int sizeofLongDouble = sizeof(long double);
+*/
+import "C"
+
+import "fmt"
+
+func main() {
+ fmt.Println(C.sizeofLongDouble)
+}
diff --git a/libgo/misc/cgo/errors/malloc.go b/libgo/misc/cgo/errors/src/malloc.go
index 65da0208b97..65da0208b97 100644
--- a/libgo/misc/cgo/errors/malloc.go
+++ b/libgo/misc/cgo/errors/src/malloc.go
diff --git a/libgo/misc/cgo/errors/test.bash b/libgo/misc/cgo/errors/test.bash
deleted file mode 100644
index ed0b0946925..00000000000
--- a/libgo/misc/cgo/errors/test.bash
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2013 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.
-
-check() {
- file=$1
- line=$(grep -n 'ERROR HERE' $file | sed 's/:.*//')
- if [ "$line" = "" ]; then
- echo 1>&2 misc/cgo/errors/test.bash: BUG: cannot find ERROR HERE in $file
- exit 1
- fi
- expect $file $file:$line:
-}
-
-expect() {
- file=$1
- shift
- if go build -gcflags=-C $file >errs 2>&1; then
- echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail on $file but it succeeded
- exit 1
- fi
- if ! test -s errs; then
- echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file but saw none
- exit 1
- fi
- for error; do
- if ! fgrep $error errs >/dev/null 2>&1; then
- echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file to contain \"$error\" but saw:
- cat 1>&2 errs
- exit 1
- fi
- done
-}
-
-check err1.go
-check err2.go
-check err3.go
-check issue7757.go
-check issue8442.go
-check issue11097a.go
-check issue11097b.go
-expect issue13129.go C.ushort
-check issue13423.go
-expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
-check issue13830.go
-check issue16116.go
-check issue16591.go
-check issue18889.go
-expect issue18452.go issue18452.go:16 issue18452.go:17
-
-if ! go build issue14669.go; then
- exit 1
-fi
-if ! CGO_CFLAGS="-O" go build issue14669.go; then
- exit 1
-fi
-
-if ! go run ptr.go; then
- exit 1
-fi
-
-# The malloc.go test should crash.
-rm -f malloc.out
-if go run malloc.go >malloc.out 2>&1; then
- echo '`go run malloc.go` succeeded unexpectedly'
- cat malloc.out
- rm -f malloc.out
- exit 1
-fi
-rm -f malloc.out
-
-rm -rf errs _obj
-exit 0
diff --git a/libgo/misc/cgo/life/main.go b/libgo/misc/cgo/life/main.go
index aa2f6d116b3..45376fd05a9 100644
--- a/libgo/misc/cgo/life/main.go
+++ b/libgo/misc/cgo/life/main.go
@@ -1,4 +1,4 @@
-// cmpout
+// cmpout -tags=use_go_run
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@@ -11,9 +11,10 @@
package main
import (
- "."
"flag"
"fmt"
+
+ "."
)
const MAXDIM = 100
diff --git a/libgo/misc/cgo/stdio/chain.go b/libgo/misc/cgo/stdio/chain.go
index 03cddb76888..0fa813cab70 100644
--- a/libgo/misc/cgo/stdio/chain.go
+++ b/libgo/misc/cgo/stdio/chain.go
@@ -1,4 +1,4 @@
-// cmpout
+// cmpout -tags=use_go_run
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
diff --git a/libgo/misc/cgo/stdio/fib.go b/libgo/misc/cgo/stdio/fib.go
index 61a1b83728c..56e32552ee6 100644
--- a/libgo/misc/cgo/stdio/fib.go
+++ b/libgo/misc/cgo/stdio/fib.go
@@ -1,4 +1,4 @@
-// cmpout
+// cmpout -tags=use_go_run
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
diff --git a/libgo/misc/cgo/stdio/hello.go b/libgo/misc/cgo/stdio/hello.go
index 47179ba4827..63bff4c617a 100644
--- a/libgo/misc/cgo/stdio/hello.go
+++ b/libgo/misc/cgo/stdio/hello.go
@@ -1,4 +1,4 @@
-// cmpout
+// cmpout -tags=use_go_run
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
diff --git a/libgo/misc/cgo/test/cgo_test.go b/libgo/misc/cgo/test/cgo_test.go
index f7cf6f613c4..67abfff2c03 100644
--- a/libgo/misc/cgo/test/cgo_test.go
+++ b/libgo/misc/cgo/test/cgo_test.go
@@ -80,5 +80,11 @@ func Test20369(t *testing.T) { test20369(t) }
func Test18720(t *testing.T) { test18720(t) }
func Test20266(t *testing.T) { test20266(t) }
func Test20129(t *testing.T) { test20129(t) }
+func Test20910(t *testing.T) { test20910(t) }
+func Test21708(t *testing.T) { test21708(t) }
+func Test21809(t *testing.T) { test21809(t) }
+func Test6907(t *testing.T) { test6907(t) }
+func Test6907Go(t *testing.T) { test6907Go(t) }
+func Test21897(t *testing.T) { test21897(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/libgo/misc/cgo/test/issue18720.go b/libgo/misc/cgo/test/issue18720.go
index a93304498e0..3d64003be74 100644
--- a/libgo/misc/cgo/test/issue18720.go
+++ b/libgo/misc/cgo/test/issue18720.go
@@ -12,13 +12,39 @@ package cgotest
struct foo { char c; };
#define SIZE_OF(x) sizeof(x)
#define SIZE_OF_FOO SIZE_OF(struct foo)
+#define VAR1 VAR
+#define VAR var
+int var = 5;
+
+#define ADDR &var
+
+#define CALL fn()
+int fn(void) {
+ return ++var;
+}
*/
import "C"
import "testing"
func test18720(t *testing.T) {
- if C.HELLO_WORLD != "hello\000world" {
- t.Fatalf(`expected "hello\000world", but got %q`, C.HELLO_WORLD)
+ if got, want := C.HELLO_WORLD, "hello\000world"; got != want {
+ t.Errorf("C.HELLO_WORLD == %q, expected %q", got, want)
+ }
+
+ if got, want := C.VAR1, C.int(5); got != want {
+ t.Errorf("C.VAR1 == %v, expected %v", got, want)
+ }
+
+ if got, want := *C.ADDR, C.int(5); got != want {
+ t.Errorf("*C.ADDR == %v, expected %v", got, want)
+ }
+
+ if got, want := C.CALL, C.int(6); got != want {
+ t.Errorf("C.CALL == %v, expected %v", got, want)
+ }
+
+ if got, want := C.CALL, C.int(7); got != want {
+ t.Errorf("C.CALL == %v, expected %v", got, want)
}
// Issue 20125.
diff --git a/libgo/misc/cgo/test/issue19832.go b/libgo/misc/cgo/test/issue19832.go
new file mode 100644
index 00000000000..44587770af4
--- /dev/null
+++ b/libgo/misc/cgo/test/issue19832.go
@@ -0,0 +1,16 @@
+// Copyright 2015 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 19832. Functions taking a pointer typedef were being expanded and triggering a compiler error.
+
+package cgotest
+
+// typedef struct { int i; } *PS;
+// void T19832(PS p) {}
+import "C"
+import "testing"
+
+func test19832(t *testing.T) {
+ C.T19832(nil)
+}
diff --git a/libgo/misc/cgo/test/issue20910.c b/libgo/misc/cgo/test/issue20910.c
new file mode 100644
index 00000000000..e8d623fc983
--- /dev/null
+++ b/libgo/misc/cgo/test/issue20910.c
@@ -0,0 +1,19 @@
+// 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.
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "_cgo_export.h"
+
+/* Test calling a Go function with multiple return values. */
+
+void
+callMulti(void)
+{
+ struct multi_return result = multi();
+ assert(strcmp(result.r0, "multi") == 0);
+ assert(result.r1 == 0);
+ free(result.r0);
+}
diff --git a/libgo/misc/cgo/test/issue20910.go b/libgo/misc/cgo/test/issue20910.go
new file mode 100644
index 00000000000..69d7d9249ac
--- /dev/null
+++ b/libgo/misc/cgo/test/issue20910.go
@@ -0,0 +1,19 @@
+// 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.
+
+package cgotest
+
+//void callMulti(void);
+import "C"
+
+import "testing"
+
+//export multi
+func multi() (*C.char, C.int) {
+ return C.CString("multi"), 0
+}
+
+func test20910(t *testing.T) {
+ C.callMulti()
+}
diff --git a/libgo/misc/cgo/test/issue21668.go b/libgo/misc/cgo/test/issue21668.go
new file mode 100644
index 00000000000..f15b9202acc
--- /dev/null
+++ b/libgo/misc/cgo/test/issue21668.go
@@ -0,0 +1,13 @@
+// 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.
+
+// Fail to guess the kind of the constant "x".
+// No runtime test; just make sure it compiles.
+
+package cgotest
+
+// const int x = 42;
+import "C"
+
+var issue21668_X = C.x
diff --git a/libgo/misc/cgo/test/issue21708.go b/libgo/misc/cgo/test/issue21708.go
new file mode 100644
index 00000000000..d413e3c57a9
--- /dev/null
+++ b/libgo/misc/cgo/test/issue21708.go
@@ -0,0 +1,16 @@
+// 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.
+
+package cgotest
+
+// #include <stdint.h>
+// #define CAST_TO_INT64 (int64_t)(-1)
+import "C"
+import "testing"
+
+func test21708(t *testing.T) {
+ if got, want := C.CAST_TO_INT64, -1; got != want {
+ t.Errorf("C.CAST_TO_INT64 == %v, expected %v", got, want)
+ }
+}
diff --git a/libgo/misc/cgo/test/issue21809.go b/libgo/misc/cgo/test/issue21809.go
new file mode 100644
index 00000000000..a3a6b88897e
--- /dev/null
+++ b/libgo/misc/cgo/test/issue21809.go
@@ -0,0 +1,45 @@
+// 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.
+
+package cgotest
+
+// Issue 21809. Compile C `typedef` to go type aliases.
+
+// typedef long MySigned_t;
+// /* tests alias-to-alias */
+// typedef MySigned_t MySigned2_t;
+//
+// long takes_long(long x) { return x * x; }
+// MySigned_t takes_typedef(MySigned_t x) { return x * x; }
+import "C"
+
+import "testing"
+
+func test21809(t *testing.T) {
+ longVar := C.long(3)
+ typedefVar := C.MySigned_t(4)
+ typedefTypedefVar := C.MySigned2_t(5)
+
+ // all three should be considered identical to `long`
+ if ret := C.takes_long(longVar); ret != 9 {
+ t.Errorf("got %v but expected %v", ret, 9)
+ }
+ if ret := C.takes_long(typedefVar); ret != 16 {
+ t.Errorf("got %v but expected %v", ret, 16)
+ }
+ if ret := C.takes_long(typedefTypedefVar); ret != 25 {
+ t.Errorf("got %v but expected %v", ret, 25)
+ }
+
+ // They should also be identical to the typedef'd type
+ if ret := C.takes_typedef(longVar); ret != 9 {
+ t.Errorf("got %v but expected %v", ret, 9)
+ }
+ if ret := C.takes_typedef(typedefVar); ret != 16 {
+ t.Errorf("got %v but expected %v", ret, 16)
+ }
+ if ret := C.takes_typedef(typedefTypedefVar); ret != 25 {
+ t.Errorf("got %v but expected %v", ret, 25)
+ }
+}
diff --git a/libgo/misc/cgo/test/issue21897.go b/libgo/misc/cgo/test/issue21897.go
new file mode 100644
index 00000000000..d13246bd84a
--- /dev/null
+++ b/libgo/misc/cgo/test/issue21897.go
@@ -0,0 +1,56 @@
+// 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.
+
+// +build darwin,cgo,!internal
+
+package cgotest
+
+/*
+#cgo LDFLAGS: -framework CoreFoundation
+#include <CoreFoundation/CoreFoundation.h>
+*/
+import "C"
+import (
+ "runtime/debug"
+ "testing"
+ "unsafe"
+)
+
+func test21897(t *testing.T) {
+ // Please write barrier, kick in soon.
+ defer debug.SetGCPercent(debug.SetGCPercent(1))
+
+ for i := 0; i < 10000; i++ {
+ testCFNumberRef()
+ testCFDateRef()
+ testCFBooleanRef()
+ // Allocate some memory, so eventually the write barrier is enabled
+ // and it will see writes of bad pointers in the test* functions below.
+ byteSliceSink = make([]byte, 1024)
+ }
+}
+
+var byteSliceSink []byte
+
+func testCFNumberRef() {
+ var v int64 = 0
+ xCFNumberRef = C.CFNumberCreate(C.kCFAllocatorSystemDefault, C.kCFNumberSInt64Type, unsafe.Pointer(&v))
+ //fmt.Printf("CFNumberRef: %x\n", uintptr(unsafe.Pointer(xCFNumberRef)))
+}
+
+var xCFNumberRef C.CFNumberRef
+
+func testCFDateRef() {
+ xCFDateRef = C.CFDateCreate(C.kCFAllocatorSystemDefault, 0) // 0 value is 1 Jan 2001 00:00:00 GMT
+ //fmt.Printf("CFDateRef: %x\n", uintptr(unsafe.Pointer(xCFDateRef)))
+}
+
+var xCFDateRef C.CFDateRef
+
+func testCFBooleanRef() {
+ xCFBooleanRef = C.kCFBooleanFalse
+ //fmt.Printf("CFBooleanRef: %x\n", uintptr(unsafe.Pointer(xCFBooleanRef)))
+}
+
+var xCFBooleanRef C.CFBooleanRef
diff --git a/libgo/misc/cgo/test/issue21897b.go b/libgo/misc/cgo/test/issue21897b.go
new file mode 100644
index 00000000000..08b5f4d808e
--- /dev/null
+++ b/libgo/misc/cgo/test/issue21897b.go
@@ -0,0 +1,13 @@
+// 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.
+
+// +build !darwin !cgo internal
+
+package cgotest
+
+import "testing"
+
+func test21897(t *testing.T) {
+ t.Skip("test runs only on darwin+cgo")
+}
diff --git a/libgo/misc/cgo/test/issue22958.go b/libgo/misc/cgo/test/issue22958.go
new file mode 100644
index 00000000000..a5f058fdae1
--- /dev/null
+++ b/libgo/misc/cgo/test/issue22958.go
@@ -0,0 +1,24 @@
+// 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.
+
+package cgotest
+
+// Test handling of bitfields.
+
+/*
+typedef struct {
+ unsigned long long f8 : 8;
+ unsigned long long f16 : 16;
+ unsigned long long f24 : 24;
+ unsigned long long f32 : 32;
+ unsigned long long f40 : 40;
+ unsigned long long f48 : 48;
+ unsigned long long f56 : 56;
+ unsigned long long f64 : 64;
+} issue22958Type;
+*/
+import "C"
+
+// Nothing to run, just make sure this compiles.
+var Vissue22958 C.issue22958Type
diff --git a/libgo/misc/cgo/test/issue6907.go b/libgo/misc/cgo/test/issue6907.go
new file mode 100644
index 00000000000..00495ab8e2e
--- /dev/null
+++ b/libgo/misc/cgo/test/issue6907.go
@@ -0,0 +1,33 @@
+// 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.
+
+package cgotest
+
+/*
+#include <stdlib.h>
+#include <string.h>
+
+char* Issue6907CopyString(_GoString_ s) {
+ size_t n;
+ const char *p;
+ char *r;
+
+ n = _GoStringLen(s);
+ p = _GoStringPtr(s);
+ r = malloc(n + 1);
+ memmove(r, p, n);
+ r[n] = '\0';
+ return r;
+}
+*/
+import "C"
+
+import "testing"
+
+func test6907(t *testing.T) {
+ want := "yarn"
+ if got := C.GoString(C.Issue6907CopyString(want)); got != want {
+ t.Errorf("C.GoString(C.Issue6907CopyString(%q)) == %q, want %q", want, got, want)
+ }
+}
diff --git a/libgo/misc/cgo/test/issue6907export.go b/libgo/misc/cgo/test/issue6907export.go
new file mode 100644
index 00000000000..d41899e1a62
--- /dev/null
+++ b/libgo/misc/cgo/test/issue6907export.go
@@ -0,0 +1,30 @@
+// 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.
+
+package cgotest
+
+/*
+extern int CheckIssue6907C(_GoString_);
+*/
+import "C"
+
+import (
+ "testing"
+)
+
+const CString = "C string"
+
+//export CheckIssue6907Go
+func CheckIssue6907Go(s string) C.int {
+ if s == CString {
+ return 1
+ }
+ return 0
+}
+
+func test6907Go(t *testing.T) {
+ if got := C.CheckIssue6907C(CString); got != 1 {
+ t.Errorf("C.CheckIssue6907C() == %d, want %d", got, 1)
+ }
+}
diff --git a/libgo/misc/cgo/test/issue6907export_c.c b/libgo/misc/cgo/test/issue6907export_c.c
new file mode 100644
index 00000000000..9b1a4fc630b
--- /dev/null
+++ b/libgo/misc/cgo/test/issue6907export_c.c
@@ -0,0 +1,11 @@
+// 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.
+
+#include <string.h>
+
+#include "_cgo_export.h"
+
+int CheckIssue6907C(_GoString_ s) {
+ return CheckIssue6907Go(s);
+}
diff --git a/libgo/misc/cgo/test/issue7978.go b/libgo/misc/cgo/test/issue7978.go
index 7fb62e807ba..b057e3eacb2 100644
--- a/libgo/misc/cgo/test/issue7978.go
+++ b/libgo/misc/cgo/test/issue7978.go
@@ -44,8 +44,8 @@ static void issue7978c(uint32_t *sync) {
import "C"
import (
- "os"
"runtime"
+ "runtime/debug"
"strings"
"sync/atomic"
"testing"
@@ -114,12 +114,7 @@ func test7978(t *testing.T) {
if C.HAS_SYNC_FETCH_AND_ADD == 0 {
t.Skip("clang required for __sync_fetch_and_add support on darwin/arm")
}
- if runtime.GOOS == "android" || runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
- t.Skip("GOTRACEBACK is not passed on to the exec wrapper")
- }
- if os.Getenv("GOTRACEBACK") != "2" {
- t.Fatalf("GOTRACEBACK must be 2")
- }
+ debug.SetTraceback("2")
issue7978sync = 0
go issue7978go()
// test in c code, before callback
diff --git a/libgo/misc/cgo/testcarchive/carchive_test.go b/libgo/misc/cgo/testcarchive/carchive_test.go
index 4865b806a3e..e3f67955802 100644
--- a/libgo/misc/cgo/testcarchive/carchive_test.go
+++ b/libgo/misc/cgo/testcarchive/carchive_test.go
@@ -6,6 +6,7 @@ package carchive_test
import (
"bufio"
+ "bytes"
"debug/elf"
"fmt"
"io/ioutil"
@@ -139,8 +140,10 @@ func cmdToRun(name string) []string {
}
func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
+ t.Helper()
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
cmd.Env = gopathEnv
+ t.Log(buildcmd)
if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
@@ -188,7 +191,7 @@ func TestInstall(t *testing.T) {
testInstall(t, "./testp1"+exeSuffix,
filepath.Join("pkg", libgodir, libgoa),
filepath.Join("pkg", libgodir, "libgo.h"),
- "go", "install", "-buildmode=c-archive", "libgo")
+ "go", "install", "-i", "-buildmode=c-archive", "libgo")
// Test building libgo other than installing it.
// Header files are now present.
@@ -523,7 +526,7 @@ func TestPIE(t *testing.T) {
os.RemoveAll("pkg")
}()
- cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
+ cmd := exec.Command("go", "install", "-i", "-buildmode=c-archive", "libgo")
cmd.Env = gopathEnv
if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("%s", out)
@@ -596,6 +599,8 @@ func TestSIGPROF(t *testing.T) {
switch GOOS {
case "windows", "plan9":
t.Skipf("skipping SIGPROF test on %s", GOOS)
+ case "darwin":
+ t.Skipf("skipping SIGPROF test on %s; see https://golang.org/issue/19320", GOOS)
}
t.Parallel()
@@ -655,12 +660,29 @@ func TestCompileWithoutShared(t *testing.T) {
}
exe := "./testnoshared" + exeSuffix
- ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a")
+
+ // In some cases, -no-pie is needed here, but not accepted everywhere. First try
+ // if -no-pie is accepted. See #22126.
+ ccArgs := append(cc, "-o", exe, "-no-pie", "main5.c", "libgo2.a")
if runtime.Compiler == "gccgo" {
ccArgs = append(ccArgs, "-lgo")
}
t.Log(ccArgs)
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+
+ // If -no-pie unrecognized, try -nopie if this is possibly clang
+ if err != nil && bytes.Contains(out, []byte("unknown")) && !strings.Contains(cc[0], "gcc") {
+ ccArgs = append(cc, "-o", exe, "-nopie", "main5.c", "libgo2.a")
+ t.Log(ccArgs)
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ }
+
+ // Don't use either -no-pie or -nopie
+ if err != nil && bytes.Contains(out, []byte("unrecognized")) {
+ ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a")
+ t.Log(ccArgs)
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ }
t.Logf("%s", out)
if err != nil {
t.Fatal(err)
diff --git a/libgo/misc/cgo/testcshared/cshared_test.go b/libgo/misc/cgo/testcshared/cshared_test.go
new file mode 100644
index 00000000000..49be0923966
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/cshared_test.go
@@ -0,0 +1,479 @@
+// 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.
+
+package cshared_test
+
+import (
+ "debug/elf"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "strings"
+ "sync"
+ "testing"
+ "unicode"
+)
+
+// C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
+var cc []string
+
+// An environment with GOPATH=$(pwd).
+var gopathEnv []string
+
+// ".exe" on Windows.
+var exeSuffix string
+
+var GOOS, GOARCH, GOROOT string
+var installdir, androiddir string
+var libSuffix, libgoname string
+
+func TestMain(m *testing.M) {
+ GOOS = goEnv("GOOS")
+ GOARCH = goEnv("GOARCH")
+ GOROOT = goEnv("GOROOT")
+
+ if _, err := os.Stat(GOROOT); os.IsNotExist(err) {
+ log.Fatalf("Unable able to find GOROOT at '%s'", GOROOT)
+ }
+
+ // Directory where cgo headers and outputs will be installed.
+ // The installation directory format varies depending on the platform.
+ installdir = path.Join("pkg", fmt.Sprintf("%s_%s_testcshared", GOOS, GOARCH))
+ switch GOOS {
+ case "darwin":
+ libSuffix = "dylib"
+ case "windows":
+ libSuffix = "dll"
+ default:
+ libSuffix = "so"
+ installdir = path.Join("pkg", fmt.Sprintf("%s_%s_testcshared_shared", GOOS, GOARCH))
+ }
+
+ androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid())
+ if GOOS == "android" {
+ cmd := exec.Command("adb", "shell", "mkdir", "-p", androiddir)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ log.Fatalf("setupAndroid failed: %v\n%s\n", err, out)
+ }
+ }
+
+ libgoname = "libgo." + libSuffix
+
+ cc = []string{goEnv("CC")}
+
+ out := goEnv("GOGCCFLAGS")
+ quote := '\000'
+ start := 0
+ lastSpace := true
+ backslash := false
+ s := string(out)
+ for i, c := range s {
+ if quote == '\000' && unicode.IsSpace(c) {
+ if !lastSpace {
+ cc = append(cc, s[start:i])
+ lastSpace = true
+ }
+ } else {
+ if lastSpace {
+ start = i
+ lastSpace = false
+ }
+ if quote == '\000' && !backslash && (c == '"' || c == '\'') {
+ quote = c
+ backslash = false
+ } else if !backslash && quote == c {
+ quote = '\000'
+ } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
+ backslash = true
+ } else {
+ backslash = false
+ }
+ }
+ }
+ if !lastSpace {
+ cc = append(cc, s[start:])
+ }
+
+ switch GOOS {
+ case "darwin":
+ // For Darwin/ARM.
+ // TODO(crawshaw): can we do better?
+ cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
+ case "android":
+ cc = append(cc, "-pie", "-fuse-ld=gold")
+ }
+ libgodir := GOOS + "_" + GOARCH
+ switch GOOS {
+ case "darwin":
+ if GOARCH == "arm" || GOARCH == "arm64" {
+ libgodir += "_shared"
+ }
+ case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+ libgodir += "_shared"
+ }
+ cc = append(cc, "-I", filepath.Join("pkg", libgodir))
+
+ // Build an environment with GOPATH=$(pwd)
+ dir, err := os.Getwd()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+ gopathEnv = append(os.Environ(), "GOPATH="+dir)
+
+ if GOOS == "windows" {
+ exeSuffix = ".exe"
+ }
+
+ st := m.Run()
+
+ os.Remove(libgoname)
+ os.RemoveAll("pkg")
+ cleanupHeaders()
+ cleanupAndroid()
+
+ os.Exit(st)
+}
+
+func goEnv(key string) string {
+ out, err := exec.Command("go", "env", key).Output()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go env %s failed:\n%s", key, err)
+ fmt.Fprintf(os.Stderr, "%s", err.(*exec.ExitError).Stderr)
+ os.Exit(2)
+ }
+ return strings.TrimSpace(string(out))
+}
+
+func cmdToRun(name string) string {
+ return "./" + name + exeSuffix
+}
+
+func adbPush(t *testing.T, filename string) {
+ if GOOS != "android" {
+ return
+ }
+ args := []string{"adb", "push", filename, fmt.Sprintf("%s/%s", androiddir, filename)}
+ cmd := exec.Command(args[0], args[1:]...)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("adb command failed: %v\n%s\n", err, out)
+ }
+}
+
+func adbRun(t *testing.T, env []string, adbargs ...string) string {
+ if GOOS != "android" {
+ t.Fatalf("trying to run adb command when operating system is not android.")
+ }
+ args := []string{"adb", "shell"}
+ // Propagate LD_LIBRARY_PATH to the adb shell invocation.
+ for _, e := range env {
+ if strings.Index(e, "LD_LIBRARY_PATH=") != -1 {
+ adbargs = append([]string{e}, adbargs...)
+ break
+ }
+ }
+ shellcmd := fmt.Sprintf("cd %s; %s", androiddir, strings.Join(adbargs, " "))
+ args = append(args, shellcmd)
+ cmd := exec.Command(args[0], args[1:]...)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("adb command failed: %v\n%s\n", err, out)
+ }
+ return strings.Replace(string(out), "\r", "", -1)
+}
+
+func run(t *testing.T, env []string, args ...string) string {
+ t.Helper()
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Env = env
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("command failed: %v\n%v\n%s\n", args, err, out)
+ } else {
+ t.Logf("run: %v", args)
+ }
+ return string(out)
+}
+
+func runExe(t *testing.T, env []string, args ...string) string {
+ t.Helper()
+ if GOOS == "android" {
+ return adbRun(t, env, args...)
+ }
+ return run(t, env, args...)
+}
+
+func runCC(t *testing.T, args ...string) string {
+ t.Helper()
+ // This function is run in parallel, so append to a copy of cc
+ // rather than cc itself.
+ return run(t, nil, append(append([]string(nil), cc...), args...)...)
+}
+
+func createHeaders() error {
+ args := []string{"go", "install", "-i", "-buildmode=c-shared",
+ "-installsuffix", "testcshared", "libgo"}
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Env = gopathEnv
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
+ }
+
+ args = []string{"go", "build", "-buildmode=c-shared",
+ "-installsuffix", "testcshared",
+ "-o", libgoname,
+ filepath.Join("src", "libgo", "libgo.go")}
+ cmd = exec.Command(args[0], args[1:]...)
+ cmd.Env = gopathEnv
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
+ }
+
+ if GOOS == "android" {
+ args = []string{"adb", "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname)}
+ cmd = exec.Command(args[0], args[1:]...)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ return fmt.Errorf("adb command failed: %v\n%s\n", err, out)
+ }
+ }
+
+ return nil
+}
+
+var (
+ headersOnce sync.Once
+ headersErr error
+)
+
+func createHeadersOnce(t *testing.T) {
+ headersOnce.Do(func() {
+ headersErr = createHeaders()
+ })
+ if headersErr != nil {
+ t.Fatal(headersErr)
+ }
+}
+
+func cleanupHeaders() {
+ os.Remove("libgo.h")
+}
+
+func cleanupAndroid() {
+ if GOOS != "android" {
+ return
+ }
+ cmd := exec.Command("adb", "shell", "rm", "-rf", androiddir)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ log.Fatalf("cleanupAndroid failed: %v\n%s\n", err, out)
+ }
+}
+
+// test0: exported symbols in shared lib are accessible.
+func TestExportedSymbols(t *testing.T) {
+ t.Parallel()
+
+ cmd := "testp0"
+ bin := cmdToRun(cmd)
+
+ createHeadersOnce(t)
+
+ runCC(t, "-I", installdir, "-o", cmd, "main0.c", libgoname)
+ adbPush(t, cmd)
+
+ defer os.Remove(bin)
+
+ out := runExe(t, append(gopathEnv, "LD_LIBRARY_PATH=."), bin)
+ if strings.TrimSpace(out) != "PASS" {
+ t.Error(out)
+ }
+}
+
+// test1: shared library can be dynamically loaded and exported symbols are accessible.
+func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
+ t.Parallel()
+
+ if GOOS == "windows" {
+ t.Logf("Skipping on %s", GOOS)
+ return
+ }
+
+ cmd := "testp1"
+ bin := cmdToRun(cmd)
+
+ createHeadersOnce(t)
+
+ runCC(t, "-o", cmd, "main1.c", "-ldl")
+ adbPush(t, cmd)
+
+ defer os.Remove(bin)
+
+ out := runExe(t, nil, bin, "./"+libgoname)
+ if strings.TrimSpace(out) != "PASS" {
+ t.Error(out)
+ }
+}
+
+// test2: tests libgo2 which does not export any functions.
+func TestUnexportedSymbols(t *testing.T) {
+ t.Parallel()
+
+ if GOOS == "windows" {
+ t.Logf("Skipping on %s", GOOS)
+ return
+ }
+
+ cmd := "testp2"
+ bin := cmdToRun(cmd)
+ libname := "libgo2." + libSuffix
+
+ run(t,
+ gopathEnv,
+ "go", "build",
+ "-buildmode=c-shared",
+ "-installsuffix", "testcshared",
+ "-o", libname, "libgo2",
+ )
+ adbPush(t, libname)
+
+ linkFlags := "-Wl,--no-as-needed"
+ if GOOS == "darwin" {
+ linkFlags = ""
+ }
+
+ runCC(t, "-o", cmd, "main2.c", linkFlags, libname)
+ adbPush(t, cmd)
+
+ defer os.Remove(libname)
+ defer os.Remove(bin)
+
+ out := runExe(t, append(gopathEnv, "LD_LIBRARY_PATH=."), bin)
+
+ if strings.TrimSpace(out) != "PASS" {
+ t.Error(out)
+ }
+}
+
+// test3: tests main.main is exported on android.
+func TestMainExportedOnAndroid(t *testing.T) {
+ t.Parallel()
+
+ switch GOOS {
+ case "android":
+ break
+ default:
+ t.Logf("Skipping on %s", GOOS)
+ return
+ }
+
+ cmd := "testp3"
+ bin := cmdToRun(cmd)
+
+ createHeadersOnce(t)
+
+ runCC(t, "-o", cmd, "main3.c", "-ldl")
+ adbPush(t, cmd)
+
+ defer os.Remove(bin)
+
+ out := runExe(t, nil, bin, "./"+libgoname)
+ if strings.TrimSpace(out) != "PASS" {
+ t.Error(out)
+ }
+}
+
+func testSignalHandlers(t *testing.T, pkgname, cfile, cmd string) {
+ libname := pkgname + "." + libSuffix
+ run(t,
+ gopathEnv,
+ "go", "build",
+ "-buildmode=c-shared",
+ "-installsuffix", "testcshared",
+ "-o", libname, pkgname,
+ )
+ adbPush(t, libname)
+ runCC(t, "-pthread", "-o", cmd, cfile, "-ldl")
+ adbPush(t, cmd)
+
+ bin := cmdToRun(cmd)
+
+ defer os.Remove(libname)
+ defer os.Remove(bin)
+ defer os.Remove(pkgname + ".h")
+
+ out := runExe(t, nil, bin, "./"+libname)
+ if strings.TrimSpace(out) != "PASS" {
+ t.Error(run(t, nil, bin, libname, "verbose"))
+ }
+}
+
+// test4: test signal handlers
+func TestSignalHandlers(t *testing.T) {
+ t.Parallel()
+ if GOOS == "windows" {
+ t.Logf("Skipping on %s", GOOS)
+ return
+ }
+ testSignalHandlers(t, "libgo4", "main4.c", "testp4")
+}
+
+// test5: test signal handlers with os/signal.Notify
+func TestSignalHandlersWithNotify(t *testing.T) {
+ t.Parallel()
+ if GOOS == "windows" {
+ t.Logf("Skipping on %s", GOOS)
+ return
+ }
+ testSignalHandlers(t, "libgo5", "main5.c", "testp5")
+}
+
+func TestPIE(t *testing.T) {
+ t.Parallel()
+
+ switch GOOS {
+ case "linux", "android":
+ break
+ default:
+ t.Logf("Skipping on %s", GOOS)
+ return
+ }
+
+ createHeadersOnce(t)
+
+ f, err := elf.Open(libgoname)
+ if err != nil {
+ t.Fatalf("elf.Open failed: %v", err)
+ }
+ defer f.Close()
+
+ ds := f.SectionByType(elf.SHT_DYNAMIC)
+ if ds == nil {
+ t.Fatalf("no SHT_DYNAMIC section")
+ }
+ d, err := ds.Data()
+ if err != nil {
+ t.Fatalf("can't read SHT_DYNAMIC contents: %v", err)
+ }
+ for len(d) > 0 {
+ var tag elf.DynTag
+ switch f.Class {
+ case elf.ELFCLASS32:
+ tag = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
+ d = d[8:]
+ case elf.ELFCLASS64:
+ tag = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
+ d = d[16:]
+ }
+ if tag == elf.DT_TEXTREL {
+ t.Fatalf("%s has DT_TEXTREL flag", libgoname)
+ }
+ }
+}
diff --git a/libgo/misc/cgo/testcshared/test.bash b/libgo/misc/cgo/testcshared/test.bash
deleted file mode 100644
index 315a0d40367..00000000000
--- a/libgo/misc/cgo/testcshared/test.bash
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2015 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.
-
-# For testing Android, this script requires adb to push and run compiled
-# binaries on a target device.
-
-set -e
-
-if [ ! -f src/libgo/libgo.go ]; then
- cwd=$(pwd)
- echo "misc/cgo/testcshared/test.bash is running in $cwd" 1>&2
- exit 1
-fi
-
-goos=$(go env GOOS)
-goarch=$(go env GOARCH)
-goroot=$(go env GOROOT)
-if [ ! -d "$goroot" ]; then
- echo 'misc/cgo/testcshared/test.bash cannot find GOROOT' 1>&2
- echo '$GOROOT:' "$GOROOT" 1>&2
- echo 'go env GOROOT:' "$goroot" 1>&2
- exit 1
-fi
-
-# Directory where cgo headers and outputs will be installed.
-# The installation directory format varies depending on the platform.
-installdir=pkg/${goos}_${goarch}_testcshared_shared
-if [ "${goos}" = "darwin" ]; then
- installdir=pkg/${goos}_${goarch}_testcshared
-fi
-
-# Temporary directory on the android device.
-androidpath=/data/local/tmp/testcshared-$$
-
-function cleanup() {
- rm -f libgo.$libext libgo2.$libext libgo4.$libext libgo5.$libext
- rm -f libgo.h libgo4.h libgo5.h
- rm -f testp testp2 testp3 testp4 testp5
- rm -rf pkg "${goroot}/${installdir}"
-
- if [ "$goos" = "android" ]; then
- adb shell rm -rf "$androidpath"
- fi
-}
-trap cleanup EXIT
-
-if [ "$goos" = "android" ]; then
- adb shell mkdir -p "$androidpath"
-fi
-
-function run() {
- case "$goos" in
- "android")
- local args=$@
- output=$(adb shell "cd ${androidpath}; $@")
- output=$(echo $output|tr -d '\r')
- case $output in
- *PASS) echo "PASS";;
- *) echo "$output";;
- esac
- ;;
- *)
- echo $(env $@)
- ;;
- esac
-}
-
-function binpush() {
- bin=${1}
- if [ "$goos" = "android" ]; then
- adb push "$bin" "${androidpath}/${bin}" 2>/dev/null
- fi
-}
-
-rm -rf pkg
-
-suffix="-installsuffix testcshared"
-
-libext="so"
-if [ "$goos" = "darwin" ]; then
- libext="dylib"
-fi
-
-# Create the header files.
-GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo
-
-GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.$libext src/libgo/libgo.go
-binpush libgo.$libext
-
-if [ "$goos" = "linux" ] || [ "$goos" = "android" ] ; then
- if readelf -d libgo.$libext | grep TEXTREL >/dev/null; then
- echo "libgo.$libext has TEXTREL set"
- exit 1
- fi
-fi
-
-GOGCCFLAGS=$(go env GOGCCFLAGS)
-if [ "$goos" = "android" ]; then
- GOGCCFLAGS="${GOGCCFLAGS} -pie -fuse-ld=gold"
-fi
-
-status=0
-
-# test0: exported symbols in shared lib are accessible.
-# TODO(iant): using _shared here shouldn't really be necessary.
-$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c ./libgo.$libext
-binpush testp
-
-output=$(run LD_LIBRARY_PATH=. ./testp)
-if [ "$output" != "PASS" ]; then
- echo "FAIL test0 got ${output}"
- status=1
-fi
-
-# test1: shared library can be dynamically loaded and exported symbols are accessible.
-$(go env CC) ${GOGCCFLAGS} -o testp main1.c -ldl
-binpush testp
-output=$(run ./testp ./libgo.$libext)
-if [ "$output" != "PASS" ]; then
- echo "FAIL test1 got ${output}"
- status=1
-fi
-
-# test2: tests libgo2 which does not export any functions.
-GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.$libext libgo2
-binpush libgo2.$libext
-linkflags="-Wl,--no-as-needed"
-if [ "$goos" = "darwin" ]; then
- linkflags=""
-fi
-$(go env CC) ${GOGCCFLAGS} -o testp2 main2.c $linkflags libgo2.$libext
-binpush testp2
-output=$(run LD_LIBRARY_PATH=. ./testp2)
-if [ "$output" != "PASS" ]; then
- echo "FAIL test2 got ${output}"
- status=1
-fi
-
-# test3: tests main.main is exported on android.
-if [ "$goos" = "android" ]; then
- $(go env CC) ${GOGCCFLAGS} -o testp3 main3.c -ldl
- binpush testp3
- output=$(run ./testp ./libgo.so)
- if [ "$output" != "PASS" ]; then
- echo "FAIL test3 got ${output}"
- status=1
- fi
-fi
-
-# test4: tests signal handlers
-GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo4.$libext libgo4
-binpush libgo4.$libext
-$(go env CC) ${GOGCCFLAGS} -pthread -o testp4 main4.c -ldl
-binpush testp4
-output=$(run ./testp4 ./libgo4.$libext 2>&1)
-if test "$output" != "PASS"; then
- echo "FAIL test4 got ${output}"
- if test "$goos" != "android"; then
- echo "re-running test4 in verbose mode"
- ./testp4 ./libgo4.$libext verbose
- fi
- status=1
-fi
-
-# test5: tests signal handlers with os/signal.Notify
-GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo5.$libext libgo5
-binpush libgo5.$libext
-$(go env CC) ${GOGCCFLAGS} -pthread -o testp5 main5.c -ldl
-binpush testp5
-output=$(run ./testp5 ./libgo5.$libext 2>&1)
-if test "$output" != "PASS"; then
- echo "FAIL test5 got ${output}"
- if test "$goos" != "android"; then
- echo "re-running test5 in verbose mode"
- ./testp5 ./libgo5.$libext verbose
- fi
- status=1
-fi
-
-if test "$libext" = "dylib"; then
- # make sure dylibs are well-formed
- if ! otool -l libgo*.dylib >/dev/null; then
- status=1
- fi
-fi
-
-if test $status = 0; then
- echo "ok"
-fi
-
-exit $status
diff --git a/libgo/misc/cgo/testplugin/src/host/host.go b/libgo/misc/cgo/testplugin/src/host/host.go
index 898f44efa15..0ca17da3def 100644
--- a/libgo/misc/cgo/testplugin/src/host/host.go
+++ b/libgo/misc/cgo/testplugin/src/host/host.go
@@ -126,14 +126,24 @@ func main() {
log.Fatalf(`plugin1.F()=%d, want 17`, gotf)
}
- // plugin2 has no exported symbols, only an init function.
- if _, err := plugin.Open("plugin2.so"); err != nil {
+ p2, err := plugin.Open("plugin2.so")
+ if err != nil {
log.Fatalf("plugin.Open failed: %v", err)
}
+ // Check that plugin2's init function was called, and
+ // that it modifies the same global variable as the host.
if got, want := common.X, 2; got != want {
log.Fatalf("after loading plugin2, common.X=%d, want %d", got, want)
}
+ _, err = plugin.Open("plugin2-dup.so")
+ if err == nil {
+ log.Fatal(`plugin.Open("plugin2-dup.so"): duplicate open should have failed`)
+ }
+ if s := err.Error(); !strings.Contains(s, "already loaded") {
+ log.Fatal(`plugin.Open("plugin2.so"): error does not mention "already loaded"`)
+ }
+
_, err = plugin.Open("plugin-mismatch.so")
if err == nil {
log.Fatal(`plugin.Open("plugin-mismatch.so"): should have failed`)
@@ -142,6 +152,24 @@ func main() {
log.Fatalf(`plugin.Open("plugin-mismatch.so"): error does not mention "different version": %v`, s)
}
+ _, err = plugin.Open("plugin2-dup.so")
+ if err == nil {
+ log.Fatal(`plugin.Open("plugin2-dup.so"): duplicate open after bad plugin should have failed`)
+ }
+ _, err = plugin.Open("plugin2.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("plugin2.so"): second open with same name failed: %v`, err)
+ }
+
+ // Test that unexported types with the same names in
+ // different plugins do not interfere with each other.
+ //
+ // See Issue #21386.
+ UnexportedNameReuse, _ := p.Lookup("UnexportedNameReuse")
+ UnexportedNameReuse.(func())()
+ UnexportedNameReuse, _ = p2.Lookup("UnexportedNameReuse")
+ UnexportedNameReuse.(func())()
+
testUnnamed()
fmt.Println("PASS")
diff --git a/libgo/misc/cgo/testplugin/src/issue18584/main.go b/libgo/misc/cgo/testplugin/src/issue18584/main.go
new file mode 100644
index 00000000000..c280fd46203
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue18584/main.go
@@ -0,0 +1,23 @@
+// 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.
+
+package main
+
+import "plugin"
+
+func main() {
+ p, err := plugin.Open("plugin.so")
+ if err != nil {
+ panic(err)
+ }
+
+ sym, err := p.Lookup("G")
+ if err != nil {
+ panic(err)
+ }
+ g := sym.(func() bool)
+ if !g() {
+ panic("expected types to match, Issue #18584")
+ }
+}
diff --git a/libgo/misc/cgo/testplugin/src/issue18584/plugin.go b/libgo/misc/cgo/testplugin/src/issue18584/plugin.go
new file mode 100644
index 00000000000..be0868d3752
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue18584/plugin.go
@@ -0,0 +1,19 @@
+// 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.
+
+package main
+
+import "reflect"
+
+type C struct {
+}
+
+func F(c *C) *C {
+ return nil
+}
+
+func G() bool {
+ var c *C
+ return reflect.TypeOf(F).Out(0) == reflect.TypeOf(c)
+}
diff --git a/libgo/misc/cgo/testplugin/src/issue19418/main.go b/libgo/misc/cgo/testplugin/src/issue19418/main.go
new file mode 100644
index 00000000000..2ec9f9aaaa2
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue19418/main.go
@@ -0,0 +1,29 @@
+// 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.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "plugin"
+)
+
+func main() {
+ p, err := plugin.Open("plugin.so")
+ if err != nil {
+ panic(err)
+ }
+
+ val, err := p.Lookup("Val")
+ if err != nil {
+ panic(err)
+ }
+ got := *val.(*string)
+ const want = "linkstr"
+ if got != want {
+ fmt.Fprintf(os.Stderr, "issue19418 value is %q, want %q\n", got, want)
+ os.Exit(2)
+ }
+}
diff --git a/libgo/misc/cgo/testplugin/src/issue19418/plugin.go b/libgo/misc/cgo/testplugin/src/issue19418/plugin.go
new file mode 100644
index 00000000000..fe93b161431
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue19418/plugin.go
@@ -0,0 +1,7 @@
+// 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.
+
+package main
+
+var Val = "val-unset"
diff --git a/libgo/misc/cgo/testplugin/src/issue19529/plugin.go b/libgo/misc/cgo/testplugin/src/issue19529/plugin.go
new file mode 100644
index 00000000000..ad2df6cc7c7
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue19529/plugin.go
@@ -0,0 +1,15 @@
+package main
+
+import (
+ "reflect"
+)
+
+type Foo struct {
+ Bar string `json:"Bar@baz,omitempty"`
+}
+
+func F() {
+ println(reflect.TypeOf(Foo{}).Field(0).Tag)
+}
+
+func main() {}
diff --git a/libgo/misc/cgo/testplugin/src/issue22175/main.go b/libgo/misc/cgo/testplugin/src/issue22175/main.go
new file mode 100644
index 00000000000..9be9bab9dc3
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue22175/main.go
@@ -0,0 +1,28 @@
+// 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.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "plugin"
+)
+
+func main() {
+ p2, err := plugin.Open("issue22175_plugin1.so")
+ if err != nil {
+ panic(err)
+ }
+ f, err := p2.Lookup("F")
+ if err != nil {
+ panic(err)
+ }
+ got := f.(func() int)()
+ const want = 971
+ if got != want {
+ fmt.Fprintf(os.Stderr, "issue22175: F()=%d, want %d", got, want)
+ os.Exit(1)
+ }
+}
diff --git a/libgo/misc/cgo/testplugin/src/issue22175/plugin1.go b/libgo/misc/cgo/testplugin/src/issue22175/plugin1.go
new file mode 100644
index 00000000000..5ae6cb631e7
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue22175/plugin1.go
@@ -0,0 +1,21 @@
+// 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.
+
+package main
+
+import "plugin"
+
+func F() int {
+ p2, err := plugin.Open("issue22175_plugin2.so")
+ if err != nil {
+ panic(err)
+ }
+ g, err := p2.Lookup("G")
+ if err != nil {
+ panic(err)
+ }
+ return g.(func() int)()
+}
+
+func main() {}
diff --git a/libgo/misc/cgo/testplugin/src/issue22175/plugin2.go b/libgo/misc/cgo/testplugin/src/issue22175/plugin2.go
new file mode 100644
index 00000000000..f387a192e67
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue22175/plugin2.go
@@ -0,0 +1,9 @@
+// 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.
+
+package main
+
+func G() int { return 971 }
+
+func main() {}
diff --git a/libgo/misc/cgo/testplugin/src/issue22295.pkg/main.go b/libgo/misc/cgo/testplugin/src/issue22295.pkg/main.go
new file mode 100644
index 00000000000..6cb186e1003
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue22295.pkg/main.go
@@ -0,0 +1,28 @@
+// 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.
+
+// +build ignore
+
+package main
+
+import (
+ "log"
+ "plugin"
+)
+
+func main() {
+ p, err := plugin.Open("issue.22295.so")
+ if err != nil {
+ log.Fatal(err)
+ }
+ f, err := p.Lookup("F")
+ if err != nil {
+ log.Fatal(err)
+ }
+ const want = 2503
+ got := f.(func() int)()
+ if got != want {
+ log.Fatalf("got %d, want %d", got, want)
+ }
+}
diff --git a/libgo/misc/cgo/testplugin/src/issue22295.pkg/plugin.go b/libgo/misc/cgo/testplugin/src/issue22295.pkg/plugin.go
new file mode 100644
index 00000000000..46b08a405bc
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/src/issue22295.pkg/plugin.go
@@ -0,0 +1,16 @@
+// 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.
+
+package main
+
+var f *int
+
+func init() {
+ f = new(int)
+ *f = 2503
+}
+
+func F() int { return *f }
+
+func main() {}
diff --git a/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go b/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go
index edcef2c77e9..0a9fa2f2c1f 100644
--- a/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go
+++ b/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go
@@ -7,7 +7,10 @@ package main
// // No C code required.
import "C"
-import "common"
+import (
+ "common"
+ "reflect"
+)
func F() int {
_ = make([]byte, 1<<21) // trigger stack unwind, Issue #18190.
@@ -33,6 +36,21 @@ func init() {
call(g)
}
+type sameNameReusedInPlugins struct {
+ X string
+}
+
+type sameNameHolder struct {
+ F *sameNameReusedInPlugins
+}
+
+func UnexportedNameReuse() {
+ h := sameNameHolder{}
+ v := reflect.ValueOf(&h).Elem().Field(0)
+ newval := reflect.New(v.Type().Elem())
+ v.Set(newval)
+}
+
func main() {
panic("plugin1.main called")
}
diff --git a/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go b/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go
index 9c507fc3658..a67f2de27a7 100644
--- a/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go
+++ b/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go
@@ -13,6 +13,7 @@ import "C"
import (
"common"
+ "reflect"
"strings"
)
@@ -22,6 +23,21 @@ func init() {
common.X = 2
}
+type sameNameReusedInPlugins struct {
+ X string
+}
+
+type sameNameHolder struct {
+ F *sameNameReusedInPlugins
+}
+
+func UnexportedNameReuse() {
+ h := sameNameHolder{}
+ v := reflect.ValueOf(&h).Elem().Field(0)
+ newval := reflect.New(v.Type().Elem())
+ v.Set(newval)
+}
+
func main() {
panic("plugin1.main called")
}
diff --git a/libgo/misc/cgo/testplugin/test.bash b/libgo/misc/cgo/testplugin/test.bash
index 69df5bd2bfa..18e3803bf42 100644
--- a/libgo/misc/cgo/testplugin/test.bash
+++ b/libgo/misc/cgo/testplugin/test.bash
@@ -15,38 +15,73 @@ goos=$(go env GOOS)
goarch=$(go env GOARCH)
function cleanup() {
- rm -f plugin*.so unnamed*.so iface*.so
- rm -rf host pkg sub iface issue18676 issue19534
+ rm -f plugin*.so unnamed*.so iface*.so issue*
+ rm -rf host pkg sub iface
}
trap cleanup EXIT
rm -rf pkg sub
mkdir sub
-GOPATH=$(pwd) go build -buildmode=plugin plugin1
-GOPATH=$(pwd) go build -buildmode=plugin plugin2
-GOPATH=$(pwd)/altpath go build -buildmode=plugin plugin-mismatch
-GOPATH=$(pwd) go build -buildmode=plugin -o=sub/plugin1.so sub/plugin1
-GOPATH=$(pwd) go build -buildmode=plugin unnamed1.go
-GOPATH=$(pwd) go build -buildmode=plugin unnamed2.go
-GOPATH=$(pwd) go build host
+GOPATH=$(pwd) go build -i -gcflags "$GO_GCFLAGS" -buildmode=plugin plugin1
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin plugin2
+cp plugin2.so plugin2-dup.so
+GOPATH=$(pwd)/altpath go build -gcflags "$GO_GCFLAGS" -buildmode=plugin plugin-mismatch
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=sub/plugin1.so sub/plugin1
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed1.so unnamed1/main.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed2.so unnamed2/main.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" host
LD_LIBRARY_PATH=$(pwd) ./host
# Test that types and itabs get properly uniqified.
-GOPATH=$(pwd) go build -buildmode=plugin iface_a
-GOPATH=$(pwd) go build -buildmode=plugin iface_b
-GOPATH=$(pwd) go build iface
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin iface_a
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin iface_b
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" iface
LD_LIBRARY_PATH=$(pwd) ./iface
+function _timeout() (
+ set -e
+ $2 &
+ p=$!
+ (sleep $1; kill $p 2>/dev/null) &
+ p2=$!
+ wait $p 2>/dev/null
+ kill -0 $p2 2>/dev/null
+)
+
# Test for issue 18676 - make sure we don't add the same itab twice.
# The buggy code hangs forever, so use a timeout to check for that.
-GOPATH=$(pwd) go build -buildmode=plugin -o plugin.so src/issue18676/plugin.go
-GOPATH=$(pwd) go build -o issue18676 src/issue18676/main.go
-timeout 10s ./issue18676
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o plugin.so src/issue18676/plugin.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue18676 src/issue18676/main.go
+_timeout 10s ./issue18676
# Test for issue 19534 - that we can load a plugin built in a path with non-alpha
# characters
-GOPATH=$(pwd) go build -buildmode=plugin -ldflags='-pluginpath=issue.19534' -o plugin.so src/issue19534/plugin.go
-GOPATH=$(pwd) go build -o issue19534 src/issue19534/main.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -ldflags='-pluginpath=issue.19534' -o plugin.so src/issue19534/plugin.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue19534 src/issue19534/main.go
./issue19534
+
+# Test for issue 18584
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o plugin.so src/issue18584/plugin.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue18584 src/issue18584/main.go
+./issue18584
+
+# Test for issue 19418
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin "-ldflags=-X main.Val=linkstr" -o plugin.so src/issue19418/plugin.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue19418 src/issue19418/main.go
+./issue19418
+
+# Test for issue 19529
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o plugin.so src/issue19529/plugin.go
+
+# Test for issue 22175
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue22175_plugin1.so src/issue22175/plugin1.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue22175_plugin2.so src/issue22175/plugin2.go
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22175 src/issue22175/main.go
+./issue22175
+
+# Test for issue 22295
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue.22295.so issue22295.pkg
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/main.go
+./issue22295
diff --git a/libgo/misc/cgo/testplugin/unnamed1.go b/libgo/misc/cgo/testplugin/unnamed1/main.go
index 5c1df086d76..5c1df086d76 100644
--- a/libgo/misc/cgo/testplugin/unnamed1.go
+++ b/libgo/misc/cgo/testplugin/unnamed1/main.go
diff --git a/libgo/misc/cgo/testplugin/unnamed2.go b/libgo/misc/cgo/testplugin/unnamed2/main.go
index 7ef66109c5c..7ef66109c5c 100644
--- a/libgo/misc/cgo/testplugin/unnamed2.go
+++ b/libgo/misc/cgo/testplugin/unnamed2/main.go
diff --git a/libgo/misc/cgo/testsanitizers/cc_test.go b/libgo/misc/cgo/testsanitizers/cc_test.go
new file mode 100644
index 00000000000..cacb0d93df7
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/cc_test.go
@@ -0,0 +1,441 @@
+// 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.
+
+// sanitizers_test checks the use of Go with sanitizers like msan, asan, etc.
+// See https://github.com/google/sanitizers.
+package sanitizers_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+ "testing"
+ "unicode"
+)
+
+var overcommit struct {
+ sync.Once
+ value int
+ err error
+}
+
+// requireOvercommit skips t if the kernel does not allow overcommit.
+func requireOvercommit(t *testing.T) {
+ t.Helper()
+
+ overcommit.Once.Do(func() {
+ var out []byte
+ out, overcommit.err = ioutil.ReadFile("/proc/sys/vm/overcommit_memory")
+ if overcommit.err != nil {
+ return
+ }
+ overcommit.value, overcommit.err = strconv.Atoi(string(bytes.TrimSpace(out)))
+ })
+
+ if overcommit.err != nil {
+ t.Skipf("couldn't determine vm.overcommit_memory (%v); assuming no overcommit", overcommit.err)
+ }
+ if overcommit.value == 2 {
+ t.Skip("vm.overcommit_memory=2")
+ }
+}
+
+var env struct {
+ sync.Once
+ m map[string]string
+ err error
+}
+
+// goEnv returns the output of $(go env) as a map.
+func goEnv(key string) (string, error) {
+ env.Once.Do(func() {
+ var out []byte
+ out, env.err = exec.Command("go", "env", "-json").Output()
+ if env.err != nil {
+ return
+ }
+
+ env.m = make(map[string]string)
+ env.err = json.Unmarshal(out, &env.m)
+ })
+ if env.err != nil {
+ return "", env.err
+ }
+
+ v, ok := env.m[key]
+ if !ok {
+ return "", fmt.Errorf("`go env`: no entry for %v", key)
+ }
+ return v, nil
+}
+
+// replaceEnv sets the key environment variable to value in cmd.
+func replaceEnv(cmd *exec.Cmd, key, value string) {
+ if cmd.Env == nil {
+ cmd.Env = os.Environ()
+ }
+ cmd.Env = append(cmd.Env, key+"="+value)
+}
+
+// mustRun executes t and fails cmd with a well-formatted message if it fails.
+func mustRun(t *testing.T, cmd *exec.Cmd) {
+ t.Helper()
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("%#q exited with %v\n%s", strings.Join(cmd.Args, " "), err, out)
+ }
+}
+
+// cc returns a cmd that executes `$(go env CC) $(go env GOGCCFLAGS) $args`.
+func cc(args ...string) (*exec.Cmd, error) {
+ CC, err := goEnv("CC")
+ if err != nil {
+ return nil, err
+ }
+
+ GOGCCFLAGS, err := goEnv("GOGCCFLAGS")
+ if err != nil {
+ return nil, err
+ }
+
+ // Split GOGCCFLAGS, respecting quoting.
+ //
+ // TODO(bcmills): This code also appears in
+ // misc/cgo/testcarchive/carchive_test.go, and perhaps ought to go in
+ // src/cmd/dist/test.go as well. Figure out where to put it so that it can be
+ // shared.
+ var flags []string
+ quote := '\000'
+ start := 0
+ lastSpace := true
+ backslash := false
+ for i, c := range GOGCCFLAGS {
+ if quote == '\000' && unicode.IsSpace(c) {
+ if !lastSpace {
+ flags = append(flags, GOGCCFLAGS[start:i])
+ lastSpace = true
+ }
+ } else {
+ if lastSpace {
+ start = i
+ lastSpace = false
+ }
+ if quote == '\000' && !backslash && (c == '"' || c == '\'') {
+ quote = c
+ backslash = false
+ } else if !backslash && quote == c {
+ quote = '\000'
+ } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
+ backslash = true
+ } else {
+ backslash = false
+ }
+ }
+ }
+ if !lastSpace {
+ flags = append(flags, GOGCCFLAGS[start:])
+ }
+
+ cmd := exec.Command(CC, flags...)
+ cmd.Args = append(cmd.Args, args...)
+ return cmd, nil
+}
+
+type version struct {
+ name string
+ major, minor int
+}
+
+var compiler struct {
+ sync.Once
+ version
+ err error
+}
+
+// compilerVersion detects the version of $(go env CC).
+//
+// It returns a non-nil error if the compiler matches a known version schema but
+// the version could not be parsed, or if $(go env CC) could not be determined.
+func compilerVersion() (version, error) {
+ compiler.Once.Do(func() {
+ compiler.err = func() error {
+ compiler.name = "unknown"
+
+ cmd, err := cc("--version")
+ if err != nil {
+ return err
+ }
+ out, err := cmd.Output()
+ if err != nil {
+ // Compiler does not support "--version" flag: not Clang or GCC.
+ return nil
+ }
+
+ var match [][]byte
+ if bytes.HasPrefix(out, []byte("gcc")) {
+ compiler.name = "gcc"
+
+ cmd, err := cc("-dumpversion")
+ if err != nil {
+ return err
+ }
+ out, err := cmd.Output()
+ if err != nil {
+ // gcc, but does not support gcc's "-dumpversion" flag?!
+ return err
+ }
+ gccRE := regexp.MustCompile(`(\d+)\.(\d+)`)
+ match = gccRE.FindSubmatch(out)
+ } else {
+ clangRE := regexp.MustCompile(`clang version (\d+)\.(\d+)`)
+ if match = clangRE.FindSubmatch(out); len(match) > 0 {
+ compiler.name = "clang"
+ }
+ }
+
+ if len(match) < 3 {
+ return nil // "unknown"
+ }
+ if compiler.major, err = strconv.Atoi(string(match[1])); err != nil {
+ return err
+ }
+ if compiler.minor, err = strconv.Atoi(string(match[2])); err != nil {
+ return err
+ }
+ return nil
+ }()
+ })
+ return compiler.version, compiler.err
+}
+
+type compilerCheck struct {
+ once sync.Once
+ err error
+ skip bool // If true, skip with err instead of failing with it.
+}
+
+type config struct {
+ sanitizer string
+
+ cFlags, ldFlags, goFlags []string
+
+ sanitizerCheck, runtimeCheck compilerCheck
+}
+
+var configs struct {
+ sync.Mutex
+ m map[string]*config
+}
+
+// configure returns the configuration for the given sanitizer.
+func configure(sanitizer string) *config {
+ configs.Lock()
+ defer configs.Unlock()
+ if c, ok := configs.m[sanitizer]; ok {
+ return c
+ }
+
+ c := &config{
+ sanitizer: sanitizer,
+ cFlags: []string{"-fsanitize=" + sanitizer},
+ ldFlags: []string{"-fsanitize=" + sanitizer},
+ }
+
+ if testing.Verbose() {
+ c.goFlags = append(c.goFlags, "-x")
+ }
+
+ switch sanitizer {
+ case "memory":
+ c.goFlags = append(c.goFlags, "-msan")
+
+ case "thread":
+ c.goFlags = append(c.goFlags, "--installsuffix=tsan")
+ compiler, _ := compilerVersion()
+ if compiler.name == "gcc" {
+ c.cFlags = append(c.cFlags, "-fPIC")
+ c.ldFlags = append(c.ldFlags, "-fPIC", "-static-libtsan")
+ }
+
+ default:
+ panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer))
+ }
+
+ if configs.m == nil {
+ configs.m = make(map[string]*config)
+ }
+ configs.m[sanitizer] = c
+ return c
+}
+
+// goCmd returns a Cmd that executes "go $subcommand $args" with appropriate
+// additional flags and environment.
+func (c *config) goCmd(subcommand string, args ...string) *exec.Cmd {
+ cmd := exec.Command("go", subcommand)
+ cmd.Args = append(cmd.Args, c.goFlags...)
+ cmd.Args = append(cmd.Args, args...)
+ replaceEnv(cmd, "CGO_CFLAGS", strings.Join(c.cFlags, " "))
+ replaceEnv(cmd, "CGO_LDFLAGS", strings.Join(c.ldFlags, " "))
+ return cmd
+}
+
+// skipIfCSanitizerBroken skips t if the C compiler does not produce working
+// binaries as configured.
+func (c *config) skipIfCSanitizerBroken(t *testing.T) {
+ check := &c.sanitizerCheck
+ check.once.Do(func() {
+ check.skip, check.err = c.checkCSanitizer()
+ })
+ if check.err != nil {
+ t.Helper()
+ if check.skip {
+ t.Skip(check.err)
+ }
+ t.Fatal(check.err)
+ }
+}
+
+var cMain = []byte(`
+int main() {
+ return 0;
+}
+`)
+
+func (c *config) checkCSanitizer() (skip bool, err error) {
+ dir, err := ioutil.TempDir("", c.sanitizer)
+ if err != nil {
+ return false, fmt.Errorf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ src := filepath.Join(dir, "return0.c")
+ if err := ioutil.WriteFile(src, cMain, 0600); err != nil {
+ return false, fmt.Errorf("failed to write C source file: %v", err)
+ }
+
+ dst := filepath.Join(dir, "return0")
+ cmd, err := cc(c.cFlags...)
+ if err != nil {
+ return false, err
+ }
+ cmd.Args = append(cmd.Args, c.ldFlags...)
+ cmd.Args = append(cmd.Args, "-o", dst, src)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ if bytes.Contains(out, []byte("-fsanitize")) &&
+ (bytes.Contains(out, []byte("unrecognized")) ||
+ bytes.Contains(out, []byte("unsupported"))) {
+ return true, errors.New(string(out))
+ }
+ return true, fmt.Errorf("%#q failed: %v\n%s", strings.Join(cmd.Args, " "), err, out)
+ }
+
+ if out, err := exec.Command(dst).CombinedOutput(); err != nil {
+ if os.IsNotExist(err) {
+ return true, fmt.Errorf("%#q failed to produce executable: %v", strings.Join(cmd.Args, " "), err)
+ }
+ snippet := bytes.SplitN(out, []byte{'\n'}, 2)[0]
+ return true, fmt.Errorf("%#q generated broken executable: %v\n%s", strings.Join(cmd.Args, " "), err, snippet)
+ }
+
+ return false, nil
+}
+
+// skipIfRuntimeIncompatible skips t if the Go runtime is suspected not to work
+// with cgo as configured.
+func (c *config) skipIfRuntimeIncompatible(t *testing.T) {
+ check := &c.runtimeCheck
+ check.once.Do(func() {
+ check.skip, check.err = c.checkRuntime()
+ })
+ if check.err != nil {
+ t.Helper()
+ if check.skip {
+ t.Skip(check.err)
+ }
+ t.Fatal(check.err)
+ }
+}
+
+func (c *config) checkRuntime() (skip bool, err error) {
+ if c.sanitizer != "thread" {
+ return false, nil
+ }
+
+ // libcgo.h sets CGO_TSAN if it detects TSAN support in the C compiler.
+ // Dump the preprocessor defines to check that that works.
+ // (Sometimes it doesn't: see https://golang.org/issue/15983.)
+ cmd, err := cc(c.cFlags...)
+ if err != nil {
+ return false, err
+ }
+ cmd.Args = append(cmd.Args, "-dM", "-E", "../../../src/runtime/cgo/libcgo.h")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return false, fmt.Errorf("%#q exited with %v\n%s", strings.Join(cmd.Args, " "), err, out)
+ }
+ if !bytes.Contains(out, []byte("#define CGO_TSAN")) {
+ return true, fmt.Errorf("%#q did not define CGO_TSAN")
+ }
+ return false, nil
+}
+
+// srcPath returns the path to the given file relative to this test's source tree.
+func srcPath(path string) string {
+ return filepath.Join("src", path)
+}
+
+// A tempDir manages a temporary directory within a test.
+type tempDir struct {
+ base string
+}
+
+func (d *tempDir) RemoveAll(t *testing.T) {
+ t.Helper()
+ if d.base == "" {
+ return
+ }
+ if err := os.RemoveAll(d.base); err != nil {
+ t.Fatal("Failed to remove temp dir: %v", err)
+ }
+}
+
+func (d *tempDir) Join(name string) string {
+ return filepath.Join(d.base, name)
+}
+
+func newTempDir(t *testing.T) *tempDir {
+ t.Helper()
+ dir, err := ioutil.TempDir("", filepath.Dir(t.Name()))
+ if err != nil {
+ t.Fatalf("Failed to create temp dir: %v", err)
+ }
+ return &tempDir{base: dir}
+}
+
+// hangProneCmd returns an exec.Cmd for a command that is likely to hang.
+//
+// If one of these tests hangs, the caller is likely to kill the test process
+// using SIGINT, which will be sent to all of the processes in the test's group.
+// Unfortunately, TSAN in particular is prone to dropping signals, so the SIGINT
+// may terminate the test binary but leave the subprocess running. hangProneCmd
+// configures subprocess to receive SIGKILL instead to ensure that it won't
+// leak.
+func hangProneCmd(name string, arg ...string) *exec.Cmd {
+ cmd := exec.Command(name, arg...)
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGKILL,
+ }
+ return cmd
+}
diff --git a/libgo/misc/cgo/testsanitizers/cshared_test.go b/libgo/misc/cgo/testsanitizers/cshared_test.go
new file mode 100644
index 00000000000..56063ea6201
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/cshared_test.go
@@ -0,0 +1,74 @@
+// 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.
+
+package sanitizers_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "strings"
+ "testing"
+)
+
+func TestShared(t *testing.T) {
+ t.Parallel()
+ requireOvercommit(t)
+
+ GOOS, err := goEnv("GOOS")
+ if err != nil {
+ t.Fatal(err)
+ }
+ libExt := "so"
+ if GOOS == "darwin" {
+ libExt = "dylib"
+ }
+
+ cases := []struct {
+ src string
+ sanitizer string
+ }{
+ {
+ src: "msan_shared.go",
+ sanitizer: "memory",
+ },
+ {
+ src: "tsan_shared.go",
+ sanitizer: "thread",
+ },
+ }
+
+ for _, tc := range cases {
+ tc := tc
+ name := strings.TrimSuffix(tc.src, ".go")
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+ config := configure(tc.sanitizer)
+ config.skipIfCSanitizerBroken(t)
+
+ dir := newTempDir(t)
+ defer dir.RemoveAll(t)
+
+ lib := dir.Join(fmt.Sprintf("lib%s.%s", name, libExt))
+ mustRun(t, config.goCmd("build", "-buildmode=c-shared", "-o", lib, srcPath(tc.src)))
+
+ cSrc := dir.Join("main.c")
+ if err := ioutil.WriteFile(cSrc, cMain, 0600); err != nil {
+ t.Fatalf("failed to write C source file: %v", err)
+ }
+
+ dstBin := dir.Join(name)
+ cmd, err := cc(config.cFlags...)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cmd.Args = append(cmd.Args, config.ldFlags...)
+ cmd.Args = append(cmd.Args, "-o", dstBin, cSrc, lib)
+ mustRun(t, cmd)
+
+ cmd = hangProneCmd(dstBin)
+ replaceEnv(cmd, "LD_LIBRARY_PATH", ".")
+ mustRun(t, cmd)
+ })
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan_test.go b/libgo/misc/cgo/testsanitizers/msan_test.go
new file mode 100644
index 00000000000..af5afa9ee48
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/msan_test.go
@@ -0,0 +1,55 @@
+// 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.
+
+package sanitizers_test
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestMSAN(t *testing.T) {
+ t.Parallel()
+ requireOvercommit(t)
+ config := configure("memory")
+ config.skipIfCSanitizerBroken(t)
+
+ mustRun(t, config.goCmd("build", "std"))
+
+ cases := []struct {
+ src string
+ wantErr bool
+ }{
+ {src: "msan.go"},
+ {src: "msan2.go"},
+ {src: "msan2_cmsan.go"},
+ {src: "msan3.go"},
+ {src: "msan4.go"},
+ {src: "msan5.go"},
+ {src: "msan_fail.go", wantErr: true},
+ }
+ for _, tc := range cases {
+ tc := tc
+ name := strings.TrimSuffix(tc.src, ".go")
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+
+ dir := newTempDir(t)
+ defer dir.RemoveAll(t)
+
+ outPath := dir.Join(name)
+ mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src)))
+
+ cmd := hangProneCmd(outPath)
+ if tc.wantErr {
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return
+ }
+ t.Fatalf("%#q exited without error; want MSAN failure\n%s", strings.Join(cmd.Args, " "), out)
+ }
+ mustRun(t, cmd)
+ })
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan.go b/libgo/misc/cgo/testsanitizers/src/msan.go
index 7915fa84f60..7915fa84f60 100644
--- a/libgo/misc/cgo/testsanitizers/msan.go
+++ b/libgo/misc/cgo/testsanitizers/src/msan.go
diff --git a/libgo/misc/cgo/testsanitizers/msan2.go b/libgo/misc/cgo/testsanitizers/src/msan2.go
index 6690cb034fc..6690cb034fc 100644
--- a/libgo/misc/cgo/testsanitizers/msan2.go
+++ b/libgo/misc/cgo/testsanitizers/src/msan2.go
diff --git a/libgo/misc/cgo/testsanitizers/src/msan2_cmsan.go b/libgo/misc/cgo/testsanitizers/src/msan2_cmsan.go
new file mode 100644
index 00000000000..8fdaea90c97
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/src/msan2_cmsan.go
@@ -0,0 +1,38 @@
+// Copyright 2015 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
+
+/*
+#cgo LDFLAGS: -fsanitize=memory
+#cgo CPPFLAGS: -fsanitize=memory
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+void f(int32_t *p, int n) {
+ int32_t * volatile q = (int32_t *)malloc(sizeof(int32_t) * n);
+ memcpy(p, q, n * sizeof(*p));
+ free(q);
+}
+
+void g(int32_t *p, int n) {
+ if (p[4] != 1) {
+ abort();
+ }
+}
+*/
+import "C"
+
+import (
+ "unsafe"
+)
+
+func main() {
+ a := make([]int32, 10)
+ C.f((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a)))
+ a[4] = 1
+ C.g((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a)))
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan3.go b/libgo/misc/cgo/testsanitizers/src/msan3.go
index 61a9c29e1a9..61a9c29e1a9 100644
--- a/libgo/misc/cgo/testsanitizers/msan3.go
+++ b/libgo/misc/cgo/testsanitizers/src/msan3.go
diff --git a/libgo/misc/cgo/testsanitizers/msan4.go b/libgo/misc/cgo/testsanitizers/src/msan4.go
index 6c91ff5f091..6c91ff5f091 100644
--- a/libgo/misc/cgo/testsanitizers/msan4.go
+++ b/libgo/misc/cgo/testsanitizers/src/msan4.go
diff --git a/libgo/misc/cgo/testsanitizers/msan5.go b/libgo/misc/cgo/testsanitizers/src/msan5.go
index f1479eb8a00..f1479eb8a00 100644
--- a/libgo/misc/cgo/testsanitizers/msan5.go
+++ b/libgo/misc/cgo/testsanitizers/src/msan5.go
diff --git a/libgo/misc/cgo/testsanitizers/msan_fail.go b/libgo/misc/cgo/testsanitizers/src/msan_fail.go
index 4c8dab34f6e..4c8dab34f6e 100644
--- a/libgo/misc/cgo/testsanitizers/msan_fail.go
+++ b/libgo/misc/cgo/testsanitizers/src/msan_fail.go
diff --git a/libgo/misc/cgo/testsanitizers/msan_shared.go b/libgo/misc/cgo/testsanitizers/src/msan_shared.go
index 966947cac35..966947cac35 100644
--- a/libgo/misc/cgo/testsanitizers/msan_shared.go
+++ b/libgo/misc/cgo/testsanitizers/src/msan_shared.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan.go b/libgo/misc/cgo/testsanitizers/src/tsan.go
index 6c377a701fb..6c377a701fb 100644
--- a/libgo/misc/cgo/testsanitizers/tsan.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan10.go b/libgo/misc/cgo/testsanitizers/src/tsan10.go
index a40f2455537..a40f2455537 100644
--- a/libgo/misc/cgo/testsanitizers/tsan10.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan10.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan11.go b/libgo/misc/cgo/testsanitizers/src/tsan11.go
index 70ac9c8ae2c..70ac9c8ae2c 100644
--- a/libgo/misc/cgo/testsanitizers/tsan11.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan11.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan12.go b/libgo/misc/cgo/testsanitizers/src/tsan12.go
index 3e767eee1f8..3e767eee1f8 100644
--- a/libgo/misc/cgo/testsanitizers/tsan12.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan12.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan2.go b/libgo/misc/cgo/testsanitizers/src/tsan2.go
index 5018a1987ca..5018a1987ca 100644
--- a/libgo/misc/cgo/testsanitizers/tsan2.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan2.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan3.go b/libgo/misc/cgo/testsanitizers/src/tsan3.go
index 87f6c80f1b1..87f6c80f1b1 100644
--- a/libgo/misc/cgo/testsanitizers/tsan3.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan3.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan4.go b/libgo/misc/cgo/testsanitizers/src/tsan4.go
index f0c76d84116..f0c76d84116 100644
--- a/libgo/misc/cgo/testsanitizers/tsan4.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan4.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan5.go b/libgo/misc/cgo/testsanitizers/src/tsan5.go
index 1214a7743b6..1214a7743b6 100644
--- a/libgo/misc/cgo/testsanitizers/tsan5.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan5.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan6.go b/libgo/misc/cgo/testsanitizers/src/tsan6.go
index c96f08d2f37..c96f08d2f37 100644
--- a/libgo/misc/cgo/testsanitizers/tsan6.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan6.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan7.go b/libgo/misc/cgo/testsanitizers/src/tsan7.go
index 2fb9e45ee2d..2fb9e45ee2d 100644
--- a/libgo/misc/cgo/testsanitizers/tsan7.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan7.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan8.go b/libgo/misc/cgo/testsanitizers/src/tsan8.go
index 88d82a60789..88d82a60789 100644
--- a/libgo/misc/cgo/testsanitizers/tsan8.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan8.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan9.go b/libgo/misc/cgo/testsanitizers/src/tsan9.go
index f166d8b495a..f166d8b495a 100644
--- a/libgo/misc/cgo/testsanitizers/tsan9.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan9.go
diff --git a/libgo/misc/cgo/testsanitizers/tsan_shared.go b/libgo/misc/cgo/testsanitizers/src/tsan_shared.go
index 55ff67ecbaf..55ff67ecbaf 100644
--- a/libgo/misc/cgo/testsanitizers/tsan_shared.go
+++ b/libgo/misc/cgo/testsanitizers/src/tsan_shared.go
diff --git a/libgo/misc/cgo/testsanitizers/test.bash b/libgo/misc/cgo/testsanitizers/test.bash
deleted file mode 100644
index 9f80af6c507..00000000000
--- a/libgo/misc/cgo/testsanitizers/test.bash
+++ /dev/null
@@ -1,233 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2015 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.
-
-# This directory is intended to test the use of Go with sanitizers
-# like msan, asan, etc. See https://github.com/google/sanitizers .
-
-set -e
-
-# The sanitizers were originally developed with clang, so prefer it.
-CC=cc
-if test -x "$(type -p clang)"; then
- CC=clang
-fi
-export CC
-
-if [ "$(sysctl -n vm.overcommit_memory)" = 2 ]; then
- echo "skipping msan/tsan tests: vm.overcommit_memory=2" >&2
- exit 0
-fi
-
-msan=yes
-
-TMPDIR=${TMPDIR:-/tmp}
-echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
-if $CC -fsanitize=memory -o ${TMPDIR}/testsanitizers$$ ${TMPDIR}/testsanitizers$$.c 2>&1 | grep "unrecognized" >& /dev/null; then
- echo "skipping msan tests: $CC -fsanitize=memory not supported"
- msan=no
-elif ! test -x ${TMPDIR}/testsanitizers$$; then
- echo "skipping msan tests: $CC -fsanitize-memory did not generate an executable"
- msan=no
-elif ! ${TMPDIR}/testsanitizers$$ >/dev/null 2>&1; then
- echo "skipping msan tests: $CC -fsanitize-memory generates broken executable"
- msan=no
-fi
-rm -f ${TMPDIR}/testsanitizers$$.*
-
-tsan=yes
-
-# The memory and thread sanitizers in versions of clang before 3.6
-# don't work with Go.
-if test "$msan" = "yes" && $CC --version | grep clang >& /dev/null; then
- ver=$($CC --version | sed -e 's/.* version \([0-9.-]*\).*/\1/')
- major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
- minor=$(echo $ver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
- if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 6; then
- echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.6)"
- msan=no
- tsan=no
- fi
-
- # Clang before 3.8 does not work with Linux at or after 4.1.
- # golang.org/issue/12898.
- if test "$msan" = "yes" -a "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 8; then
- if test "$(uname)" = Linux; then
- linuxver=$(uname -r)
- linuxmajor=$(echo $linuxver | sed -e 's/\([0-9]*\).*/\1/')
- linuxminor=$(echo $linuxver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
- if test "$linuxmajor" -gt 4 || test "$linuxmajor" -eq 4 -a "$linuxminor" -ge 1; then
- echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)"
- msan=no
- tsan=no
- fi
- fi
- fi
-fi
-
-status=0
-
-testmsanshared() {
- goos=$(go env GOOS)
- suffix="-installsuffix testsanitizers"
- libext="so"
- if [ "$goos" = "darwin" ]; then
- libext="dylib"
- fi
- go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go
-
- echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c
- $CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext
-
- if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then
- echo "FAIL: msan_shared"
- status=1
- fi
- rm -f ${TMPDIR}/{testmsanshared,testmsanshared.c,libmsanshared.$libext}
-}
-
-if test "$msan" = "yes"; then
- if ! go build -msan std; then
- echo "FAIL: build -msan std"
- status=1
- fi
-
- if ! go run -msan msan.go; then
- echo "FAIL: msan"
- status=1
- fi
-
- if ! CGO_LDFLAGS="-fsanitize=memory" CGO_CPPFLAGS="-fsanitize=memory" go run -msan -a msan2.go; then
- echo "FAIL: msan2 with -fsanitize=memory"
- status=1
- fi
-
- if ! go run -msan -a msan2.go; then
- echo "FAIL: msan2"
- status=1
- fi
-
- if ! go run -msan msan3.go; then
- echo "FAIL: msan3"
- status=1
- fi
-
- if ! go run -msan msan4.go; then
- echo "FAIL: msan4"
- status=1
- fi
-
- if ! go run -msan msan5.go; then
- echo "FAIL: msan5"
- status=1
- fi
-
- if go run -msan msan_fail.go 2>/dev/null; then
- echo "FAIL: msan_fail"
- status=1
- fi
-
- testmsanshared
-fi
-
-testtsanshared() {
- goos=$(go env GOOS)
- suffix="-installsuffix tsan"
- libext="so"
- if [ "$goos" = "darwin" ]; then
- libext="dylib"
- fi
- go build -buildmode=c-shared $suffix -o ${TMPDIR}/libtsanshared.$libext tsan_shared.go
-
- echo 'int main() { return 0; }' > ${TMPDIR}/testtsanshared.c
- $CC $(go env GOGCCFLAGS) -fsanitize=thread -o ${TMPDIR}/testtsanshared ${TMPDIR}/testtsanshared.c ${TMPDIR}/libtsanshared.$libext
-
- if ! LD_LIBRARY_PATH=. ${TMPDIR}/testtsanshared; then
- echo "FAIL: tsan_shared"
- status=1
- fi
- rm -f ${TMPDIR}/{testtsanshared,testtsanshared.c,libtsanshared.$libext}
-}
-
-if test "$tsan" = "yes"; then
- echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
- ok=yes
- if ! $CC -fsanitize=thread ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$ &> ${TMPDIR}/testsanitizers$$.err; then
- ok=no
- fi
- if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then
- echo "skipping tsan tests: -fsanitize=thread not supported"
- tsan=no
- elif test "$ok" != "yes"; then
- cat ${TMPDIR}/testsanitizers$$.err
- echo "skipping tsan tests: -fsanitizer=thread build failed"
- tsan=no
- elif ! ${TMPDIR}/testsanitizers$$ 2>&1; then
- echo "skipping tsan tests: running tsan program failed"
- tsan=no
- fi
- rm -f ${TMPDIR}/testsanitizers$$*
-fi
-
-# Run a TSAN test.
-# $1 test name
-# $2 environment variables
-# $3 go run args
-testtsan() {
- err=${TMPDIR}/tsanerr$$.out
- if ! env $2 go run $3 $1 2>$err; then
- cat $err
- echo "FAIL: $1"
- status=1
- elif grep -i warning $err >/dev/null 2>&1; then
- cat $err
- echo "FAIL: $1"
- status=1
- fi
- rm -f $err
-}
-
-if test "$tsan" = "yes"; then
- testtsan tsan.go
- testtsan tsan2.go
- testtsan tsan3.go
- testtsan tsan4.go
- testtsan tsan8.go
- testtsan tsan9.go
-
- # These tests are only reliable using clang or GCC version 7 or later.
- # Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
- ok=false
- clang=false
- if ${CC} --version | grep clang >/dev/null 2>&1; then
- ok=true
- clang=true
- else
- ver=$($CC -dumpversion)
- major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
- if test "$major" -lt 7; then
- echo "skipping remaining TSAN tests: GCC version $major (older than 7)"
- else
- ok=true
- fi
- fi
-
- if test "$ok" = "true"; then
- # These tests require rebuilding os/user with -fsanitize=thread.
- testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
- testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
- testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
-
- # The remaining tests reportedly hang when built with GCC; issue #21196.
- if test "$clang" = "true"; then
- testtsan tsan10.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
- testtsan tsan11.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
- testtsan tsan12.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
- fi
-
- testtsanshared
- fi
-fi
-
-exit $status
diff --git a/libgo/misc/cgo/testsanitizers/tsan_test.go b/libgo/misc/cgo/testsanitizers/tsan_test.go
new file mode 100644
index 00000000000..ec4e0033fb4
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan_test.go
@@ -0,0 +1,56 @@
+// 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.
+
+package sanitizers_test
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestTSAN(t *testing.T) {
+ t.Parallel()
+ requireOvercommit(t)
+ config := configure("thread")
+ config.skipIfCSanitizerBroken(t)
+
+ mustRun(t, config.goCmd("build", "std"))
+
+ cases := []struct {
+ src string
+ needsRuntime bool
+ }{
+ {src: "tsan.go"},
+ {src: "tsan2.go"},
+ {src: "tsan3.go"},
+ {src: "tsan4.go"},
+ {src: "tsan5.go", needsRuntime: true},
+ {src: "tsan6.go", needsRuntime: true},
+ {src: "tsan7.go", needsRuntime: true},
+ {src: "tsan8.go"},
+ {src: "tsan9.go"},
+ {src: "tsan10.go", needsRuntime: true},
+ {src: "tsan11.go", needsRuntime: true},
+ {src: "tsan12.go", needsRuntime: true},
+ }
+ for _, tc := range cases {
+ tc := tc
+ name := strings.TrimSuffix(tc.src, ".go")
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+
+ dir := newTempDir(t)
+ defer dir.RemoveAll(t)
+
+ outPath := dir.Join(name)
+ mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src)))
+
+ cmd := hangProneCmd(outPath)
+ if tc.needsRuntime {
+ config.skipIfRuntimeIncompatible(t)
+ }
+ mustRun(t, cmd)
+ })
+ }
+}
diff --git a/libgo/misc/cgo/testshared/shared_test.go b/libgo/misc/cgo/testshared/shared_test.go
index 9e682a2fb59..f1e8f0605b6 100644
--- a/libgo/misc/cgo/testshared/shared_test.go
+++ b/libgo/misc/cgo/testshared/shared_test.go
@@ -10,6 +10,7 @@ import (
"debug/elf"
"encoding/binary"
"errors"
+ "flag"
"fmt"
"go/build"
"io"
@@ -46,7 +47,7 @@ func run(t *testing.T, msg string, args ...string) {
func goCmd(t *testing.T, args ...string) {
newargs := []string{args[0], "-installsuffix=" + suffix}
if testing.Verbose() {
- newargs = append(newargs, "-v")
+ newargs = append(newargs, "-x")
}
newargs = append(newargs, args[1:]...)
c := exec.Command("go", newargs...)
@@ -57,6 +58,7 @@ func goCmd(t *testing.T, args ...string) {
c.Stdout = os.Stdout
c.Stderr = os.Stderr
err = c.Run()
+ output = []byte("(output above)")
} else {
output, err = c.CombinedOutput()
}
@@ -161,6 +163,8 @@ func testMain(m *testing.M) (int, error) {
}
func TestMain(m *testing.M) {
+ flag.Parse()
+
// Some of the tests install binaries into a custom GOPATH.
// That won't work if GOBIN is set.
os.Unsetenv("GOBIN")
@@ -461,13 +465,13 @@ func TestGopathShlib(t *testing.T) {
// that is not mapped into memory.
func testPkgListNote(t *testing.T, f *elf.File, note *note) {
if note.section.Flags != 0 {
- t.Errorf("package list section has flags %v", note.section.Flags)
+ t.Errorf("package list section has flags %v, want 0", note.section.Flags)
}
if isOffsetLoaded(f, note.section.Offset) {
t.Errorf("package list section contained in PT_LOAD segment")
}
if note.desc != "depBase\n" {
- t.Errorf("incorrect package list %q", note.desc)
+ t.Errorf("incorrect package list %q, want %q", note.desc, "depBase\n")
}
}
@@ -476,7 +480,7 @@ func testPkgListNote(t *testing.T, f *elf.File, note *note) {
// bytes into it.
func testABIHashNote(t *testing.T, f *elf.File, note *note) {
if note.section.Flags != elf.SHF_ALLOC {
- t.Errorf("abi hash section has flags %v", note.section.Flags)
+ t.Errorf("abi hash section has flags %v, want SHF_ALLOC", note.section.Flags)
}
if !isOffsetLoaded(f, note.section.Offset) {
t.Errorf("abihash section not contained in PT_LOAD segment")
@@ -497,13 +501,13 @@ func testABIHashNote(t *testing.T, f *elf.File, note *note) {
return
}
if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL {
- t.Errorf("%s has incorrect binding %v", hashbytes.Name, elf.ST_BIND(hashbytes.Info))
+ t.Errorf("%s has incorrect binding %v, want STB_LOCAL", hashbytes.Name, elf.ST_BIND(hashbytes.Info))
}
if f.Sections[hashbytes.Section] != note.section {
- t.Errorf("%s has incorrect section %v", hashbytes.Name, f.Sections[hashbytes.Section].Name)
+ t.Errorf("%s has incorrect section %v, want %s", hashbytes.Name, f.Sections[hashbytes.Section].Name, note.section.Name)
}
if hashbytes.Value-note.section.Addr != 16 {
- t.Errorf("%s has incorrect offset into section %d", hashbytes.Name, hashbytes.Value-note.section.Addr)
+ t.Errorf("%s has incorrect offset into section %d, want 16", hashbytes.Name, hashbytes.Value-note.section.Addr)
}
}
@@ -511,14 +515,14 @@ func testABIHashNote(t *testing.T, f *elf.File, note *note) {
// was linked against in an unmapped section.
func testDepsNote(t *testing.T, f *elf.File, note *note) {
if note.section.Flags != 0 {
- t.Errorf("package list section has flags %v", note.section.Flags)
+ t.Errorf("package list section has flags %v, want 0", note.section.Flags)
}
if isOffsetLoaded(f, note.section.Offset) {
t.Errorf("package list section contained in PT_LOAD segment")
}
// libdepBase.so just links against the lib containing the runtime.
if note.desc != soname {
- t.Errorf("incorrect dependency list %q", note.desc)
+ t.Errorf("incorrect dependency list %q, want %q", note.desc, soname)
}
}
@@ -556,7 +560,7 @@ func TestNotes(t *testing.T) {
abiHashNoteFound = true
case 3: // ELF_NOTE_GODEPS_TAG
if depsNoteFound {
- t.Error("multiple abi hash notes")
+ t.Error("multiple depedency list notes")
}
testDepsNote(t, f, note)
depsNoteFound = true
@@ -594,6 +598,7 @@ func TestThreeGopathShlibs(t *testing.T) {
// If gccgo is not available or not new enough call t.Skip. Otherwise,
// return a build.Context that is set up for gccgo.
func prepGccgo(t *testing.T) build.Context {
+ t.Skip("golang.org/issue/22472")
gccgoName := os.Getenv("GCCGO")
if gccgoName == "" {
gccgoName = "gccgo"
@@ -643,6 +648,8 @@ func TestGoPathShlibGccgo(t *testing.T) {
// library with gccgo, another GOPATH package that depends on the first and an
// executable that links the second library.
func TestTwoGopathShlibsGccgo(t *testing.T) {
+ t.Skip("golang.org/issue/22224")
+
gccgoContext := prepGccgo(t)
libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
@@ -696,18 +703,55 @@ func resetFileStamps() {
reset(gorootInstallDir)
}
-// touch makes path newer than the "old" time stamp used by resetFileStamps.
-func touch(path string) {
+// touch changes path and returns a function that changes it back.
+// It also sets the time of the file, so that we can see if it is rewritten.
+func touch(t *testing.T, path string) (cleanup func()) {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ old := make([]byte, len(data))
+ copy(old, data)
+ if bytes.HasPrefix(data, []byte("!<arch>\n")) {
+ // Change last digit of build ID.
+ // (Content ID in the new content-based build IDs.)
+ const marker = `build id "`
+ i := bytes.Index(data, []byte(marker))
+ if i < 0 {
+ t.Fatal("cannot find build id in archive")
+ }
+ j := bytes.IndexByte(data[i+len(marker):], '"')
+ if j < 0 {
+ t.Fatal("cannot find build id in archive")
+ }
+ i += len(marker) + j - 1
+ if data[i] == 'a' {
+ data[i] = 'b'
+ } else {
+ data[i] = 'a'
+ }
+ } else {
+ // assume it's a text file
+ data = append(data, '\n')
+ }
+ if err := ioutil.WriteFile(path, data, 0666); err != nil {
+ t.Fatal(err)
+ }
if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil {
- log.Fatalf("os.Chtimes failed: %v", err)
+ t.Fatal(err)
+ }
+ return func() {
+ if err := ioutil.WriteFile(path, old, 0666); err != nil {
+ t.Fatal(err)
+ }
}
}
// isNew returns if the path is newer than the time stamp used by touch.
-func isNew(path string) bool {
+func isNew(t *testing.T, path string) bool {
fi, err := os.Stat(path)
if err != nil {
- log.Fatalf("os.Stat failed: %v", err)
+ t.Fatal(err)
}
return fi.ModTime().After(stampTime)
}
@@ -715,14 +759,16 @@ func isNew(path string) bool {
// Fail unless path has been rebuilt (i.e. is newer than the time stamp used by
// isNew)
func AssertRebuilt(t *testing.T, msg, path string) {
- if !isNew(path) {
+ t.Helper()
+ if !isNew(t, path) {
t.Errorf("%s was not rebuilt (%s)", msg, path)
}
}
// Fail if path has been rebuilt (i.e. is newer than the time stamp used by isNew)
func AssertNotRebuilt(t *testing.T, msg, path string) {
- if isNew(path) {
+ t.Helper()
+ if isNew(t, path) {
t.Errorf("%s was rebuilt (%s)", msg, path)
}
}
@@ -732,41 +778,55 @@ func TestRebuilding(t *testing.T) {
goCmd(t, "install", "-linkshared", "exe")
// If the source is newer than both the .a file and the .so, both are rebuilt.
- resetFileStamps()
- touch("src/depBase/dep.go")
- goCmd(t, "install", "-linkshared", "exe")
- AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "depBase.a"))
- AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdepBase.so"))
+ t.Run("newsource", func(t *testing.T) {
+ resetFileStamps()
+ cleanup := touch(t, "src/depBase/dep.go")
+ defer func() {
+ cleanup()
+ goCmd(t, "install", "-linkshared", "exe")
+ }()
+ goCmd(t, "install", "-linkshared", "exe")
+ AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "depBase.a"))
+ AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdepBase.so"))
+ })
// If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
- resetFileStamps()
- touch(filepath.Join(gopathInstallDir, "depBase.a"))
- goCmd(t, "install", "-linkshared", "exe")
- AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "depBase.a"))
- AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdepBase.so"))
+ t.Run("newarchive", func(t *testing.T) {
+ resetFileStamps()
+ goCmd(t, "list", "-linkshared", "-f={{.ImportPath}} {{.Stale}} {{.StaleReason}} {{.Target}}", "depBase")
+ AssertNotRebuilt(t, "new .a file before build", filepath.Join(gopathInstallDir, "depBase.a"))
+ cleanup := touch(t, filepath.Join(gopathInstallDir, "depBase.a"))
+ defer func() {
+ cleanup()
+ goCmd(t, "install", "-v", "-linkshared", "exe")
+ }()
+ goCmd(t, "install", "-v", "-linkshared", "exe")
+ AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "depBase.a"))
+ AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdepBase.so"))
+ })
}
-func appendFile(path, content string) {
+func appendFile(t *testing.T, path, content string) {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0660)
if err != nil {
- log.Fatalf("os.OpenFile failed: %v", err)
+ t.Fatalf("os.OpenFile failed: %v", err)
}
defer func() {
err := f.Close()
if err != nil {
- log.Fatalf("f.Close failed: %v", err)
+ t.Fatalf("f.Close failed: %v", err)
}
}()
_, err = f.WriteString(content)
if err != nil {
- log.Fatalf("f.WriteString failed: %v", err)
+ t.Fatalf("f.WriteString failed: %v", err)
}
}
-func writeFile(path, content string) {
+func writeFile(t *testing.T, path, content string) {
err := ioutil.WriteFile(path, []byte(content), 0644)
if err != nil {
- log.Fatalf("ioutil.WriteFile failed: %v", err)
+ t.Fatalf("ioutil.WriteFile failed: %v", err)
}
}
@@ -780,7 +840,7 @@ func TestABIChecking(t *testing.T) {
// some senses but suffices for the narrow definition of ABI compatibility the
// toolchain uses today.
resetFileStamps()
- appendFile("src/depBase/dep.go", "func ABIBreak() {}\n")
+ appendFile(t, "src/depBase/dep.go", "func ABIBreak() {}\n")
goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
c := exec.Command("./bin/exe")
output, err := c.CombinedOutput()
@@ -811,7 +871,7 @@ func TestABIChecking(t *testing.T) {
// function) and rebuild libdepBase.so, exe still works, even if new function
// is in a file by itself.
resetFileStamps()
- writeFile("src/depBase/dep2.go", "package depBase\nfunc noABIBreak() {}\n")
+ writeFile(t, "src/depBase/dep2.go", "package depBase\nfunc noABIBreak() {}\n")
goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
run(t, "after non-ABI breaking change", "./bin/exe")
}
@@ -838,3 +898,12 @@ func TestInterface(t *testing.T) {
goCmd(t, "install", "-linkshared", "iface")
run(t, "running type/itab uniqueness tester", "./bin/iface")
}
+
+// Access a global variable from a library.
+func TestGlobal(t *testing.T) {
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "globallib")
+ goCmd(t, "install", "-linkshared", "global")
+ run(t, "global executable", "./bin/global")
+ AssertIsLinkedTo(t, "./bin/global", soname)
+ AssertHasRPath(t, "./bin/global", gorootInstallDir)
+}
diff --git a/libgo/misc/cgo/testshared/src/depBase/dep.go b/libgo/misc/cgo/testshared/src/depBase/dep.go
index 9f86710db01..569c210aa14 100644
--- a/libgo/misc/cgo/testshared/src/depBase/dep.go
+++ b/libgo/misc/cgo/testshared/src/depBase/dep.go
@@ -22,7 +22,7 @@ type Dep struct {
func (d *Dep) Method() int {
// This code below causes various go.itab.* symbols to be generated in
// the shared library. Similar code in ../exe/exe.go results in
- // exercising https://github.com/golang/go/issues/17594
+ // exercising https://golang.org/issues/17594
reflect.TypeOf(os.Stdout).Elem()
return 10
}
diff --git a/libgo/misc/cgo/testshared/src/exe/exe.go b/libgo/misc/cgo/testshared/src/exe/exe.go
index 84302a811f0..bd864d88ad8 100644
--- a/libgo/misc/cgo/testshared/src/exe/exe.go
+++ b/libgo/misc/cgo/testshared/src/exe/exe.go
@@ -25,7 +25,7 @@ func main() {
defer depBase.ImplementedInAsm()
// This code below causes various go.itab.* symbols to be generated in
// the executable. Similar code in ../depBase/dep.go results in
- // exercising https://github.com/golang/go/issues/17594
+ // exercising https://golang.org/issues/17594
reflect.TypeOf(os.Stdout).Elem()
runtime.GC()
depBase.V = depBase.F() + 1
diff --git a/libgo/misc/cgo/testshared/src/global/main.go b/libgo/misc/cgo/testshared/src/global/main.go
new file mode 100644
index 00000000000..94e7f247dee
--- /dev/null
+++ b/libgo/misc/cgo/testshared/src/global/main.go
@@ -0,0 +1,71 @@
+// 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.
+
+package main
+
+import (
+ "globallib"
+)
+
+//go:noinline
+func testLoop() {
+ for i, s := range globallib.Data {
+ if s != int64(i) {
+ panic("testLoop: mismatch")
+ }
+ }
+}
+
+//go:noinline
+func ptrData() *[1<<20 + 10]int64 {
+ return &globallib.Data
+}
+
+//go:noinline
+func testMediumOffset() {
+ for i, s := range globallib.Data[1<<16-2:] {
+ if s != int64(i)+1<<16-2 {
+ panic("testMediumOffset: index mismatch")
+ }
+ }
+
+ x := globallib.Data[1<<16-1]
+ if x != 1<<16-1 {
+ panic("testMediumOffset: direct mismatch")
+ }
+
+ y := &globallib.Data[1<<16-3]
+ if y != &ptrData()[1<<16-3] {
+ panic("testMediumOffset: address mismatch")
+ }
+}
+
+//go:noinline
+func testLargeOffset() {
+ for i, s := range globallib.Data[1<<20:] {
+ if s != int64(i)+1<<20 {
+ panic("testLargeOffset: index mismatch")
+ }
+ }
+
+ x := globallib.Data[1<<20+1]
+ if x != 1<<20+1 {
+ panic("testLargeOffset: direct mismatch")
+ }
+
+ y := &globallib.Data[1<<20+2]
+ if y != &ptrData()[1<<20+2] {
+ panic("testLargeOffset: address mismatch")
+ }
+}
+
+func main() {
+ testLoop()
+
+ // SSA rules commonly merge offsets into addresses. These
+ // tests access global data in different ways to try
+ // and exercise different SSA rules.
+ testMediumOffset()
+ testLargeOffset()
+}
diff --git a/libgo/misc/cgo/testshared/src/globallib/global.go b/libgo/misc/cgo/testshared/src/globallib/global.go
new file mode 100644
index 00000000000..b4372a2e9e2
--- /dev/null
+++ b/libgo/misc/cgo/testshared/src/globallib/global.go
@@ -0,0 +1,17 @@
+// 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.
+
+package globallib
+
+// Data is large enough to that offsets into it do not fit into
+// 16-bit or 20-bit immediates. Ideally we'd also try and overrun
+// 32-bit immediates, but that requires the test machine to have
+// too much memory.
+var Data [1<<20 + 10]int64
+
+func init() {
+ for i := range Data {
+ Data[i] = int64(i)
+ }
+}