aboutsummaryrefslogtreecommitdiff
path: root/libgo/misc/cgo
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-01-02 15:05:27 -0800
committerIan Lance Taylor <iant@golang.org>2020-01-21 23:53:22 -0800
commit5a8ea165926cb0737ab03bc48c18dc5198ab5305 (patch)
tree962dc3357c57f019f85658f99e2e753e30201c27 /libgo/misc/cgo
parent6ac6529e155c9baa0aaaed7aca06bd38ebda5b43 (diff)
downloadgcc-5a8ea165926cb0737ab03bc48c18dc5198ab5305.zip
gcc-5a8ea165926cb0737ab03bc48c18dc5198ab5305.tar.gz
gcc-5a8ea165926cb0737ab03bc48c18dc5198ab5305.tar.bz2
libgo: update to Go1.14beta1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/214297
Diffstat (limited to 'libgo/misc/cgo')
-rw-r--r--libgo/misc/cgo/fortran/test.bash2
-rw-r--r--libgo/misc/cgo/life/overlaydir_test.go11
-rw-r--r--libgo/misc/cgo/stdio/overlaydir_test.go11
-rw-r--r--libgo/misc/cgo/test/cgo_test.go6
-rw-r--r--libgo/misc/cgo/test/issue31891.c13
-rw-r--r--libgo/misc/cgo/test/issue8945.go16
-rw-r--r--libgo/misc/cgo/test/overlaydir_test.go11
-rw-r--r--libgo/misc/cgo/test/test.go102
-rw-r--r--libgo/misc/cgo/test/testdata/issue9026/issue9026.go6
-rw-r--r--libgo/misc/cgo/test/testx.go35
-rw-r--r--libgo/misc/cgo/testasan/main.go7
-rw-r--r--libgo/misc/cgo/testcarchive/carchive_test.go310
-rw-r--r--libgo/misc/cgo/testcarchive/overlaydir_test.go11
-rw-r--r--libgo/misc/cgo/testcarchive/testdata/libgo7/sink.go17
-rw-r--r--libgo/misc/cgo/testcarchive/testdata/main2.c37
-rw-r--r--libgo/misc/cgo/testcarchive/testdata/main3.c21
-rw-r--r--libgo/misc/cgo/testcarchive/testdata/main7.c18
-rw-r--r--libgo/misc/cgo/testcshared/cshared_test.go45
-rw-r--r--libgo/misc/cgo/testcshared/overlaydir_test.go11
-rw-r--r--libgo/misc/cgo/testgodefs/test.bash24
-rw-r--r--libgo/misc/cgo/testgodefs/testgodefs_test.go83
-rw-r--r--libgo/misc/cgo/testplugin/overlaydir_test.go11
-rw-r--r--libgo/misc/cgo/testplugin/plugin_test.go9
-rw-r--r--libgo/misc/cgo/testshared/overlaydir_test.go11
-rw-r--r--libgo/misc/cgo/testshared/shared_test.go200
-rw-r--r--libgo/misc/cgo/testsigfwd/main.go1
-rw-r--r--libgo/misc/cgo/testso/overlaydir_test.go11
-rw-r--r--libgo/misc/cgo/testsovar/overlaydir_test.go11
28 files changed, 755 insertions, 296 deletions
diff --git a/libgo/misc/cgo/fortran/test.bash b/libgo/misc/cgo/fortran/test.bash
index 9498da0..2b61730 100644
--- a/libgo/misc/cgo/fortran/test.bash
+++ b/libgo/misc/cgo/fortran/test.bash
@@ -28,7 +28,7 @@ case "$FC" in
;;
esac
-if ! $FC helloworld/helloworld.f90 -o main.exe >& /dev/null; then
+if ! $FC helloworld/helloworld.f90 -o /dev/null >& /dev/null; then
echo "skipping Fortran test: could not build helloworld.f90 with $FC"
exit 0
fi
diff --git a/libgo/misc/cgo/life/overlaydir_test.go b/libgo/misc/cgo/life/overlaydir_test.go
index f381ea6..034c836 100644
--- a/libgo/misc/cgo/life/overlaydir_test.go
+++ b/libgo/misc/cgo/life/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
diff --git a/libgo/misc/cgo/stdio/overlaydir_test.go b/libgo/misc/cgo/stdio/overlaydir_test.go
index 8a8dcdb..027ebf1 100644
--- a/libgo/misc/cgo/stdio/overlaydir_test.go
+++ b/libgo/misc/cgo/stdio/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
diff --git a/libgo/misc/cgo/test/cgo_test.go b/libgo/misc/cgo/test/cgo_test.go
index c66df2c..b745a44 100644
--- a/libgo/misc/cgo/test/cgo_test.go
+++ b/libgo/misc/cgo/test/cgo_test.go
@@ -58,6 +58,7 @@ func Test27660(t *testing.T) { test27660(t) }
func Test28896(t *testing.T) { test28896(t) }
func Test30065(t *testing.T) { test30065(t) }
func Test32579(t *testing.T) { test32579(t) }
+func Test31891(t *testing.T) { test31891(t) }
func TestAlign(t *testing.T) { testAlign(t) }
func TestAtol(t *testing.T) { testAtol(t) }
func TestBlocking(t *testing.T) { testBlocking(t) }
@@ -91,5 +92,6 @@ func TestThreadLock(t *testing.T) { testThreadLockFunc(t) }
func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) }
func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
-func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
-func BenchmarkGoString(b *testing.B) { benchGoString(b) }
+func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
+func BenchmarkGoString(b *testing.B) { benchGoString(b) }
+func BenchmarkCGoCallback(b *testing.B) { benchCallback(b) }
diff --git a/libgo/misc/cgo/test/issue31891.c b/libgo/misc/cgo/test/issue31891.c
new file mode 100644
index 0000000..67a0dda
--- /dev/null
+++ b/libgo/misc/cgo/test/issue31891.c
@@ -0,0 +1,13 @@
+// Copyright 2019 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 "_cgo_export.h"
+
+void callIssue31891() {
+ Issue31891A a;
+ useIssue31891A(&a);
+
+ Issue31891B b;
+ useIssue31891B(&b);
+}
diff --git a/libgo/misc/cgo/test/issue8945.go b/libgo/misc/cgo/test/issue8945.go
deleted file mode 100644
index 57a5b2d..0000000
--- a/libgo/misc/cgo/test/issue8945.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 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 gccgo
-
-package cgotest
-
-//typedef void (*PFunc)();
-//PFunc success_cb;
-import "C"
-
-//export Test
-func Test() {
- _ = C.success_cb
-}
diff --git a/libgo/misc/cgo/test/overlaydir_test.go b/libgo/misc/cgo/test/overlaydir_test.go
index 1b5c67d..f651979 100644
--- a/libgo/misc/cgo/test/overlaydir_test.go
+++ b/libgo/misc/cgo/test/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
diff --git a/libgo/misc/cgo/test/test.go b/libgo/misc/cgo/test/test.go
index 2d060bf..b014899 100644
--- a/libgo/misc/cgo/test/test.go
+++ b/libgo/misc/cgo/test/test.go
@@ -115,6 +115,44 @@ int add(int x, int y) {
return x+y;
};
+// Following mimicks vulkan complex definitions for benchmarking cgocheck overhead.
+
+typedef uint32_t VkFlags;
+typedef VkFlags VkDeviceQueueCreateFlags;
+typedef uint32_t VkStructureType;
+
+typedef struct VkDeviceQueueCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkDeviceQueueCreateFlags flags;
+ uint32_t queueFamilyIndex;
+ uint32_t queueCount;
+ const float* pQueuePriorities;
+} VkDeviceQueueCreateInfo;
+
+typedef struct VkPhysicalDeviceFeatures {
+ uint32_t bools[56];
+} VkPhysicalDeviceFeatures;
+
+typedef struct VkDeviceCreateInfo {
+ VkStructureType sType;
+ const void* pNext;
+ VkFlags flags;
+ uint32_t queueCreateInfoCount;
+ const VkDeviceQueueCreateInfo* pQueueCreateInfos;
+ uint32_t enabledLayerCount;
+ const char* const* ppEnabledLayerNames;
+ uint32_t enabledExtensionCount;
+ const char* const* ppEnabledExtensionNames;
+ const VkPhysicalDeviceFeatures* pEnabledFeatures;
+} VkDeviceCreateInfo;
+
+void handleComplexPointer(VkDeviceCreateInfo *a0) {}
+void handleComplexPointer8(
+ VkDeviceCreateInfo *a0, VkDeviceCreateInfo *a1, VkDeviceCreateInfo *a2, VkDeviceCreateInfo *a3,
+ VkDeviceCreateInfo *a4, VkDeviceCreateInfo *a5, VkDeviceCreateInfo *a6, VkDeviceCreateInfo *a7
+) {}
+
// complex alignment
struct {
@@ -524,6 +562,11 @@ void issue8811Execute() {
issue8811Init();
}
+// issue 8945
+
+typedef void (*PFunc8945)();
+PFunc8945 func8945;
+
// issue 9557
struct issue9557_t {
@@ -993,10 +1036,55 @@ type Context struct {
}
func benchCgoCall(b *testing.B) {
- const x = C.int(2)
- const y = C.int(3)
+ b.Run("add-int", func(b *testing.B) {
+ const x = C.int(2)
+ const y = C.int(3)
+
+ for i := 0; i < b.N; i++ {
+ C.add(x, y)
+ }
+ })
+
+ b.Run("one-pointer", func(b *testing.B) {
+ var a0 C.VkDeviceCreateInfo
+ for i := 0; i < b.N; i++ {
+ C.handleComplexPointer(&a0)
+ }
+ })
+ b.Run("eight-pointers", func(b *testing.B) {
+ var a0, a1, a2, a3, a4, a5, a6, a7 C.VkDeviceCreateInfo
+ for i := 0; i < b.N; i++ {
+ C.handleComplexPointer8(&a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7)
+ }
+ })
+ b.Run("eight-pointers-nil", func(b *testing.B) {
+ var a0, a1, a2, a3, a4, a5, a6, a7 *C.VkDeviceCreateInfo
+ for i := 0; i < b.N; i++ {
+ C.handleComplexPointer8(a0, a1, a2, a3, a4, a5, a6, a7)
+ }
+ })
+ b.Run("eight-pointers-array", func(b *testing.B) {
+ var a [8]C.VkDeviceCreateInfo
+ for i := 0; i < b.N; i++ {
+ C.handleComplexPointer8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7])
+ }
+ })
+ b.Run("eight-pointers-slice", func(b *testing.B) {
+ a := make([]C.VkDeviceCreateInfo, 8)
+ for i := 0; i < b.N; i++ {
+ C.handleComplexPointer8(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7])
+ }
+ })
+}
+
+// Benchmark measuring overhead from Go to C and back to Go (via a callback)
+func benchCallback(b *testing.B) {
+ var x = false
for i := 0; i < b.N; i++ {
- C.add(x, y)
+ nestedCall(func() { x = true })
+ }
+ if !x {
+ b.Fatal("nestedCall was not invoked")
}
}
@@ -1956,12 +2044,14 @@ func test27660(t *testing.T) {
locks[j].Lock()
ints[j]++
locks[j].Unlock()
- // Avoid making the loop unpreemptible
- // for gccgo.
- if i%0x1000000 == 0 {
+ // needed for gccgo, to avoid creation of an
+ // unpreemptible "fast path" in this loop. Choice
+ // of (1<<24) is somewhat arbitrary.
+ if i%(1<<24) == 0 {
runtime.Gosched()
}
i++
+
}
}()
time.Sleep(time.Millisecond)
diff --git a/libgo/misc/cgo/test/testdata/issue9026/issue9026.go b/libgo/misc/cgo/test/testdata/issue9026/issue9026.go
index 149c265..ff269ca 100644
--- a/libgo/misc/cgo/test/testdata/issue9026/issue9026.go
+++ b/libgo/misc/cgo/test/testdata/issue9026/issue9026.go
@@ -4,9 +4,9 @@ package issue9026
// per-package counter used to create fresh identifiers.
/*
-typedef struct {} git_merge_file_input;
+typedef struct { int i; } git_merge_file_input;
-typedef struct {} git_merge_file_options;
+typedef struct { int j; } git_merge_file_options;
void git_merge_file(
git_merge_file_input *in,
@@ -29,7 +29,7 @@ func Test(t *testing.T) {
// Brittle: the assertion may fail spuriously when the algorithm
// changes, but should remain stable otherwise.
got := fmt.Sprintf("%T %T", in, opts)
- want := "issue9026._Ctype_struct___0 *issue9026._Ctype_struct___0"
+ want := "issue9026._Ctype_struct___0 *issue9026._Ctype_struct___1"
if got != want {
t.Errorf("Non-deterministic type names: got %s, want %s", got, want)
}
diff --git a/libgo/misc/cgo/test/testx.go b/libgo/misc/cgo/test/testx.go
index 67def90..42979b5 100644
--- a/libgo/misc/cgo/test/testx.go
+++ b/libgo/misc/cgo/test/testx.go
@@ -102,12 +102,28 @@ static void issue7978c(uint32_t *sync) {
// #include'd twice. No runtime test; just make sure it compiles.
#include "issue8331.h"
+// issue 8945
+
+typedef void (*PFunc8945)();
+extern PFunc8945 func8945; // definition is in test.go
+
// issue 20910
void callMulti(void);
// issue 28772 part 2 - part 1 in issuex.go
#define issue28772Constant2 2
+
+// issue 31891
+typedef struct {
+ long obj;
+} Issue31891A;
+
+typedef struct {
+ long obj;
+} Issue31891B;
+
+void callIssue31891(void);
*/
import "C"
@@ -503,6 +519,13 @@ func test7978(t *testing.T) {
var issue8331Var C.issue8331
+// issue 8945
+
+//export Test8945
+func Test8945() {
+ _ = C.func8945
+}
+
// issue 20910
//export multi
@@ -517,3 +540,15 @@ func test20910(t *testing.T) {
// issue 28772 part 2
const issue28772Constant2 = C.issue28772Constant2
+
+// issue 31891
+
+//export useIssue31891A
+func useIssue31891A(c *C.Issue31891A) {}
+
+//export useIssue31891B
+func useIssue31891B(c *C.Issue31891B) {}
+
+func test31891(t *testing.T) {
+ C.callIssue31891()
+}
diff --git a/libgo/misc/cgo/testasan/main.go b/libgo/misc/cgo/testasan/main.go
index 1837c6c..bc77678 100644
--- a/libgo/misc/cgo/testasan/main.go
+++ b/libgo/misc/cgo/testasan/main.go
@@ -36,14 +36,21 @@ thread(void *p)
import "C"
import (
+ "fmt"
+ "os"
+ "path/filepath"
"time"
)
func main() {
+ start := time.Now()
+
// ensure that we can function normally
var v [][]byte
for i := 0; i < 1000; i++ {
time.Sleep(10 * time.Microsecond)
v = append(v, make([]byte, 64<<10))
}
+
+ fmt.Printf("ok\t%s\t%s\n", filepath.Base(os.Args[0]), time.Since(start).Round(time.Millisecond))
}
diff --git a/libgo/misc/cgo/testcarchive/carchive_test.go b/libgo/misc/cgo/testcarchive/carchive_test.go
index 7051670..98cd41a 100644
--- a/libgo/misc/cgo/testcarchive/carchive_test.go
+++ b/libgo/misc/cgo/testcarchive/carchive_test.go
@@ -36,7 +36,10 @@ var exeSuffix string
var GOOS, GOARCH, GOPATH string
var libgodir string
+var testWork bool // If true, preserve temporary directories.
+
func TestMain(m *testing.M) {
+ flag.BoolVar(&testWork, "testwork", false, "if true, log and preserve the test's temporary working directory")
flag.Parse()
if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
fmt.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
@@ -54,7 +57,11 @@ func testMain(m *testing.M) int {
if err != nil {
log.Panic(err)
}
- defer os.RemoveAll(GOPATH)
+ if testWork {
+ log.Println(GOPATH)
+ } else {
+ defer os.RemoveAll(GOPATH)
+ }
os.Setenv("GOPATH", GOPATH)
// Copy testdata into GOPATH/src/testarchive, along with a go.mod file
@@ -164,6 +171,38 @@ func cmdToRun(name string) []string {
return []string{executor, name}
}
+// genHeader writes a C header file for the C-exported declarations found in .go
+// source files in dir.
+//
+// TODO(golang.org/issue/35715): This should be simpler.
+func genHeader(t *testing.T, header, dir string) {
+ t.Helper()
+
+ // The 'cgo' command generates a number of additional artifacts,
+ // but we're only interested in the header.
+ // Shunt the rest of the outputs to a temporary directory.
+ objDir, err := ioutil.TempDir(GOPATH, "_obj")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(objDir)
+
+ files, err := filepath.Glob(filepath.Join(dir, "*.go"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ cmd := exec.Command("go", "tool", "cgo",
+ "-objdir", objDir,
+ "-exportheader", header)
+ cmd.Args = append(cmd.Args, files...)
+ t.Log(cmd.Args)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+}
+
func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
t.Helper()
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
@@ -172,10 +211,12 @@ func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
t.Logf("%s", out)
t.Fatal(err)
}
- defer func() {
- os.Remove(libgoa)
- os.Remove(libgoh)
- }()
+ if !testWork {
+ defer func() {
+ os.Remove(libgoa)
+ os.Remove(libgoh)
+ }()
+ }
ccArgs := append(cc, "-o", exe, "main.c")
if GOOS == "windows" {
@@ -191,7 +232,9 @@ func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
t.Logf("%s", out)
t.Fatal(err)
}
- defer os.Remove(exe)
+ if !testWork {
+ defer os.Remove(exe)
+ }
binArgs := append(cmdToRun(exe), "arg1", "arg2")
cmd = exec.Command(binArgs[0], binArgs[1:]...)
@@ -227,17 +270,27 @@ func checkLineComments(t *testing.T, hdrname string) {
}
func TestInstall(t *testing.T) {
- defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ if !testWork {
+ defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }
libgoa := "libgo.a"
if runtime.Compiler == "gccgo" {
libgoa = "liblibgo.a"
}
+ // Generate the p.h header file.
+ //
+ // 'go install -i -buildmode=c-archive ./libgo' would do that too, but that
+ // would also attempt to install transitive standard-library dependencies to
+ // GOROOT, and we cannot assume that GOROOT is writable. (A non-root user may
+ // be running this test in a GOROOT owned by root.)
+ genHeader(t, "p.h", "./p")
+
testInstall(t, "./testp1"+exeSuffix,
filepath.Join(libgodir, libgoa),
filepath.Join(libgodir, "libgo.h"),
- "go", "install", "-i", "-buildmode=c-archive", "./libgo")
+ "go", "install", "-buildmode=c-archive", "./libgo")
// Test building libgo other than installing it.
// Header files are now present.
@@ -259,12 +312,14 @@ func TestEarlySignalHandler(t *testing.T) {
t.Skip("skipping signal test on Windows")
}
- defer func() {
- os.Remove("libgo2.a")
- os.Remove("libgo2.h")
- os.Remove("testp")
- os.RemoveAll(filepath.Join(GOPATH, "pkg"))
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("libgo2.a")
+ os.Remove("libgo2.h")
+ os.Remove("testp")
+ os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }()
+ }
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
if out, err := cmd.CombinedOutput(); err != nil {
@@ -282,7 +337,13 @@ func TestEarlySignalHandler(t *testing.T) {
t.Fatal(err)
}
- if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
+ darwin := "0"
+ if runtime.GOOS == "darwin" {
+ darwin = "1"
+ }
+ cmd = exec.Command(bin[0], append(bin[1:], darwin)...)
+
+ if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
@@ -291,12 +352,14 @@ func TestEarlySignalHandler(t *testing.T) {
func TestSignalForwarding(t *testing.T) {
checkSignalForwardingTest(t)
- defer func() {
- os.Remove("libgo2.a")
- os.Remove("libgo2.h")
- os.Remove("testp")
- os.RemoveAll(filepath.Join(GOPATH, "pkg"))
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("libgo2.a")
+ os.Remove("libgo2.h")
+ os.Remove("testp")
+ os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }()
+ }
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
if out, err := cmd.CombinedOutput(); err != nil {
@@ -320,12 +383,15 @@ func TestSignalForwarding(t *testing.T) {
t.Logf("%s", out)
expectSignal(t, err, syscall.SIGSEGV)
- // Test SIGPIPE forwarding
- cmd = exec.Command(bin[0], append(bin[1:], "3")...)
+ // SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
+ if runtime.GOOS != "darwin" {
+ // Test SIGPIPE forwarding
+ cmd = exec.Command(bin[0], append(bin[1:], "3")...)
- out, err = cmd.CombinedOutput()
- t.Logf("%s", out)
- expectSignal(t, err, syscall.SIGPIPE)
+ out, err = cmd.CombinedOutput()
+ t.Logf("%s", out)
+ expectSignal(t, err, syscall.SIGPIPE)
+ }
}
func TestSignalForwardingExternal(t *testing.T) {
@@ -336,12 +402,14 @@ func TestSignalForwardingExternal(t *testing.T) {
}
checkSignalForwardingTest(t)
- defer func() {
- os.Remove("libgo2.a")
- os.Remove("libgo2.h")
- os.Remove("testp")
- os.RemoveAll(filepath.Join(GOPATH, "pkg"))
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("libgo2.a")
+ os.Remove("libgo2.h")
+ os.Remove("testp")
+ os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }()
+ }
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
if out, err := cmd.CombinedOutput(); err != nil {
@@ -451,12 +519,14 @@ func TestOsSignal(t *testing.T) {
t.Skip("skipping signal test on Windows")
}
- defer func() {
- os.Remove("libgo3.a")
- os.Remove("libgo3.h")
- os.Remove("testp")
- os.RemoveAll(filepath.Join(GOPATH, "pkg"))
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("libgo3.a")
+ os.Remove("libgo3.h")
+ os.Remove("testp")
+ os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }()
+ }
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "./libgo3")
if out, err := cmd.CombinedOutput(); err != nil {
@@ -486,12 +556,14 @@ func TestSigaltstack(t *testing.T) {
t.Skip("skipping signal test on Windows")
}
- defer func() {
- os.Remove("libgo4.a")
- os.Remove("libgo4.h")
- os.Remove("testp")
- os.RemoveAll(filepath.Join(GOPATH, "pkg"))
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("libgo4.a")
+ os.Remove("libgo4.h")
+ os.Remove("testp")
+ os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }()
+ }
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "./libgo4")
if out, err := cmd.CombinedOutput(); err != nil {
@@ -535,13 +607,15 @@ func TestExtar(t *testing.T) {
t.Skip("shell scripts are not executable on iOS hosts")
}
- defer func() {
- os.Remove("libgo4.a")
- os.Remove("libgo4.h")
- os.Remove("testar")
- os.Remove("testar.ran")
- os.RemoveAll(filepath.Join(GOPATH, "pkg"))
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("libgo4.a")
+ os.Remove("libgo4.h")
+ os.Remove("testar")
+ os.Remove("testar.ran")
+ os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }()
+ }
os.Remove("testar")
dir, err := os.Getwd()
@@ -575,12 +649,22 @@ func TestPIE(t *testing.T) {
t.Skipf("skipping PIE test on %s", GOOS)
}
- defer func() {
- os.Remove("testp" + exeSuffix)
- os.RemoveAll(filepath.Join(GOPATH, "pkg"))
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("testp" + exeSuffix)
+ os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }()
+ }
+
+ // Generate the p.h header file.
+ //
+ // 'go install -i -buildmode=c-archive ./libgo' would do that too, but that
+ // would also attempt to install transitive standard-library dependencies to
+ // GOROOT, and we cannot assume that GOROOT is writable. (A non-root user may
+ // be running this test in a GOROOT owned by root.)
+ genHeader(t, "p.h", "./p")
- cmd := exec.Command("go", "install", "-i", "-buildmode=c-archive", "./libgo")
+ cmd := exec.Command("go", "install", "-buildmode=c-archive", "./libgo")
if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
@@ -660,11 +744,13 @@ func TestSIGPROF(t *testing.T) {
t.Parallel()
- defer func() {
- os.Remove("testp6" + exeSuffix)
- os.Remove("libgo6.a")
- os.Remove("libgo6.h")
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("testp6" + exeSuffix)
+ os.Remove("libgo6.a")
+ os.Remove("libgo6.h")
+ }()
+ }
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "./libgo6")
if out, err := cmd.CombinedOutput(); err != nil {
@@ -700,10 +786,12 @@ func TestCompileWithoutShared(t *testing.T) {
// For simplicity, reuse the signal forwarding test.
checkSignalForwardingTest(t)
- defer func() {
- os.Remove("libgo2.a")
- os.Remove("libgo2.h")
- }()
+ if !testWork {
+ defer func() {
+ os.Remove("libgo2.a")
+ os.Remove("libgo2.h")
+ }()
+ }
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "./libgo2")
t.Log(cmd.Args)
@@ -742,23 +830,35 @@ func TestCompileWithoutShared(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- defer os.Remove(exe)
+ if !testWork {
+ defer os.Remove(exe)
+ }
- binArgs := append(cmdToRun(exe), "3")
+ binArgs := append(cmdToRun(exe), "1")
t.Log(binArgs)
out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
t.Logf("%s", out)
- expectSignal(t, err, syscall.SIGPIPE)
+ expectSignal(t, err, syscall.SIGSEGV)
+
+ // SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
+ if runtime.GOOS != "darwin" {
+ binArgs := append(cmdToRun(exe), "3")
+ t.Log(binArgs)
+ out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
+ t.Logf("%s", out)
+ expectSignal(t, err, syscall.SIGPIPE)
+ }
}
-// Test that installing a second time recreates the header files.
+// Test that installing a second time recreates the header file.
func TestCachedInstall(t *testing.T) {
- defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ if !testWork {
+ defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
+ }
- h1 := filepath.Join(libgodir, "libgo.h")
- h2 := filepath.Join(libgodir, "p.h")
+ h := filepath.Join(libgodir, "libgo.h")
- buildcmd := []string{"go", "install", "-i", "-buildmode=c-archive", "./libgo"}
+ buildcmd := []string{"go", "install", "-buildmode=c-archive", "./libgo"}
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
t.Log(buildcmd)
@@ -767,17 +867,11 @@ func TestCachedInstall(t *testing.T) {
t.Fatal(err)
}
- if _, err := os.Stat(h1); err != nil {
+ if _, err := os.Stat(h); err != nil {
t.Errorf("libgo.h not installed: %v", err)
}
- if _, err := os.Stat(h2); err != nil {
- t.Errorf("p.h not installed: %v", err)
- }
- if err := os.Remove(h1); err != nil {
- t.Fatal(err)
- }
- if err := os.Remove(h2); err != nil {
+ if err := os.Remove(h); err != nil {
t.Fatal(err)
}
@@ -788,10 +882,58 @@ func TestCachedInstall(t *testing.T) {
t.Fatal(err)
}
- if _, err := os.Stat(h1); err != nil {
+ if _, err := os.Stat(h); err != nil {
t.Errorf("libgo.h not installed in second run: %v", err)
}
- if _, err := os.Stat(h2); err != nil {
- t.Errorf("p.h not installed in second run: %v", err)
+}
+
+// Issue 35294.
+func TestManyCalls(t *testing.T) {
+ t.Parallel()
+
+ if !testWork {
+ defer func() {
+ os.Remove("testp7" + exeSuffix)
+ os.Remove("libgo7.a")
+ os.Remove("libgo7.h")
+ }()
+ }
+
+ cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo7.a", "./libgo7")
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+ checkLineComments(t, "libgo7.h")
+
+ ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
+ if runtime.Compiler == "gccgo" {
+ ccArgs = append(ccArgs, "-lgo")
+ }
+ if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ argv := cmdToRun("./testp7")
+ cmd = exec.Command(argv[0], argv[1:]...)
+ var sb strings.Builder
+ cmd.Stdout = &sb
+ cmd.Stderr = &sb
+ if err := cmd.Start(); err != nil {
+ t.Fatal(err)
+ }
+
+ timer := time.AfterFunc(time.Minute,
+ func() {
+ t.Error("test program timed out")
+ cmd.Process.Kill()
+ },
+ )
+ defer timer.Stop()
+
+ if err := cmd.Wait(); err != nil {
+ t.Log(sb.String())
+ t.Error(err)
}
}
diff --git a/libgo/misc/cgo/testcarchive/overlaydir_test.go b/libgo/misc/cgo/testcarchive/overlaydir_test.go
index 68878e4..67974c5 100644
--- a/libgo/misc/cgo/testcarchive/overlaydir_test.go
+++ b/libgo/misc/cgo/testcarchive/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
diff --git a/libgo/misc/cgo/testcarchive/testdata/libgo7/sink.go b/libgo/misc/cgo/testcarchive/testdata/libgo7/sink.go
new file mode 100644
index 0000000..d61638b
--- /dev/null
+++ b/libgo/misc/cgo/testcarchive/testdata/libgo7/sink.go
@@ -0,0 +1,17 @@
+// Copyright 2019 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 "C"
+
+var sink []byte
+
+//export GoFunction7
+func GoFunction7() {
+ sink = make([]byte, 4096)
+}
+
+func main() {
+}
diff --git a/libgo/misc/cgo/testcarchive/testdata/main2.c b/libgo/misc/cgo/testcarchive/testdata/main2.c
index 769cd49..da35673 100644
--- a/libgo/misc/cgo/testcarchive/testdata/main2.c
+++ b/libgo/misc/cgo/testcarchive/testdata/main2.c
@@ -123,8 +123,12 @@ int main(int argc, char** argv) {
sigset_t mask;
int i;
struct timespec ts;
+ int darwin;
+
+ darwin = atoi(argv[1]);
+
+ verbose = argc > 2;
- verbose = argc > 1;
setvbuf(stdout, NULL, _IONBF, 0);
// Call setsid so that we can use kill(0, SIGIO) below.
@@ -186,22 +190,25 @@ int main(int argc, char** argv) {
printf("provoking SIGPIPE\n");
}
- GoRaiseSIGPIPE();
+ // SIGPIPE is never forwarded on Darwin, see golang.org/issue/33384.
+ if (!darwin) {
+ GoRaiseSIGPIPE();
- if (verbose) {
- printf("waiting for sigpipeSeen\n");
- }
+ if (verbose) {
+ printf("waiting for sigpipeSeen\n");
+ }
- // Wait until the signal has been delivered.
- i = 0;
- while (!sigpipeSeen) {
- ts.tv_sec = 0;
- ts.tv_nsec = 1000000;
- nanosleep(&ts, NULL);
- i++;
- if (i > 5000) {
- fprintf(stderr, "looping too long waiting for SIGPIPE\n");
- exit(EXIT_FAILURE);
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (!sigpipeSeen) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ i++;
+ if (i > 5000) {
+ fprintf(stderr, "looping too long waiting for SIGPIPE\n");
+ exit(EXIT_FAILURE);
+ }
}
}
diff --git a/libgo/misc/cgo/testcarchive/testdata/main3.c b/libgo/misc/cgo/testcarchive/testdata/main3.c
index 60a16cf..4d11d9c 100644
--- a/libgo/misc/cgo/testcarchive/testdata/main3.c
+++ b/libgo/misc/cgo/testcarchive/testdata/main3.c
@@ -12,6 +12,7 @@
#include <time.h>
#include <sched.h>
#include <unistd.h>
+#include <pthread.h>
#include "libgo3.h"
@@ -51,11 +52,18 @@ static void init() {
}
}
+static void *provokeSIGPIPE(void *arg) {
+ ProvokeSIGPIPE();
+ return NULL;
+}
+
int main(int argc, char** argv) {
int verbose;
struct sigaction sa;
int i;
struct timespec ts;
+ int res;
+ pthread_t tid;
verbose = argc > 2;
setvbuf(stdout, NULL, _IONBF, 0);
@@ -68,6 +76,19 @@ int main(int argc, char** argv) {
// a non-default SIGPIPE handler before the runtime initializes.
ProvokeSIGPIPE();
+ // Test that SIGPIPE on a non-main thread is also handled by Go.
+ res = pthread_create(&tid, NULL, provokeSIGPIPE, NULL);
+ if (res != 0) {
+ fprintf(stderr, "pthread_create: %s\n", strerror(res));
+ exit(EXIT_FAILURE);
+ }
+
+ res = pthread_join(tid, NULL);
+ if (res != 0) {
+ fprintf(stderr, "pthread_join: %s\n", strerror(res));
+ exit(EXIT_FAILURE);
+ }
+
if (verbose) {
printf("calling sigaction\n");
}
diff --git a/libgo/misc/cgo/testcarchive/testdata/main7.c b/libgo/misc/cgo/testcarchive/testdata/main7.c
new file mode 100644
index 0000000..2c6d98d
--- /dev/null
+++ b/libgo/misc/cgo/testcarchive/testdata/main7.c
@@ -0,0 +1,18 @@
+// Copyright 2019 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.
+
+// Test that lots of calls don't deadlock.
+
+#include <stdio.h>
+
+#include "libgo7.h"
+
+int main() {
+ int i;
+
+ for (i = 0; i < 100000; i++) {
+ GoFunction7();
+ }
+ return 0;
+}
diff --git a/libgo/misc/cgo/testcshared/cshared_test.go b/libgo/misc/cgo/testcshared/cshared_test.go
index daef3a9..cb95153 100644
--- a/libgo/misc/cgo/testcshared/cshared_test.go
+++ b/libgo/misc/cgo/testcshared/cshared_test.go
@@ -103,7 +103,7 @@ func testMain(m *testing.M) int {
// TODO(crawshaw): can we do better?
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
case "android":
- cc = append(cc, "-pie", "-fuse-ld=gold")
+ cc = append(cc, "-pie")
}
libgodir := GOOS + "_" + GOARCH
switch GOOS {
@@ -130,8 +130,6 @@ func testMain(m *testing.M) int {
defer os.RemoveAll(GOPATH)
os.Setenv("GOPATH", GOPATH)
- // Copy testdata into GOPATH/src/testarchive, along with a go.mod file
- // declaring the same path.
modRoot := filepath.Join(GOPATH, "src", "testcshared")
if err := overlayDir(modRoot, "testdata"); err != nil {
log.Panic(err)
@@ -257,14 +255,38 @@ func runCC(t *testing.T, args ...string) string {
}
func createHeaders() error {
- args := []string{"go", "install", "-i", "-buildmode=c-shared",
- "-installsuffix", "testcshared", "./libgo"}
+ // The 'cgo' command generates a number of additional artifacts,
+ // but we're only interested in the header.
+ // Shunt the rest of the outputs to a temporary directory.
+ objDir, err := ioutil.TempDir("", "testcshared_obj")
+ if err != nil {
+ return err
+ }
+ defer os.RemoveAll(objDir)
+
+ // Generate a C header file for p, which is a non-main dependency
+ // of main package libgo.
+ //
+ // TODO(golang.org/issue/35715): This should be simpler.
+ args := []string{"go", "tool", "cgo",
+ "-objdir", objDir,
+ "-exportheader", "p.h",
+ filepath.Join(".", "p", "p.go")}
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
}
+ // Generate a C header file for libgo itself.
+ args = []string{"go", "install", "-buildmode=c-shared",
+ "-installsuffix", "testcshared", "./libgo"}
+ cmd = exec.Command(args[0], args[1:]...)
+ 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,
@@ -522,7 +544,7 @@ func TestPIE(t *testing.T) {
}
}
-// Test that installing a second time recreates the header files.
+// Test that installing a second time recreates the header file.
func TestCachedInstall(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "cshared")
if err != nil {
@@ -536,7 +558,7 @@ func TestCachedInstall(t *testing.T) {
env := append(os.Environ(), "GOPATH="+tmpdir, "GOBIN="+filepath.Join(tmpdir, "bin"))
- buildcmd := []string{"go", "install", "-x", "-i", "-buildmode=c-shared", "-installsuffix", "testcshared", "./libgo"}
+ buildcmd := []string{"go", "install", "-x", "-buildmode=c-shared", "-installsuffix", "testcshared", "./libgo"}
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
cmd.Dir = filepath.Join(tmpdir, "src", "testcshared")
@@ -577,16 +599,10 @@ func TestCachedInstall(t *testing.T) {
if libgoh == "" {
t.Fatal("libgo.h not installed")
}
- if ph == "" {
- t.Fatal("p.h not installed")
- }
if err := os.Remove(libgoh); err != nil {
t.Fatal(err)
}
- if err := os.Remove(ph); err != nil {
- t.Fatal(err)
- }
cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
cmd.Dir = filepath.Join(tmpdir, "src", "testcshared")
@@ -601,9 +617,6 @@ func TestCachedInstall(t *testing.T) {
if _, err := os.Stat(libgoh); err != nil {
t.Errorf("libgo.h not installed in second run: %v", err)
}
- if _, err := os.Stat(ph); err != nil {
- t.Errorf("p.h not installed in second run: %v", err)
- }
}
// copyFile copies src to dst.
diff --git a/libgo/misc/cgo/testcshared/overlaydir_test.go b/libgo/misc/cgo/testcshared/overlaydir_test.go
index 1eaabf6..85d6b44 100644
--- a/libgo/misc/cgo/testcshared/overlaydir_test.go
+++ b/libgo/misc/cgo/testcshared/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
diff --git a/libgo/misc/cgo/testgodefs/test.bash b/libgo/misc/cgo/testgodefs/test.bash
deleted file mode 100644
index e4ce2ee..0000000
--- a/libgo/misc/cgo/testgodefs/test.bash
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2014 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.
-
-# We are testing cgo -godefs, which translates Go files that use
-# import "C" into Go files with Go definitions of types defined in the
-# import "C" block. Add more tests here.
-FILE_PREFIXES="anonunion issue8478 fieldtypedef"
-
-cd testdata
-
-RM=
-for FP in $FILE_PREFIXES
-do
- go tool cgo -godefs -srcdir . ${FP}.go > ${FP}_defs.go
- RM="${RM} ${FP}_defs.go"
-done
-
-go build -o testgodefs . && ./testgodefs
-EXIT=$?
-rm -rf _obj testgodefs ${RM}
-exit $EXIT
diff --git a/libgo/misc/cgo/testgodefs/testgodefs_test.go b/libgo/misc/cgo/testgodefs/testgodefs_test.go
new file mode 100644
index 0000000..c02c3ff
--- /dev/null
+++ b/libgo/misc/cgo/testgodefs/testgodefs_test.go
@@ -0,0 +1,83 @@
+// Copyright 2019 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 testgodefs
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+// We are testing cgo -godefs, which translates Go files that use
+// import "C" into Go files with Go definitions of types defined in the
+// import "C" block. Add more tests here.
+var filePrefixes = []string{
+ "anonunion",
+ "issue8478",
+ "fieldtypedef",
+}
+
+func TestGoDefs(t *testing.T) {
+ testdata, err := filepath.Abs("testdata")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ gopath, err := ioutil.TempDir("", "testgodefs-gopath")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(gopath)
+
+ dir := filepath.Join(gopath, "src", "testgodefs")
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ t.Fatal(err)
+ }
+
+ for _, fp := range filePrefixes {
+ cmd := exec.Command("go", "tool", "cgo",
+ "-godefs",
+ "-srcdir", testdata,
+ "-objdir", dir,
+ fp+".go")
+ cmd.Stderr = new(bytes.Buffer)
+
+ out, err := cmd.Output()
+ if err != nil {
+ t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
+ }
+
+ if err := ioutil.WriteFile(filepath.Join(dir, fp+"_defs.go"), out, 0644); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ main, err := ioutil.ReadFile(filepath.Join("testdata", "main.go"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(dir, "main.go"), main, 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module testgodefs\ngo 1.14\n"), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ // Use 'go run' to build and run the resulting binary in a single step,
+ // instead of invoking 'go build' and the resulting binary separately, so that
+ // this test can pass on mobile builders, which do not copy artifacts back
+ // from remote invocations.
+ cmd := exec.Command("go", "run", ".")
+ cmd.Env = append(os.Environ(), "GOPATH="+gopath)
+ cmd.Dir = dir
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("%s [%s]: %v\n%s", strings.Join(cmd.Args, " "), dir, err, out)
+ }
+}
diff --git a/libgo/misc/cgo/testplugin/overlaydir_test.go b/libgo/misc/cgo/testplugin/overlaydir_test.go
index b68436a..e2c32d8 100644
--- a/libgo/misc/cgo/testplugin/overlaydir_test.go
+++ b/libgo/misc/cgo/testplugin/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
diff --git a/libgo/misc/cgo/testplugin/plugin_test.go b/libgo/misc/cgo/testplugin/plugin_test.go
index 7e2b6eb..ab98f61 100644
--- a/libgo/misc/cgo/testplugin/plugin_test.go
+++ b/libgo/misc/cgo/testplugin/plugin_test.go
@@ -14,7 +14,6 @@ import (
"os"
"os/exec"
"path/filepath"
- "runtime"
"strings"
"testing"
"time"
@@ -71,7 +70,7 @@ func testMain(m *testing.M) int {
os.Setenv("LD_LIBRARY_PATH", modRoot)
- goCmd(nil, "build", "-i", "-buildmode=plugin", "./plugin1")
+ goCmd(nil, "build", "-buildmode=plugin", "./plugin1")
goCmd(nil, "build", "-buildmode=plugin", "./plugin2")
so, err := ioutil.ReadFile("plugin2.so")
if err != nil {
@@ -114,11 +113,7 @@ func run(t *testing.T, bin string, args ...string) string {
func TestDWARFSections(t *testing.T) {
// test that DWARF sections are emitted for plugins and programs importing "plugin"
- if runtime.GOOS != "darwin" {
- // On macOS, for some reason, the linker doesn't add debug sections to .so,
- // see issue #27502.
- goCmd(t, "run", "./checkdwarf/main.go", "plugin2.so", "plugin2.UnexportedNameReuse")
- }
+ goCmd(t, "run", "./checkdwarf/main.go", "plugin2.so", "plugin2.UnexportedNameReuse")
goCmd(t, "run", "./checkdwarf/main.go", "./host.exe", "main.main")
}
diff --git a/libgo/misc/cgo/testshared/overlaydir_test.go b/libgo/misc/cgo/testshared/overlaydir_test.go
index 68be056..eb587a2 100644
--- a/libgo/misc/cgo/testshared/overlaydir_test.go
+++ b/libgo/misc/cgo/testshared/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
diff --git a/libgo/misc/cgo/testshared/shared_test.go b/libgo/misc/cgo/testshared/shared_test.go
index 9d16338..b9ef6da 100644
--- a/libgo/misc/cgo/testshared/shared_test.go
+++ b/libgo/misc/cgo/testshared/shared_test.go
@@ -9,31 +9,33 @@ import (
"bytes"
"debug/elf"
"encoding/binary"
- "errors"
"flag"
"fmt"
"go/build"
"io"
"io/ioutil"
"log"
- "math/rand"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
+ "sort"
"strings"
"testing"
"time"
)
-var gopathInstallDir, gorootInstallDir, suffix string
+var gopathInstallDir, gorootInstallDir string
// This is the smallest set of packages we can link into a shared
// library (runtime/cgo is built implicitly).
var minpkgs = []string{"runtime", "sync/atomic"}
var soname = "libruntime,sync-atomic.so"
+var testX = flag.Bool("testx", false, "if true, pass -x to 'go' subcommands invoked by the test")
+var testWork = flag.Bool("testwork", false, "if true, log and do not delete the temporary working directory")
+
// run runs a command and calls t.Errorf if it fails.
func run(t *testing.T, msg string, args ...string) {
c := exec.Command(args[0], args[1:]...)
@@ -45,31 +47,34 @@ func run(t *testing.T, msg string, args ...string) {
// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls
// t.Fatalf if the command fails.
func goCmd(t *testing.T, args ...string) string {
- newargs := []string{args[0], "-installsuffix=" + suffix}
- if testing.Verbose() {
+ newargs := []string{args[0]}
+ if *testX {
newargs = append(newargs, "-x")
}
newargs = append(newargs, args[1:]...)
c := exec.Command("go", newargs...)
-
stderr := new(strings.Builder)
- var output []byte
- var err error
- if testing.Verbose() {
- fmt.Printf("+ go %s\n", strings.Join(args, " "))
+ c.Stderr = stderr
+
+ if testing.Verbose() && t == nil {
+ fmt.Fprintf(os.Stderr, "+ go %s\n", strings.Join(args, " "))
c.Stderr = os.Stderr
- stderr.WriteString("(output above)")
- } else {
- c.Stderr = stderr
}
- output, err = c.Output()
+ output, err := c.Output()
if err != nil {
if t != nil {
t.Helper()
t.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, stderr)
} else {
- log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, stderr)
+ // Panic instead of using log.Fatalf so that deferred cleanup may run in testMain.
+ log.Panicf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, stderr)
+ }
+ }
+ if testing.Verbose() && t != nil {
+ t.Logf("go %s", strings.Join(args, " "))
+ if stderr.Len() > 0 {
+ t.Logf("%s", stderr)
}
}
return string(bytes.TrimSpace(output))
@@ -77,73 +82,61 @@ func goCmd(t *testing.T, args ...string) string {
// TestMain calls testMain so that the latter can use defer (TestMain exits with os.Exit).
func testMain(m *testing.M) (int, error) {
- // Because go install -buildmode=shared $standard_library_package always
- // installs into $GOROOT, here are some gymnastics to come up with a unique
- // installsuffix to use in this test that we can clean up afterwards.
- myContext := build.Default
- runtimeP, err := myContext.Import("runtime", ".", build.ImportComment)
+ workDir, err := ioutil.TempDir("", "shared_test")
if err != nil {
- return 0, fmt.Errorf("import failed: %v", err)
- }
- for i := 0; i < 10000; i++ {
- try := fmt.Sprintf("%s_%d_dynlink", runtimeP.PkgTargetRoot, rand.Int63())
- err = os.Mkdir(try, 0700)
- if os.IsExist(err) {
- continue
- }
- if err == nil {
- gorootInstallDir = try
- }
- break
- }
- if err != nil {
- return 0, fmt.Errorf("can't create temporary directory: %v", err)
+ return 0, err
}
- if gorootInstallDir == "" {
- return 0, errors.New("could not create temporary directory after 10000 tries")
+ if *testWork || testing.Verbose() {
+ fmt.Printf("+ mkdir -p %s\n", workDir)
}
- if testing.Verbose() {
- fmt.Printf("+ mkdir -p %s\n", gorootInstallDir)
+ if !*testWork {
+ defer os.RemoveAll(workDir)
}
- defer os.RemoveAll(gorootInstallDir)
// Some tests need to edit the source in GOPATH, so copy this directory to a
// temporary directory and chdir to that.
- gopath, err := ioutil.TempDir("", "testshared")
+ gopath := filepath.Join(workDir, "gopath")
+ modRoot, err := cloneTestdataModule(gopath)
if err != nil {
- return 0, fmt.Errorf("TempDir failed: %v", err)
- }
- if testing.Verbose() {
- fmt.Printf("+ mkdir -p %s\n", gopath)
- }
- defer os.RemoveAll(gopath)
-
- modRoot := filepath.Join(gopath, "src", "testshared")
- if err := overlayDir(modRoot, "testdata"); err != nil {
return 0, err
}
if testing.Verbose() {
+ fmt.Printf("+ export GOPATH=%s\n", gopath)
fmt.Printf("+ cd %s\n", modRoot)
}
+ os.Setenv("GOPATH", gopath)
os.Chdir(modRoot)
os.Setenv("PWD", modRoot)
- if err := ioutil.WriteFile("go.mod", []byte("module testshared\n"), 0666); err != nil {
+
+ // The test also needs to install libraries into GOROOT/pkg, so copy the
+ // subset of GOROOT that we need.
+ //
+ // TODO(golang.org/issue/28553): Rework -buildmode=shared so that it does not
+ // need to write to GOROOT.
+ goroot := filepath.Join(workDir, "goroot")
+ if err := cloneGOROOTDeps(goroot); err != nil {
return 0, err
}
-
- os.Setenv("GOPATH", gopath)
if testing.Verbose() {
- fmt.Printf("+ export GOPATH=%s\n", gopath)
+ fmt.Fprintf(os.Stderr, "+ export GOROOT=%s\n", goroot)
}
+ os.Setenv("GOROOT", goroot)
+
+ myContext := build.Default
+ myContext.GOROOT = goroot
myContext.GOPATH = gopath
+ runtimeP, err := myContext.Import("runtime", ".", build.ImportComment)
+ if err != nil {
+ return 0, fmt.Errorf("import failed: %v", err)
+ }
+ gorootInstallDir = runtimeP.PkgTargetRoot + "_dynlink"
// All tests depend on runtime being built into a shared library. Because
// that takes a few seconds, do it here and have all tests use the version
// built here.
- suffix = strings.Split(filepath.Base(gorootInstallDir), "_")[2]
goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...)
- myContext.InstallSuffix = suffix + "_dynlink"
+ myContext.InstallSuffix = "_dynlink"
depP, err := myContext.Import("./depBase", ".", build.ImportComment)
if err != nil {
return 0, fmt.Errorf("import failed: %v", err)
@@ -171,6 +164,75 @@ func TestMain(m *testing.M) {
os.Exit(exitCode)
}
+// cloneTestdataModule clones the packages from src/testshared into gopath.
+// It returns the directory within gopath at which the module root is located.
+func cloneTestdataModule(gopath string) (string, error) {
+ modRoot := filepath.Join(gopath, "src", "testshared")
+ if err := overlayDir(modRoot, "testdata"); err != nil {
+ return "", err
+ }
+ if err := ioutil.WriteFile(filepath.Join(modRoot, "go.mod"), []byte("module testshared\n"), 0644); err != nil {
+ return "", err
+ }
+ return modRoot, nil
+}
+
+// cloneGOROOTDeps copies (or symlinks) the portions of GOROOT/src and
+// GOROOT/pkg relevant to this test into the given directory.
+// It must be run from within the testdata module.
+func cloneGOROOTDeps(goroot string) error {
+ oldGOROOT := strings.TrimSpace(goCmd(nil, "env", "GOROOT"))
+ if oldGOROOT == "" {
+ return fmt.Errorf("go env GOROOT returned an empty string")
+ }
+
+ // Before we clone GOROOT, figure out which packages we need to copy over.
+ listArgs := []string{
+ "list",
+ "-deps",
+ "-f", "{{if and .Standard (not .ForTest)}}{{.ImportPath}}{{end}}",
+ }
+ stdDeps := goCmd(nil, append(listArgs, minpkgs...)...)
+ testdataDeps := goCmd(nil, append(listArgs, "-test", "./...")...)
+
+ pkgs := append(strings.Split(strings.TrimSpace(stdDeps), "\n"),
+ strings.Split(strings.TrimSpace(testdataDeps), "\n")...)
+ sort.Strings(pkgs)
+ var pkgRoots []string
+ for _, pkg := range pkgs {
+ parentFound := false
+ for _, prev := range pkgRoots {
+ if strings.HasPrefix(pkg, prev) {
+ // We will copy in the source for pkg when we copy in prev.
+ parentFound = true
+ break
+ }
+ }
+ if !parentFound {
+ pkgRoots = append(pkgRoots, pkg)
+ }
+ }
+
+ gorootDirs := []string{
+ "pkg/tool",
+ "pkg/include",
+ }
+ for _, pkg := range pkgRoots {
+ gorootDirs = append(gorootDirs, filepath.Join("src", pkg))
+ }
+
+ for _, dir := range gorootDirs {
+ if testing.Verbose() {
+ fmt.Fprintf(os.Stderr, "+ cp -r %s %s\n", filepath.Join(goroot, dir), filepath.Join(oldGOROOT, dir))
+ }
+ if err := overlayDir(filepath.Join(goroot, dir), filepath.Join(oldGOROOT, dir)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
// The shared library was built at the expected location.
func TestSOBuilt(t *testing.T) {
_, err := os.Stat(filepath.Join(gorootInstallDir, soname))
@@ -219,6 +281,7 @@ func TestNoTextrel(t *testing.T) {
}
// The shared library does not contain symbols called ".dup"
+// (See golang.org/issue/14841.)
func TestNoDupSymbols(t *testing.T) {
sopath := filepath.Join(gorootInstallDir, soname)
f, err := elf.Open(sopath)
@@ -695,7 +758,7 @@ func resetFileStamps() {
}
reset := func(path string) {
if err := filepath.Walk(path, chtime); err != nil {
- log.Fatalf("resetFileStamps failed: %v", err)
+ log.Panicf("resetFileStamps failed: %v", err)
}
}
@@ -708,6 +771,7 @@ func resetFileStamps() {
// 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()) {
+ t.Helper()
data, err := ioutil.ReadFile(path)
if err != nil {
t.Fatal(err)
@@ -736,14 +800,32 @@ func touch(t *testing.T, path string) (cleanup func()) {
// assume it's a text file
data = append(data, '\n')
}
- if err := ioutil.WriteFile(path, data, 0666); err != nil {
+
+ // If the file is still a symlink from an overlay, delete it so that we will
+ // replace it with a regular file instead of overwriting the symlinked one.
+ fi, err := os.Lstat(path)
+ if err == nil && !fi.Mode().IsRegular() {
+ fi, err = os.Stat(path)
+ if err := os.Remove(path); err != nil {
+ t.Fatal(err)
+ }
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // If we're replacing a symlink to a read-only file, make the new file
+ // user-writable.
+ perm := fi.Mode().Perm() | 0200
+
+ if err := ioutil.WriteFile(path, data, perm); err != nil {
t.Fatal(err)
}
if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil {
t.Fatal(err)
}
return func() {
- if err := ioutil.WriteFile(path, old, 0666); err != nil {
+ if err := ioutil.WriteFile(path, old, perm); err != nil {
t.Fatal(err)
}
}
diff --git a/libgo/misc/cgo/testsigfwd/main.go b/libgo/misc/cgo/testsigfwd/main.go
index 61bd0da..6d97050 100644
--- a/libgo/misc/cgo/testsigfwd/main.go
+++ b/libgo/misc/cgo/testsigfwd/main.go
@@ -25,6 +25,7 @@ static void sigsegv() {
static void segvhandler(int signum) {
if (signum == SIGSEGV) {
+ fprintf(stdout, "ok\ttestsigfwd\n");
exit(0); // success
}
}
diff --git a/libgo/misc/cgo/testso/overlaydir_test.go b/libgo/misc/cgo/testso/overlaydir_test.go
index 10c874d..09a1d51 100644
--- a/libgo/misc/cgo/testso/overlaydir_test.go
+++ b/libgo/misc/cgo/testso/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
diff --git a/libgo/misc/cgo/testsovar/overlaydir_test.go b/libgo/misc/cgo/testsovar/overlaydir_test.go
index 10c874d..09a1d51 100644
--- a/libgo/misc/cgo/testsovar/overlaydir_test.go
+++ b/libgo/misc/cgo/testsovar/overlaydir_test.go
@@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
- symBase, err := filepath.Rel(srcRoot, dstRoot)
+ srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
- symBase, err = filepath.Abs(srcRoot)
- if err != nil {
- return err
- }
+ return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
- return os.Mkdir(dstPath, perm)
+ return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
- if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
+ if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}