summaryrefslogtreecommitdiff
path: root/misc/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'misc/cgo')
-rw-r--r--misc/cgo/test/callback.go2
-rw-r--r--misc/cgo/test/cgo_linux_test.go1
-rw-r--r--misc/cgo/test/cgo_test.go2
-rw-r--r--misc/cgo/test/issue1435.go152
-rw-r--r--misc/cgo/test/issue4029.c1
-rw-r--r--misc/cgo/test/issue4029.go5
-rw-r--r--misc/cgo/test/issue4029w.go2
-rw-r--r--misc/cgo/test/sigaltstack.go2
-rw-r--r--misc/cgo/test/test.go26
-rw-r--r--misc/cgo/test/testdata/issue41761.go20
-rw-r--r--misc/cgo/test/testdata/issue41761a/a.go14
-rw-r--r--misc/cgo/testcarchive/carchive_test.go2
-rw-r--r--misc/cgo/testcshared/cshared_test.go96
13 files changed, 321 insertions, 4 deletions
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index e749650293..814888e3ac 100644
--- a/misc/cgo/test/callback.go
+++ b/misc/cgo/test/callback.go
@@ -181,7 +181,7 @@ func testCallbackCallers(t *testing.T) {
name := []string{
"runtime.cgocallbackg1",
"runtime.cgocallbackg",
- "runtime.cgocallback_gofunc",
+ "runtime.cgocallback",
"runtime.asmcgocall",
"runtime.cgocall",
"test._Cfunc_callback",
diff --git a/misc/cgo/test/cgo_linux_test.go b/misc/cgo/test/cgo_linux_test.go
index 7b56e11a27..a9746b552e 100644
--- a/misc/cgo/test/cgo_linux_test.go
+++ b/misc/cgo/test/cgo_linux_test.go
@@ -15,5 +15,6 @@ func TestSetgid(t *testing.T) {
}
testSetgid(t)
}
+func Test1435(t *testing.T) { test1435(t) }
func Test6997(t *testing.T) { test6997(t) }
func TestBuildID(t *testing.T) { testBuildID(t) }
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index b745a4417f..f7a76d047b 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -76,6 +76,8 @@ func TestCheckConst(t *testing.T) { testCheckConst(t) }
func TestConst(t *testing.T) { testConst(t) }
func TestCthread(t *testing.T) { testCthread(t) }
func TestEnum(t *testing.T) { testEnum(t) }
+func TestNamedEnum(t *testing.T) { testNamedEnum(t) }
+func TestCastToEnum(t *testing.T) { testCastToEnum(t) }
func TestErrno(t *testing.T) { testErrno(t) }
func TestFpVar(t *testing.T) { testFpVar(t) }
func TestHelpers(t *testing.T) { testHelpers(t) }
diff --git a/misc/cgo/test/issue1435.go b/misc/cgo/test/issue1435.go
new file mode 100644
index 0000000000..155d33baff
--- /dev/null
+++ b/misc/cgo/test/issue1435.go
@@ -0,0 +1,152 @@
+// 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.
+
+// +build linux,cgo
+
+package cgotest
+
+import (
+ "fmt"
+ "io/ioutil"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+// #include <stdio.h>
+// #include <stdlib.h>
+// #include <pthread.h>
+// #include <unistd.h>
+// #include <sys/types.h>
+//
+// pthread_t *t = NULL;
+// pthread_mutex_t mu;
+// int nts = 0;
+// int all_done = 0;
+//
+// static void *aFn(void *vargp) {
+// int done = 0;
+// while (!done) {
+// usleep(100);
+// pthread_mutex_lock(&mu);
+// done = all_done;
+// pthread_mutex_unlock(&mu);
+// }
+// return NULL;
+// }
+//
+// void trial(int argc) {
+// int i;
+// nts = argc;
+// t = calloc(nts, sizeof(pthread_t));
+// pthread_mutex_init(&mu, NULL);
+// for (i = 0; i < nts; i++) {
+// pthread_create(&t[i], NULL, aFn, NULL);
+// }
+// }
+//
+// void cleanup(void) {
+// int i;
+// pthread_mutex_lock(&mu);
+// all_done = 1;
+// pthread_mutex_unlock(&mu);
+// for (i = 0; i < nts; i++) {
+// pthread_join(t[i], NULL);
+// }
+// pthread_mutex_destroy(&mu);
+// free(t);
+// }
+import "C"
+
+// compareStatus is used to confirm the contents of the thread
+// specific status files match expectations.
+func compareStatus(filter, expect string) error {
+ expected := filter + "\t" + expect
+ pid := syscall.Getpid()
+ fs, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid))
+ if err != nil {
+ return fmt.Errorf("unable to find %d tasks: %v", pid, err)
+ }
+ for _, f := range fs {
+ tf := fmt.Sprintf("/proc/%s/status", f.Name())
+ d, err := ioutil.ReadFile(tf)
+ if err != nil {
+ return fmt.Errorf("unable to read %q: %v", tf, err)
+ }
+ lines := strings.Split(string(d), "\n")
+ for _, line := range lines {
+ if strings.HasPrefix(line, filter) {
+ if line != expected {
+ return fmt.Errorf("%s %s (bad)\n", tf, line)
+ }
+ break
+ }
+ }
+ }
+ return nil
+}
+
+// test1435 test 9 glibc implemented setuid/gid syscall functions are
+// mapped. This test is a slightly more expansive test than that of
+// src/syscall/syscall_linux_test.go:TestSetuidEtc() insofar as it
+// launches concurrent threads from C code via CGo and validates that
+// they are subject to the system calls being tested. For the actual
+// Go functionality being tested here, the syscall_linux_test version
+// is considered authoritative, but non-trivial improvements to that
+// should be mirrored here.
+func test1435(t *testing.T) {
+ if syscall.Getuid() != 0 {
+ t.Skip("skipping root only test")
+ }
+
+ // Launch some threads in C.
+ const cts = 5
+ C.trial(cts)
+ defer C.cleanup()
+
+ vs := []struct {
+ call string
+ fn func() error
+ filter, expect string
+ }{
+ {call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "0\t1\t0\t1"},
+ {call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+
+ {call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "0\t1\t0\t1"},
+ {call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
+
+ {call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "1\t1\t1\t1"},
+ {call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+
+ {call: "Setgroups([]int{0,1,2,3})", fn: func() error { return syscall.Setgroups([]int{0, 1, 2, 3}) }, filter: "Groups:", expect: "0 1 2 3 "},
+ {call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: " "},
+ {call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "0 "},
+
+ {call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "101\t0\t0\t0"},
+ {call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "0\t102\t102\t102"},
+ {call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+
+ {call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "1\t0\t0\t0"},
+ {call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "0\t2\t2\t2"},
+ {call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
+
+ {call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "101\t0\t102\t0"},
+ {call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "0\t102\t101\t102"},
+ {call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+
+ {call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "1\t0\t2\t0"},
+ {call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "0\t2\t1\t2"},
+ {call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
+ }
+
+ for i, v := range vs {
+ if err := v.fn(); err != nil {
+ t.Errorf("[%d] %q failed: %v", i, v.call, err)
+ continue
+ }
+ if err := compareStatus(v.filter, v.expect); err != nil {
+ t.Errorf("[%d] %q comparison: %v", i, v.call, err)
+ }
+ }
+}
diff --git a/misc/cgo/test/issue4029.c b/misc/cgo/test/issue4029.c
index 30646ade02..e79c5a709c 100644
--- a/misc/cgo/test/issue4029.c
+++ b/misc/cgo/test/issue4029.c
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build !windows,!static
+// +build !darwin !internal_pie,!arm64
#include <stdint.h>
#include <dlfcn.h>
diff --git a/misc/cgo/test/issue4029.go b/misc/cgo/test/issue4029.go
index 1bf029d760..b2d131833a 100644
--- a/misc/cgo/test/issue4029.go
+++ b/misc/cgo/test/issue4029.go
@@ -3,6 +3,11 @@
// license that can be found in the LICENSE file.
// +build !windows,!static
+// +build !darwin !internal_pie,!arm64
+
+// Excluded in darwin internal linking PIE mode, as dynamic export is not
+// supported.
+// Excluded in internal linking mode on darwin/arm64, as it is always PIE.
package cgotest
diff --git a/misc/cgo/test/issue4029w.go b/misc/cgo/test/issue4029w.go
index eee33f7010..b969bdd0fe 100644
--- a/misc/cgo/test/issue4029w.go
+++ b/misc/cgo/test/issue4029w.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build windows static
+// +build windows static darwin,internal_pie darwin,arm64
package cgotest
diff --git a/misc/cgo/test/sigaltstack.go b/misc/cgo/test/sigaltstack.go
index 27b753a147..034cc4b371 100644
--- a/misc/cgo/test/sigaltstack.go
+++ b/misc/cgo/test/sigaltstack.go
@@ -62,7 +62,7 @@ import (
func testSigaltstack(t *testing.T) {
switch {
- case runtime.GOOS == "solaris", runtime.GOOS == "illumos", (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64":
+ case runtime.GOOS == "solaris", runtime.GOOS == "illumos", runtime.GOOS == "ios" && runtime.GOARCH == "arm64":
t.Skipf("switching signal stack not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
diff --git a/misc/cgo/test/test.go b/misc/cgo/test/test.go
index a78f88499b..65823b1ca0 100644
--- a/misc/cgo/test/test.go
+++ b/misc/cgo/test/test.go
@@ -1000,6 +1000,32 @@ func testEnum(t *testing.T) {
}
}
+func testNamedEnum(t *testing.T) {
+ e := new(C.enum_E)
+
+ *e = C.Enum1
+ if *e != 1 {
+ t.Error("bad enum", C.Enum1)
+ }
+
+ *e = C.Enum2
+ if *e != 2 {
+ t.Error("bad enum", C.Enum2)
+ }
+}
+
+func testCastToEnum(t *testing.T) {
+ e := C.enum_E(C.Enum1)
+ if e != 1 {
+ t.Error("bad enum", C.Enum1)
+ }
+
+ e = C.enum_E(C.Enum2)
+ if e != 2 {
+ t.Error("bad enum", C.Enum2)
+ }
+}
+
func testAtol(t *testing.T) {
l := Atol("123")
if l != 123 {
diff --git a/misc/cgo/test/testdata/issue41761.go b/misc/cgo/test/testdata/issue41761.go
new file mode 100644
index 0000000000..919c749251
--- /dev/null
+++ b/misc/cgo/test/testdata/issue41761.go
@@ -0,0 +1,20 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+ typedef struct S S;
+*/
+import "C"
+
+import (
+ "cgotest/issue41761a"
+ "testing"
+)
+
+func test41761(t *testing.T) {
+ var x issue41761a.T
+ _ = (*C.struct_S)(x.X)
+}
diff --git a/misc/cgo/test/testdata/issue41761a/a.go b/misc/cgo/test/testdata/issue41761a/a.go
new file mode 100644
index 0000000000..ca5c18191e
--- /dev/null
+++ b/misc/cgo/test/testdata/issue41761a/a.go
@@ -0,0 +1,14 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package issue41761a
+
+/*
+ typedef struct S S;
+*/
+import "C"
+
+type T struct {
+ X *C.S
+}
diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go
index 2e223ea369..6ed25d8948 100644
--- a/misc/cgo/testcarchive/carchive_test.go
+++ b/misc/cgo/testcarchive/carchive_test.go
@@ -603,7 +603,7 @@ func TestExtar(t *testing.T) {
if runtime.Compiler == "gccgo" {
t.Skip("skipping -extar test when using gccgo")
}
- if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
+ if runtime.GOOS == "ios" {
t.Skip("shell scripts are not executable on iOS hosts")
}
diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go
index d557f34b0f..e1835afa51 100644
--- a/misc/cgo/testcshared/cshared_test.go
+++ b/misc/cgo/testcshared/cshared_test.go
@@ -7,6 +7,8 @@ package cshared_test
import (
"bytes"
"debug/elf"
+ "debug/pe"
+ "encoding/binary"
"flag"
"fmt"
"io/ioutil"
@@ -355,6 +357,100 @@ func TestExportedSymbols(t *testing.T) {
}
}
+func checkNumberOfExportedFunctionsWindows(t *testing.T, exportAllSymbols bool) {
+ const prog = `
+package main
+
+import "C"
+
+//export GoFunc
+func GoFunc() {
+ println(42)
+}
+
+//export GoFunc2
+func GoFunc2() {
+ println(24)
+}
+
+func main() {
+}
+`
+
+ tmpdir := t.TempDir()
+
+ srcfile := filepath.Join(tmpdir, "test.go")
+ objfile := filepath.Join(tmpdir, "test.dll")
+ if err := ioutil.WriteFile(srcfile, []byte(prog), 0666); err != nil {
+ t.Fatal(err)
+ }
+ argv := []string{"build", "-buildmode=c-shared"}
+ if exportAllSymbols {
+ argv = append(argv, "-ldflags", "-extldflags=-Wl,--export-all-symbols")
+ }
+ argv = append(argv, "-o", objfile, srcfile)
+ out, err := exec.Command("go", argv...).CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failure: %s\n%s\n", err, string(out))
+ }
+
+ f, err := pe.Open(objfile)
+ if err != nil {
+ t.Fatalf("pe.Open failed: %v", err)
+ }
+ defer f.Close()
+ section := f.Section(".edata")
+ if section == nil {
+ t.Error(".edata section is not present")
+ }
+
+ // TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
+ type IMAGE_EXPORT_DIRECTORY struct {
+ _ [2]uint32
+ _ [2]uint16
+ _ [2]uint32
+ NumberOfFunctions uint32
+ NumberOfNames uint32
+ _ [3]uint32
+ }
+ var e IMAGE_EXPORT_DIRECTORY
+ if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil {
+ t.Fatalf("binary.Read failed: %v", err)
+ }
+
+ expectedNumber := uint32(2)
+
+ if exportAllSymbols {
+ if e.NumberOfFunctions <= expectedNumber {
+ t.Fatalf("missing exported functions: %v", e.NumberOfFunctions)
+ }
+ if e.NumberOfNames <= expectedNumber {
+ t.Fatalf("missing exported names: %v", e.NumberOfNames)
+ }
+ } else {
+ if e.NumberOfFunctions != expectedNumber {
+ t.Fatalf("too many exported functions: %v", e.NumberOfFunctions)
+ }
+ if e.NumberOfNames != expectedNumber {
+ t.Fatalf("too many exported names: %v", e.NumberOfNames)
+ }
+ }
+}
+
+func TestNumberOfExportedFunctions(t *testing.T) {
+ if GOOS != "windows" {
+ t.Skip("skipping windows only test")
+ }
+ t.Parallel()
+
+ t.Run("OnlyExported", func(t *testing.T) {
+ checkNumberOfExportedFunctionsWindows(t, false)
+ })
+ t.Run("All", func(t *testing.T) {
+ checkNumberOfExportedFunctionsWindows(t, true)
+ })
+}
+
// test1: shared library can be dynamically loaded and exported symbols are accessible.
func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
t.Parallel()