diff options
author | Cherry Zhang <cherryyz@google.com> | 2020-10-28 09:12:20 -0400 |
---|---|---|
committer | Cherry Zhang <cherryyz@google.com> | 2020-10-28 09:12:20 -0400 |
commit | a16e30d162c1c7408db7821e7b9513cefa09c6ca (patch) | |
tree | af752ba9ba44c547df39bb0af9bff79f610ba9d5 /misc/cgo | |
parent | 91e4d2d57bc341dd82c98247117114c851380aef (diff) | |
parent | cf6cfba4d5358404dd890f6025e573a4b2156543 (diff) | |
download | go-git-dev.link.tar.gz |
[dev.link] all: merge branch 'master' into dev.linkdev.link
Clean merge.
Change-Id: Ia7b2808bc649790198d34c226a61d9e569084dc5
Diffstat (limited to 'misc/cgo')
-rw-r--r-- | misc/cgo/test/callback.go | 2 | ||||
-rw-r--r-- | misc/cgo/test/cgo_linux_test.go | 1 | ||||
-rw-r--r-- | misc/cgo/test/cgo_test.go | 2 | ||||
-rw-r--r-- | misc/cgo/test/issue1435.go | 152 | ||||
-rw-r--r-- | misc/cgo/test/issue4029.c | 1 | ||||
-rw-r--r-- | misc/cgo/test/issue4029.go | 5 | ||||
-rw-r--r-- | misc/cgo/test/issue4029w.go | 2 | ||||
-rw-r--r-- | misc/cgo/test/sigaltstack.go | 2 | ||||
-rw-r--r-- | misc/cgo/test/test.go | 26 | ||||
-rw-r--r-- | misc/cgo/test/testdata/issue41761.go | 20 | ||||
-rw-r--r-- | misc/cgo/test/testdata/issue41761a/a.go | 14 | ||||
-rw-r--r-- | misc/cgo/testcarchive/carchive_test.go | 2 | ||||
-rw-r--r-- | misc/cgo/testcshared/cshared_test.go | 96 |
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() |