summaryrefslogtreecommitdiff
path: root/libgo/misc/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/misc/cgo')
-rw-r--r--libgo/misc/cgo/errors/errors_test.go9
-rw-r--r--libgo/misc/cgo/errors/testdata/err2.go12
-rw-r--r--libgo/misc/cgo/gmp/fib.go1
-rw-r--r--libgo/misc/cgo/gmp/pi.go1
-rw-r--r--libgo/misc/cgo/test/cgo_test.go2
-rw-r--r--libgo/misc/cgo/test/cgo_thread_lock.go1
-rw-r--r--libgo/misc/cgo/test/cgo_unix_test.go1
-rw-r--r--libgo/misc/cgo/test/issue18146.go1
-rw-r--r--libgo/misc/cgo/test/issue21897.go1
-rw-r--r--libgo/misc/cgo/test/issue21897b.go1
-rw-r--r--libgo/misc/cgo/test/issue4029.go4
-rw-r--r--libgo/misc/cgo/test/issue4029w.go1
-rw-r--r--libgo/misc/cgo/test/issue42018.go14
-rw-r--r--libgo/misc/cgo/test/issue42018_windows.go46
-rw-r--r--libgo/misc/cgo/test/issue8517.go1
-rw-r--r--libgo/misc/cgo/test/issue8694.go1
-rw-r--r--libgo/misc/cgo/test/sigaltstack.go1
-rw-r--r--libgo/misc/cgo/test/sigprocmask.go1
-rw-r--r--libgo/misc/cgo/test/test.go5
-rw-r--r--libgo/misc/cgo/test/test_unix.go1
-rw-r--r--libgo/misc/cgo/test/testdata/issue43639.go9
-rw-r--r--libgo/misc/cgo/test/testdata/issue43639/a.go8
-rw-r--r--libgo/misc/cgo/test/testdata/issue9400_linux.go9
-rw-r--r--libgo/misc/cgo/test/testx.go24
-rw-r--r--libgo/misc/cgo/test/typeparam.go21
-rw-r--r--libgo/misc/cgo/testcarchive/carchive_test.go330
-rw-r--r--libgo/misc/cgo/testcarchive/testdata/libgo8/a.go36
-rw-r--r--libgo/misc/cgo/testcarchive/testdata/main8.c16
-rw-r--r--libgo/misc/cgo/testcshared/cshared_test.go10
-rw-r--r--libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go1
-rw-r--r--libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go3
-rw-r--r--libgo/misc/cgo/testgodefs/testdata/issue48396.go18
-rw-r--r--libgo/misc/cgo/testgodefs/testdata/main.go3
-rw-r--r--libgo/misc/cgo/testgodefs/testgodefs_test.go1
-rw-r--r--libgo/misc/cgo/testplugin/plugin_test.go32
-rw-r--r--libgo/misc/cgo/testplugin/testdata/forkexec/main.go30
-rw-r--r--libgo/misc/cgo/testsanitizers/asan_test.go81
-rw-r--r--libgo/misc/cgo/testsanitizers/cc_test.go35
-rw-r--r--libgo/misc/cgo/testsanitizers/testdata/asan1_fail.go28
-rw-r--r--libgo/misc/cgo/testsanitizers/testdata/asan2_fail.go34
-rw-r--r--libgo/misc/cgo/testsanitizers/testdata/asan3_fail.go23
-rw-r--r--libgo/misc/cgo/testsanitizers/testdata/asan4_fail.go22
-rw-r--r--libgo/misc/cgo/testsanitizers/testdata/asan5_fail.go21
-rw-r--r--libgo/misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go26
-rw-r--r--libgo/misc/cgo/testshared/shared_test.go35
-rw-r--r--libgo/misc/cgo/testshared/testdata/issue47837/a/a.go19
-rw-r--r--libgo/misc/cgo/testshared/testdata/issue47837/main/main.go14
-rw-r--r--libgo/misc/cgo/testso/noso_test.go1
-rw-r--r--libgo/misc/cgo/testsovar/noso_test.go1
-rw-r--r--libgo/misc/cgo/testtls/tls_test.go1
50 files changed, 938 insertions, 59 deletions
diff --git a/libgo/misc/cgo/errors/errors_test.go b/libgo/misc/cgo/errors/errors_test.go
index 68a30a44fe4..e90ed1e058d 100644
--- a/libgo/misc/cgo/errors/errors_test.go
+++ b/libgo/misc/cgo/errors/errors_test.go
@@ -36,14 +36,13 @@ func check(t *testing.T, file string) {
continue
}
- frags := bytes.SplitAfterN(line, []byte("ERROR HERE: "), 2)
- if len(frags) == 1 {
+ _, frag, ok := bytes.Cut(line, []byte("ERROR HERE: "))
+ if !ok {
continue
}
- frag := fmt.Sprintf(":%d:.*%s", i+1, frags[1])
- re, err := regexp.Compile(frag)
+ re, err := regexp.Compile(fmt.Sprintf(":%d:.*%s", i+1, frag))
if err != nil {
- t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1])
+ t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frag)
continue
}
errors = append(errors, re)
diff --git a/libgo/misc/cgo/errors/testdata/err2.go b/libgo/misc/cgo/errors/testdata/err2.go
index a90598fe35b..aa941584c3c 100644
--- a/libgo/misc/cgo/errors/testdata/err2.go
+++ b/libgo/misc/cgo/errors/testdata/err2.go
@@ -91,10 +91,18 @@ func main() {
// issue 26745
_ = func(i int) int {
- return C.i + 1 // ERROR HERE: 14
+ // typecheck reports at column 14 ('+'), but types2 reports at
+ // column 10 ('C').
+ // TODO(mdempsky): Investigate why, and see if types2 can be
+ // updated to match typecheck behavior.
+ return C.i + 1 // ERROR HERE: \b(10|14)\b
}
_ = func(i int) {
- C.fi(i) // ERROR HERE: 7
+ // typecheck reports at column 7 ('('), but types2 reports at
+ // column 8 ('i'). The types2 position is more correct, but
+ // updating typecheck here is fundamentally challenging because of
+ // IR limitations.
+ C.fi(i) // ERROR HERE: \b(7|8)\b
}
C.fi = C.fi // ERROR HERE
diff --git a/libgo/misc/cgo/gmp/fib.go b/libgo/misc/cgo/gmp/fib.go
index f1091b1c54f..f453fcf1843 100644
--- a/libgo/misc/cgo/gmp/fib.go
+++ b/libgo/misc/cgo/gmp/fib.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build ignore
// +build ignore
// Compute Fibonacci numbers with two goroutines
diff --git a/libgo/misc/cgo/gmp/pi.go b/libgo/misc/cgo/gmp/pi.go
index d5851e8e6bd..5ea034900a9 100644
--- a/libgo/misc/cgo/gmp/pi.go
+++ b/libgo/misc/cgo/gmp/pi.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build ignore
// +build ignore
package main
diff --git a/libgo/misc/cgo/test/cgo_test.go b/libgo/misc/cgo/test/cgo_test.go
index 143f23f0e0c..774277e10da 100644
--- a/libgo/misc/cgo/test/cgo_test.go
+++ b/libgo/misc/cgo/test/cgo_test.go
@@ -59,7 +59,9 @@ 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 Test42018(t *testing.T) { test42018(t) }
func Test45451(t *testing.T) { test45451(t) }
+func Test49633(t *testing.T) { test49633(t) }
func TestAlign(t *testing.T) { testAlign(t) }
func TestAtol(t *testing.T) { testAtol(t) }
func TestBlocking(t *testing.T) { testBlocking(t) }
diff --git a/libgo/misc/cgo/test/cgo_thread_lock.go b/libgo/misc/cgo/test/cgo_thread_lock.go
index b1050685182..3b9ac845493 100644
--- a/libgo/misc/cgo/test/cgo_thread_lock.go
+++ b/libgo/misc/cgo/test/cgo_thread_lock.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build linux && freebsd && openbsd
// +build linux,freebsd,openbsd
package cgotest
diff --git a/libgo/misc/cgo/test/cgo_unix_test.go b/libgo/misc/cgo/test/cgo_unix_test.go
index e3d59166498..a324503a22f 100644
--- a/libgo/misc/cgo/test/cgo_unix_test.go
+++ b/libgo/misc/cgo/test/cgo_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows
// +build !windows
package cgotest
diff --git a/libgo/misc/cgo/test/issue18146.go b/libgo/misc/cgo/test/issue18146.go
index f92d6c7f939..e50f9ae5301 100644
--- a/libgo/misc/cgo/test/issue18146.go
+++ b/libgo/misc/cgo/test/issue18146.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows
// +build !windows
// Issue 18146: pthread_create failure during syscall.Exec.
diff --git a/libgo/misc/cgo/test/issue21897.go b/libgo/misc/cgo/test/issue21897.go
index d13246bd84a..8f39252e688 100644
--- a/libgo/misc/cgo/test/issue21897.go
+++ b/libgo/misc/cgo/test/issue21897.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin && cgo && !internal
// +build darwin,cgo,!internal
package cgotest
diff --git a/libgo/misc/cgo/test/issue21897b.go b/libgo/misc/cgo/test/issue21897b.go
index 08b5f4d808e..50aece35289 100644
--- a/libgo/misc/cgo/test/issue21897b.go
+++ b/libgo/misc/cgo/test/issue21897b.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !darwin || !cgo || internal
// +build !darwin !cgo internal
package cgotest
diff --git a/libgo/misc/cgo/test/issue4029.go b/libgo/misc/cgo/test/issue4029.go
index b2d131833a9..90ca08cbfb7 100644
--- a/libgo/misc/cgo/test/issue4029.go
+++ b/libgo/misc/cgo/test/issue4029.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !windows,!static
+//go:build !windows && !static && (!darwin || (!internal_pie && !arm64))
+// +build !windows
+// +build !static
// +build !darwin !internal_pie,!arm64
// Excluded in darwin internal linking PIE mode, as dynamic export is not
diff --git a/libgo/misc/cgo/test/issue4029w.go b/libgo/misc/cgo/test/issue4029w.go
index b969bdd0fe8..c2f59485e49 100644
--- a/libgo/misc/cgo/test/issue4029w.go
+++ b/libgo/misc/cgo/test/issue4029w.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build windows || static || (darwin && internal_pie) || (darwin && arm64)
// +build windows static darwin,internal_pie darwin,arm64
package cgotest
diff --git a/libgo/misc/cgo/test/issue42018.go b/libgo/misc/cgo/test/issue42018.go
new file mode 100644
index 00000000000..fab686a6783
--- /dev/null
+++ b/libgo/misc/cgo/test/issue42018.go
@@ -0,0 +1,14 @@
+// Copyright 2021 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.
+
+//go:build !windows
+// +build !windows
+
+package cgotest
+
+import "testing"
+
+func test42018(t *testing.T) {
+ t.Skip("skipping Windows-only test")
+}
diff --git a/libgo/misc/cgo/test/issue42018_windows.go b/libgo/misc/cgo/test/issue42018_windows.go
new file mode 100644
index 00000000000..8f4570ab2a5
--- /dev/null
+++ b/libgo/misc/cgo/test/issue42018_windows.go
@@ -0,0 +1,46 @@
+// Copyright 2021 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 void *HANDLE;
+
+struct HWND__{int unused;}; typedef struct HWND__ *HWND;
+*/
+import "C"
+
+import (
+ "testing"
+ "unsafe"
+)
+
+func test42018(t *testing.T) {
+ // Test that Windows handles are marked go:notinheap, by growing the
+ // stack and checking for pointer adjustments. Trick from
+ // test/fixedbugs/issue40954.go.
+ var i int
+ handle := C.HANDLE(unsafe.Pointer(uintptr(unsafe.Pointer(&i))))
+ recurseHANDLE(100, handle, uintptr(unsafe.Pointer(&i)))
+ hwnd := C.HWND(unsafe.Pointer(uintptr(unsafe.Pointer(&i))))
+ recurseHWND(400, hwnd, uintptr(unsafe.Pointer(&i)))
+}
+
+func recurseHANDLE(n int, p C.HANDLE, v uintptr) {
+ if n > 0 {
+ recurseHANDLE(n-1, p, v)
+ }
+ if uintptr(unsafe.Pointer(p)) != v {
+ panic("adjusted notinheap pointer")
+ }
+}
+
+func recurseHWND(n int, p C.HWND, v uintptr) {
+ if n > 0 {
+ recurseHWND(n-1, p, v)
+ }
+ if uintptr(unsafe.Pointer(p)) != v {
+ panic("adjusted notinheap pointer")
+ }
+}
diff --git a/libgo/misc/cgo/test/issue8517.go b/libgo/misc/cgo/test/issue8517.go
index 4e431df921d..7316ab0335d 100644
--- a/libgo/misc/cgo/test/issue8517.go
+++ b/libgo/misc/cgo/test/issue8517.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows
// +build !windows
package cgotest
diff --git a/libgo/misc/cgo/test/issue8694.go b/libgo/misc/cgo/test/issue8694.go
index 89be7ea0907..19071ce1595 100644
--- a/libgo/misc/cgo/test/issue8694.go
+++ b/libgo/misc/cgo/test/issue8694.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !android
// +build !android
package cgotest
diff --git a/libgo/misc/cgo/test/sigaltstack.go b/libgo/misc/cgo/test/sigaltstack.go
index 034cc4b3719..6b371897a73 100644
--- a/libgo/misc/cgo/test/sigaltstack.go
+++ b/libgo/misc/cgo/test/sigaltstack.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows && !android
// +build !windows,!android
// Test that the Go runtime still works if C code changes the signal stack.
diff --git a/libgo/misc/cgo/test/sigprocmask.go b/libgo/misc/cgo/test/sigprocmask.go
index e2b939f05e2..983734cc7b6 100644
--- a/libgo/misc/cgo/test/sigprocmask.go
+++ b/libgo/misc/cgo/test/sigprocmask.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows
// +build !windows
package cgotest
diff --git a/libgo/misc/cgo/test/test.go b/libgo/misc/cgo/test/test.go
index 3b8f548b13d..dd81f770a20 100644
--- a/libgo/misc/cgo/test/test.go
+++ b/libgo/misc/cgo/test/test.go
@@ -915,6 +915,11 @@ void issue40494(enum Enum40494 e, union Union40494* up) {}
// Issue 45451, bad handling of go:notinheap types.
typedef struct issue45451Undefined issue45451;
+
+// Issue 49633, example of cgo.Handle with void*.
+extern void GoFunc49633(void*);
+void cfunc49633(void *context) { GoFunc49633(context); }
+
*/
import "C"
diff --git a/libgo/misc/cgo/test/test_unix.go b/libgo/misc/cgo/test/test_unix.go
index 4a234469dbc..831b9ca625a 100644
--- a/libgo/misc/cgo/test/test_unix.go
+++ b/libgo/misc/cgo/test/test_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows
// +build !windows
package cgotest
diff --git a/libgo/misc/cgo/test/testdata/issue43639.go b/libgo/misc/cgo/test/testdata/issue43639.go
new file mode 100644
index 00000000000..e755fbd4bc0
--- /dev/null
+++ b/libgo/misc/cgo/test/testdata/issue43639.go
@@ -0,0 +1,9 @@
+// Copyright 2021 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 43639: No runtime test needed, make sure package cgotest/issue43639 compiles well.
+
+import _ "cgotest/issue43639"
diff --git a/libgo/misc/cgo/test/testdata/issue43639/a.go b/libgo/misc/cgo/test/testdata/issue43639/a.go
new file mode 100644
index 00000000000..fe37d5e4b0f
--- /dev/null
+++ b/libgo/misc/cgo/test/testdata/issue43639/a.go
@@ -0,0 +1,8 @@
+// Copyright 2021 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 issue43639
+
+// #cgo CFLAGS: -W -Wall -Werror
+import "C"
diff --git a/libgo/misc/cgo/test/testdata/issue9400_linux.go b/libgo/misc/cgo/test/testdata/issue9400_linux.go
index e94a9bb45f5..051b9ab0bbe 100644
--- a/libgo/misc/cgo/test/testdata/issue9400_linux.go
+++ b/libgo/misc/cgo/test/testdata/issue9400_linux.go
@@ -15,6 +15,7 @@ import "C"
import (
"runtime"
+ "runtime/debug"
"sync/atomic"
"testing"
@@ -46,6 +47,14 @@ func test9400(t *testing.T) {
big[i] = pattern
}
+ // Disable GC for the duration of the test.
+ // This avoids a potential GC deadlock when spinning in uninterruptable ASM below #49695.
+ defer debug.SetGCPercent(debug.SetGCPercent(-1))
+ // SetGCPercent waits until the mark phase is over, but the runtime
+ // also preempts at the start of the sweep phase, so make sure that's
+ // done too. See #49695.
+ runtime.GC()
+
// Temporarily rewind the stack and trigger SIGSETXID
issue9400.RewindAndSetgid()
diff --git a/libgo/misc/cgo/test/testx.go b/libgo/misc/cgo/test/testx.go
index 823c3e13d29..8ec84a8b22e 100644
--- a/libgo/misc/cgo/test/testx.go
+++ b/libgo/misc/cgo/test/testx.go
@@ -113,6 +113,7 @@ typedef struct {
int i;
} Issue38408, *PIssue38408;
+extern void cfunc49633(void*); // definition is in test.go
*/
import "C"
@@ -554,3 +555,26 @@ func GoFunc37033(handle C.uintptr_t) {
// A typedef pointer can be used as the element type.
// No runtime test; just make sure it compiles.
var _ C.PIssue38408 = &C.Issue38408{i: 1}
+
+// issue 49633, example use of cgo.Handle with void*
+
+type data49633 struct {
+ msg string
+}
+
+//export GoFunc49633
+func GoFunc49633(context unsafe.Pointer) {
+ h := *(*cgo.Handle)(context)
+ v := h.Value().(*data49633)
+ v.msg = "hello"
+}
+
+func test49633(t *testing.T) {
+ v := &data49633{}
+ h := cgo.NewHandle(v)
+ defer h.Delete()
+ C.cfunc49633(unsafe.Pointer(&h))
+ if v.msg != "hello" {
+ t.Errorf("msg = %q, want 'hello'", v.msg)
+ }
+}
diff --git a/libgo/misc/cgo/test/typeparam.go b/libgo/misc/cgo/test/typeparam.go
new file mode 100644
index 00000000000..9291005db67
--- /dev/null
+++ b/libgo/misc/cgo/test/typeparam.go
@@ -0,0 +1,21 @@
+// Copyright 2021 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 <stddef.h>
+import "C"
+
+/* FIXME: Commented out for gofrontend.
+
+func generic[T, U any](t T, u U) {}
+
+func useGeneric() {
+ const zero C.size_t = 0
+
+ generic(zero, zero)
+ generic[C.size_t, C.size_t](0, 0)
+}
+
+*/
diff --git a/libgo/misc/cgo/testcarchive/carchive_test.go b/libgo/misc/cgo/testcarchive/carchive_test.go
index e5db0d628a4..8ed72fb0e59 100644
--- a/libgo/misc/cgo/testcarchive/carchive_test.go
+++ b/libgo/misc/cgo/testcarchive/carchive_test.go
@@ -10,12 +10,15 @@ import (
"debug/elf"
"flag"
"fmt"
+ "io"
+ "io/fs"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"syscall"
"testing"
@@ -245,6 +248,29 @@ func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
var badLineRegexp = regexp.MustCompile(`(?m)^#line [0-9]+ "/.*$`)
+// checkIsExecutable verifies that exe exists and has execute permission.
+//
+// (https://golang.org/issue/49693 notes failures with "no such file or
+// directory", so we want to double-check that the executable actually exists
+// immediately after we build it in order to better understand that failure
+// mode.)
+func checkIsExecutable(t *testing.T, exe string) {
+ t.Helper()
+ fi, err := os.Stat(exe)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if runtime.GOOS == "windows" {
+ // os.File doesn't check the "execute" permission on Windows files
+ // and as a result doesn't set that bit in a file's permissions.
+ // Assume that if the file exists it is “executable enough”.
+ return
+ }
+ if fi.Mode()&0111 == 0 {
+ t.Fatalf("%s is not executable: %0o", exe, fi.Mode()&fs.ModePerm)
+ }
+}
+
// checkLineComments checks that the export header generated by
// -buildmode=c-archive doesn't have any absolute paths in the #line
// comments. We don't want those paths because they are unhelpful for
@@ -263,6 +289,173 @@ func checkLineComments(t *testing.T, hdrname string) {
}
}
+// checkArchive verifies that the created library looks OK.
+// We just check a couple of things now, we can add more checks as needed.
+func checkArchive(t *testing.T, arname string) {
+ t.Helper()
+
+ switch GOOS {
+ case "aix", "darwin", "ios", "windows":
+ // We don't have any checks for non-ELF libraries yet.
+ if _, err := os.Stat(arname); err != nil {
+ t.Errorf("archive %s does not exist: %v", arname, err)
+ }
+ default:
+ checkELFArchive(t, arname)
+ }
+}
+
+// checkELFArchive checks an ELF archive.
+func checkELFArchive(t *testing.T, arname string) {
+ t.Helper()
+
+ f, err := os.Open(arname)
+ if err != nil {
+ t.Errorf("archive %s does not exist: %v", arname, err)
+ return
+ }
+ defer f.Close()
+
+ // TODO(iant): put these in a shared package? But where?
+ const (
+ magic = "!<arch>\n"
+ fmag = "`\n"
+
+ namelen = 16
+ datelen = 12
+ uidlen = 6
+ gidlen = 6
+ modelen = 8
+ sizelen = 10
+ fmaglen = 2
+ hdrlen = namelen + datelen + uidlen + gidlen + modelen + sizelen + fmaglen
+ )
+
+ type arhdr struct {
+ name string
+ date string
+ uid string
+ gid string
+ mode string
+ size string
+ fmag string
+ }
+
+ var magbuf [len(magic)]byte
+ if _, err := io.ReadFull(f, magbuf[:]); err != nil {
+ t.Errorf("%s: archive too short", arname)
+ return
+ }
+ if string(magbuf[:]) != magic {
+ t.Errorf("%s: incorrect archive magic string %q", arname, magbuf)
+ }
+
+ off := int64(len(magic))
+ for {
+ if off&1 != 0 {
+ var b [1]byte
+ if _, err := f.Read(b[:]); err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Errorf("%s: error skipping alignment byte at %d: %v", arname, off, err)
+ }
+ off++
+ }
+
+ var hdrbuf [hdrlen]byte
+ if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Errorf("%s: error reading archive header at %d: %v", arname, off, err)
+ return
+ }
+
+ var hdr arhdr
+ hdrslice := hdrbuf[:]
+ set := func(len int, ps *string) {
+ *ps = string(bytes.TrimSpace(hdrslice[:len]))
+ hdrslice = hdrslice[len:]
+ }
+ set(namelen, &hdr.name)
+ set(datelen, &hdr.date)
+ set(uidlen, &hdr.uid)
+ set(gidlen, &hdr.gid)
+ set(modelen, &hdr.mode)
+ set(sizelen, &hdr.size)
+ hdr.fmag = string(hdrslice[:fmaglen])
+ hdrslice = hdrslice[fmaglen:]
+ if len(hdrslice) != 0 {
+ t.Fatalf("internal error: len(hdrslice) == %d", len(hdrslice))
+ }
+
+ if hdr.fmag != fmag {
+ t.Errorf("%s: invalid fmagic value %q at %d", arname, hdr.fmag, off)
+ return
+ }
+
+ size, err := strconv.ParseInt(hdr.size, 10, 64)
+ if err != nil {
+ t.Errorf("%s: error parsing size %q at %d: %v", arname, hdr.size, off, err)
+ return
+ }
+
+ off += hdrlen
+
+ switch hdr.name {
+ case "__.SYMDEF", "/", "/SYM64/":
+ // The archive symbol map.
+ case "//", "ARFILENAMES/":
+ // The extended name table.
+ default:
+ // This should be an ELF object.
+ checkELFArchiveObject(t, arname, off, io.NewSectionReader(f, off, size))
+ }
+
+ off += size
+ if _, err := f.Seek(off, os.SEEK_SET); err != nil {
+ t.Errorf("%s: failed to seek to %d: %v", arname, off, err)
+ }
+ }
+}
+
+// checkELFArchiveObject checks an object in an ELF archive.
+func checkELFArchiveObject(t *testing.T, arname string, off int64, obj io.ReaderAt) {
+ t.Helper()
+
+ ef, err := elf.NewFile(obj)
+ if err != nil {
+ t.Errorf("%s: failed to open ELF file at %d: %v", arname, off, err)
+ return
+ }
+ defer ef.Close()
+
+ // Verify section types.
+ for _, sec := range ef.Sections {
+ want := elf.SHT_NULL
+ switch sec.Name {
+ case ".text", ".data":
+ want = elf.SHT_PROGBITS
+ case ".bss":
+ want = elf.SHT_NOBITS
+ case ".symtab":
+ want = elf.SHT_SYMTAB
+ case ".strtab":
+ want = elf.SHT_STRTAB
+ case ".init_array":
+ want = elf.SHT_INIT_ARRAY
+ case ".fini_array":
+ want = elf.SHT_FINI_ARRAY
+ case ".preinit_array":
+ want = elf.SHT_PREINIT_ARRAY
+ }
+ if want != elf.SHT_NULL && sec.Type != want {
+ t.Errorf("%s: incorrect section type in elf file at %d for section %q: got %v want %v", arname, off, sec.Name, sec.Type, want)
+ }
+ }
+}
+
func TestInstall(t *testing.T) {
if !testWork {
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
@@ -310,7 +503,7 @@ func TestEarlySignalHandler(t *testing.T) {
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
@@ -321,6 +514,7 @@ func TestEarlySignalHandler(t *testing.T) {
t.Fatal(err)
}
checkLineComments(t, "libgo2.h")
+ checkArchive(t, "libgo2.a")
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
if runtime.Compiler == "gccgo" {
@@ -350,7 +544,7 @@ func TestSignalForwarding(t *testing.T) {
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
@@ -361,6 +555,7 @@ func TestSignalForwarding(t *testing.T) {
t.Fatal(err)
}
checkLineComments(t, "libgo2.h")
+ checkArchive(t, "libgo2.a")
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
if runtime.Compiler == "gccgo" {
@@ -374,7 +569,7 @@ func TestSignalForwarding(t *testing.T) {
cmd = exec.Command(bin[0], append(bin[1:], "1")...)
out, err := cmd.CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("%v\n%s", cmd.Args, out)
expectSignal(t, err, syscall.SIGSEGV)
// SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
@@ -383,7 +578,9 @@ func TestSignalForwarding(t *testing.T) {
cmd = exec.Command(bin[0], append(bin[1:], "3")...)
out, err = cmd.CombinedOutput()
- t.Logf("%s", out)
+ if len(out) > 0 {
+ t.Logf("%s", out)
+ }
expectSignal(t, err, syscall.SIGPIPE)
}
}
@@ -400,7 +597,7 @@ func TestSignalForwardingExternal(t *testing.T) {
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
@@ -411,6 +608,7 @@ func TestSignalForwardingExternal(t *testing.T) {
t.Fatal(err)
}
checkLineComments(t, "libgo2.h")
+ checkArchive(t, "libgo2.a")
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
if runtime.Compiler == "gccgo" {
@@ -517,7 +715,7 @@ func TestOsSignal(t *testing.T) {
defer func() {
os.Remove("libgo3.a")
os.Remove("libgo3.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
@@ -528,6 +726,7 @@ func TestOsSignal(t *testing.T) {
t.Fatal(err)
}
checkLineComments(t, "libgo3.h")
+ checkArchive(t, "libgo3.a")
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
if runtime.Compiler == "gccgo" {
@@ -554,7 +753,7 @@ func TestSigaltstack(t *testing.T) {
defer func() {
os.Remove("libgo4.a")
os.Remove("libgo4.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
@@ -565,6 +764,7 @@ func TestSigaltstack(t *testing.T) {
t.Fatal(err)
}
checkLineComments(t, "libgo4.h")
+ checkArchive(t, "libgo4.a")
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
if runtime.Compiler == "gccgo" {
@@ -747,25 +947,30 @@ func TestSIGPROF(t *testing.T) {
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "./libgo6")
- if out, err := cmd.CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err := cmd.CombinedOutput()
+ t.Logf("%v\n%s", cmd.Args, out)
+ if err != nil {
t.Fatal(err)
}
checkLineComments(t, "libgo6.h")
+ checkArchive(t, "libgo6.a")
ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.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)
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
+ if err != nil {
t.Fatal(err)
}
+ checkIsExecutable(t, "./testp6"+exeSuffix)
argv := cmdToRun("./testp6")
cmd = exec.Command(argv[0], argv[1:]...)
- if out, err := cmd.CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err = cmd.CombinedOutput()
+ t.Logf("%v\n%s", argv, out)
+ if err != nil {
t.Fatal(err)
}
}
@@ -788,13 +993,13 @@ func TestCompileWithoutShared(t *testing.T) {
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "./libgo2")
- t.Log(cmd.Args)
out, err := cmd.CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("%v\n%s", cmd.Args, out)
if err != nil {
t.Fatal(err)
}
checkLineComments(t, "libgo2.h")
+ checkArchive(t, "libgo2.a")
exe := "./testnoshared" + exeSuffix
@@ -804,23 +1009,22 @@ func TestCompileWithoutShared(t *testing.T) {
if runtime.Compiler == "gccgo" {
ccArgs = append(ccArgs, "-lgo")
}
- t.Log(ccArgs)
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
// 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()
+ t.Logf("%v\n%s", ccArgs, out)
}
// 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)
+ ccArgs = append(cc, "-o", exe, "main5.c", "libgo2.a")
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
}
- t.Logf("%s", out)
if err != nil {
t.Fatal(err)
}
@@ -829,17 +1033,15 @@ func TestCompileWithoutShared(t *testing.T) {
}
binArgs := append(cmdToRun(exe), "1")
- t.Log(binArgs)
out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("%v\n%s", binArgs, out)
expectSignal(t, err, syscall.SIGSEGV)
// SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
if runtime.GOOS != "darwin" && runtime.GOOS != "ios" {
binArgs := append(cmdToRun(exe), "3")
- t.Log(binArgs)
out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("%v\n%s", binArgs, out)
expectSignal(t, err, syscall.SIGPIPE)
}
}
@@ -894,26 +1096,87 @@ func TestManyCalls(t *testing.T) {
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo7.a", "./libgo7")
- if out, err := cmd.CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err := cmd.CombinedOutput()
+ t.Logf("%v\n%s", cmd.Args, out)
+ if err != nil {
t.Fatal(err)
}
checkLineComments(t, "libgo7.h")
+ checkArchive(t, "libgo7.a")
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)
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
+ if err != nil {
t.Fatal(err)
}
+ checkIsExecutable(t, "./testp7"+exeSuffix)
argv := cmdToRun("./testp7")
cmd = exec.Command(argv[0], argv[1:]...)
- var sb strings.Builder
- cmd.Stdout = &sb
- cmd.Stderr = &sb
+ sb := new(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()
+
+ err = cmd.Wait()
+ t.Logf("%v\n%s", cmd.Args, sb)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+// Issue 49288.
+func TestPreemption(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping asynchronous preemption test with gccgo")
+ }
+
+ t.Parallel()
+
+ if !testWork {
+ defer func() {
+ os.Remove("testp8" + exeSuffix)
+ os.Remove("libgo8.a")
+ os.Remove("libgo8.h")
+ }()
+ }
+
+ cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo8.a", "./libgo8")
+ out, err := cmd.CombinedOutput()
+ t.Logf("%v\n%s", cmd.Args, out)
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkLineComments(t, "libgo8.h")
+ checkArchive(t, "libgo8.a")
+
+ ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkIsExecutable(t, "./testp8"+exeSuffix)
+
+ argv := cmdToRun("./testp8")
+ cmd = exec.Command(argv[0], argv[1:]...)
+ sb := new(strings.Builder)
+ cmd.Stdout = sb
+ cmd.Stderr = sb
if err := cmd.Start(); err != nil {
t.Fatal(err)
}
@@ -926,8 +1189,9 @@ func TestManyCalls(t *testing.T) {
)
defer timer.Stop()
- if err := cmd.Wait(); err != nil {
- t.Log(sb.String())
+ err = cmd.Wait()
+ t.Logf("%v\n%s", cmd.Args, sb)
+ if err != nil {
t.Error(err)
}
}
diff --git a/libgo/misc/cgo/testcarchive/testdata/libgo8/a.go b/libgo/misc/cgo/testcarchive/testdata/libgo8/a.go
new file mode 100644
index 00000000000..718418ecb87
--- /dev/null
+++ b/libgo/misc/cgo/testcarchive/testdata/libgo8/a.go
@@ -0,0 +1,36 @@
+// Copyright 2021 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"
+
+import (
+ "os"
+ "runtime"
+ "sync/atomic"
+)
+
+var started int32
+
+// Start a goroutine that loops forever.
+func init() {
+ runtime.GOMAXPROCS(1)
+ go func() {
+ for {
+ atomic.StoreInt32(&started, 1)
+ }
+ }()
+}
+
+//export GoFunction8
+func GoFunction8() {
+ for atomic.LoadInt32(&started) == 0 {
+ runtime.Gosched()
+ }
+ os.Exit(0)
+}
+
+func main() {
+}
diff --git a/libgo/misc/cgo/testcarchive/testdata/main8.c b/libgo/misc/cgo/testcarchive/testdata/main8.c
new file mode 100644
index 00000000000..95fb7a349e1
--- /dev/null
+++ b/libgo/misc/cgo/testcarchive/testdata/main8.c
@@ -0,0 +1,16 @@
+// Copyright 2021 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 preemption.
+
+#include <stdlib.h>
+
+#include "libgo8.h"
+
+int main() {
+ GoFunction8();
+
+ // That should have exited the program.
+ abort();
+}
diff --git a/libgo/misc/cgo/testcshared/cshared_test.go b/libgo/misc/cgo/testcshared/cshared_test.go
index 19ad8c76a83..13ec8761e86 100644
--- a/libgo/misc/cgo/testcshared/cshared_test.go
+++ b/libgo/misc/cgo/testcshared/cshared_test.go
@@ -200,7 +200,7 @@ func adbRun(t *testing.T, env []string, adbargs ...string) string {
args := append(adbCmd(), "exec-out")
// Propagate LD_LIBRARY_PATH to the adb shell invocation.
for _, e := range env {
- if strings.Index(e, "LD_LIBRARY_PATH=") != -1 {
+ if strings.Contains(e, "LD_LIBRARY_PATH=") {
adbargs = append([]string{e}, adbargs...)
break
}
@@ -326,7 +326,7 @@ func createHeaders() error {
base, name := filepath.Split(args[0])
args[0] = filepath.Join(base, "llvm-dlltool")
var machine string
- switch strings.SplitN(name, "-", 2)[0] {
+ switch prefix, _, _ := strings.Cut(name, "-"); prefix {
case "i686":
machine = "i386"
case "x86_64":
@@ -781,10 +781,10 @@ func copyFile(t *testing.T, dst, src string) {
func TestGo2C2Go(t *testing.T) {
switch GOOS {
- case "darwin", "ios":
- // Darwin shared libraries don't support the multiple
+ case "darwin", "ios", "windows":
+ // Non-ELF shared libraries don't support the multiple
// copies of the runtime package implied by this test.
- t.Skip("linking c-shared into Go programs not supported on Darwin; issue 29061")
+ t.Skipf("linking c-shared into Go programs not supported on %s; issue 29061, 49457", GOOS)
case "android":
t.Skip("test fails on android; issue 29087")
}
diff --git a/libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go b/libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go
index 3b53e1ceea2..17432a33148 100644
--- a/libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go
+++ b/libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || (linux && !arm64 && !riscv && !riscv64) || netbsd || openbsd
// +build darwin dragonfly freebsd linux,!arm64,!riscv,!riscv64 netbsd openbsd
package main
diff --git a/libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go b/libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go
index 79a37730c84..9b1e8391c18 100644
--- a/libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go
+++ b/libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux,arm64 linux,riscv,riscv64
+//go:build (linux && arm64) || (linux && riscv) || (linux && riscv64)
+// +build linux,arm64 linux,riscv linux,riscv64
package main
diff --git a/libgo/misc/cgo/testgodefs/testdata/issue48396.go b/libgo/misc/cgo/testgodefs/testdata/issue48396.go
new file mode 100644
index 00000000000..d4c192403fd
--- /dev/null
+++ b/libgo/misc/cgo/testgodefs/testdata/issue48396.go
@@ -0,0 +1,18 @@
+// Copyright 2021 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
+
+/*
+// from <linux/kcm.h>
+struct issue48396 {
+ int fd;
+ int bpf_fd;
+};
+*/
+import "C"
+
+type Issue48396 C.struct_issue48396
diff --git a/libgo/misc/cgo/testgodefs/testdata/main.go b/libgo/misc/cgo/testgodefs/testdata/main.go
index 4a3f6a701cc..5c670f3d329 100644
--- a/libgo/misc/cgo/testgodefs/testdata/main.go
+++ b/libgo/misc/cgo/testgodefs/testdata/main.go
@@ -28,6 +28,9 @@ var v7 = S{}
// Test that #define'd type is fully defined
var _ = issue38649{X: 0}
+// Test that prefixes do not cause duplicate field names.
+var _ = Issue48396{Fd: 1, Bpf_fd: 2}
+
func main() {
pass := true
diff --git a/libgo/misc/cgo/testgodefs/testgodefs_test.go b/libgo/misc/cgo/testgodefs/testgodefs_test.go
index aae34043605..7628ffc595b 100644
--- a/libgo/misc/cgo/testgodefs/testgodefs_test.go
+++ b/libgo/misc/cgo/testgodefs/testgodefs_test.go
@@ -25,6 +25,7 @@ var filePrefixes = []string{
"issue37621",
"issue38649",
"issue39534",
+ "issue48396",
}
func TestGoDefs(t *testing.T) {
diff --git a/libgo/misc/cgo/testplugin/plugin_test.go b/libgo/misc/cgo/testplugin/plugin_test.go
index 9697dbf7a78..10c5db2646b 100644
--- a/libgo/misc/cgo/testplugin/plugin_test.go
+++ b/libgo/misc/cgo/testplugin/plugin_test.go
@@ -265,10 +265,6 @@ func TestIssue25756(t *testing.T) {
// Test with main using -buildmode=pie with plugin for issue #43228
func TestIssue25756pie(t *testing.T) {
- if os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-11_0-toothrot" {
- t.Skip("broken on darwin/arm64 builder in sharded mode; see issue 46239")
- }
-
goCmd(t, "build", "-buildmode=plugin", "-o", "life.so", "./issue25756/plugin")
goCmd(t, "build", "-buildmode=pie", "-o", "issue25756pie.exe", "./issue25756/main.go")
run(t, "./issue25756pie.exe")
@@ -293,3 +289,31 @@ func TestIssue44956(t *testing.T) {
goCmd(t, "build", "-o", "issue44956.exe", "./issue44956/main.go")
run(t, "./issue44956.exe")
}
+
+func TestForkExec(t *testing.T) {
+ // Issue 38824: importing the plugin package causes it hang in forkExec on darwin.
+
+ t.Parallel()
+ goCmd(t, "build", "-o", "forkexec.exe", "./forkexec/main.go")
+
+ var cmd *exec.Cmd
+ done := make(chan int, 1)
+
+ go func() {
+ for i := 0; i < 100; i++ {
+ cmd = exec.Command("./forkexec.exe", "1")
+ err := cmd.Run()
+ if err != nil {
+ t.Errorf("running command failed: %v", err)
+ break
+ }
+ }
+ done <- 1
+ }()
+ select {
+ case <-done:
+ case <-time.After(5 * time.Minute):
+ cmd.Process.Kill()
+ t.Fatalf("subprocess hang")
+ }
+}
diff --git a/libgo/misc/cgo/testplugin/testdata/forkexec/main.go b/libgo/misc/cgo/testplugin/testdata/forkexec/main.go
new file mode 100644
index 00000000000..3169ff5f04d
--- /dev/null
+++ b/libgo/misc/cgo/testplugin/testdata/forkexec/main.go
@@ -0,0 +1,30 @@
+// Copyright 2021 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 (
+ "os"
+ "os/exec"
+ _ "plugin"
+ "sync"
+)
+
+func main() {
+ if os.Args[1] != "1" {
+ return
+ }
+
+ var wg sync.WaitGroup
+ for i := 0; i < 8; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ // does not matter what we exec, just exec itself
+ cmd := exec.Command("./forkexec.exe", "0")
+ cmd.Run()
+ }()
+ }
+ wg.Wait()
+}
diff --git a/libgo/misc/cgo/testsanitizers/asan_test.go b/libgo/misc/cgo/testsanitizers/asan_test.go
new file mode 100644
index 00000000000..1b70bce3d11
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/asan_test.go
@@ -0,0 +1,81 @@
+// Copyright 2021 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 TestASAN(t *testing.T) {
+ goos, err := goEnv("GOOS")
+ if err != nil {
+ t.Fatal(err)
+ }
+ goarch, err := goEnv("GOARCH")
+ if err != nil {
+ t.Fatal(err)
+ }
+ // The asan tests require support for the -asan option.
+ if !aSanSupported(goos, goarch) {
+ t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
+ }
+
+ t.Parallel()
+ requireOvercommit(t)
+ config := configure("address")
+ config.skipIfCSanitizerBroken(t)
+
+ mustRun(t, config.goCmd("build", "std"))
+
+ cases := []struct {
+ src string
+ memoryAccessError string
+ errorLocation string
+ }{
+ {src: "asan1_fail.go", memoryAccessError: "heap-use-after-free", errorLocation: "asan1_fail.go:25"},
+ {src: "asan2_fail.go", memoryAccessError: "heap-buffer-overflow", errorLocation: "asan2_fail.go:31"},
+ {src: "asan3_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan3_fail.go:13"},
+ {src: "asan4_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan4_fail.go:13"},
+ {src: "asan5_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan5_fail.go:18"},
+ {src: "asan_useAfterReturn.go"},
+ }
+ 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.memoryAccessError != "" {
+ outb, err := cmd.CombinedOutput()
+ out := string(outb)
+ if err != nil && strings.Contains(out, tc.memoryAccessError) {
+ // This string is output if the
+ // sanitizer library needs a
+ // symbolizer program and can't find it.
+ const noSymbolizer = "external symbolizer"
+ // Check if -asan option can correctly print where the error occured.
+ if tc.errorLocation != "" &&
+ !strings.Contains(out, tc.errorLocation) &&
+ !strings.Contains(out, noSymbolizer) &&
+ compilerSupportsLocation() {
+
+ t.Errorf("%#q exited without expected location of the error\n%s; got failure\n%s", strings.Join(cmd.Args, " "), tc.errorLocation, out)
+ }
+ return
+ }
+ t.Fatalf("%#q exited without expected memory access error\n%s; got failure\n%s", strings.Join(cmd.Args, " "), tc.memoryAccessError, out)
+ }
+ mustRun(t, cmd)
+ })
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/cc_test.go b/libgo/misc/cgo/testsanitizers/cc_test.go
index 384b6250e1e..05b77932b4c 100644
--- a/libgo/misc/cgo/testsanitizers/cc_test.go
+++ b/libgo/misc/cgo/testsanitizers/cc_test.go
@@ -218,6 +218,23 @@ func compilerVersion() (version, error) {
return compiler.version, compiler.err
}
+// compilerSupportsLocation reports whether the compiler should be
+// able to provide file/line information in backtraces.
+func compilerSupportsLocation() bool {
+ compiler, err := compilerVersion()
+ if err != nil {
+ return false
+ }
+ switch compiler.name {
+ case "gcc":
+ return compiler.major >= 10
+ case "clang":
+ return true
+ default:
+ return false
+ }
+}
+
type compilerCheck struct {
once sync.Once
err error
@@ -267,6 +284,11 @@ func configure(sanitizer string) *config {
c.ldFlags = append(c.ldFlags, "-fPIC", "-static-libtsan")
}
+ case "address":
+ c.goFlags = append(c.goFlags, "-asan")
+ // Set the debug mode to print the C stack trace.
+ c.cFlags = append(c.cFlags, "-g")
+
default:
panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer))
}
@@ -344,7 +366,7 @@ func (c *config) checkCSanitizer() (skip bool, err error) {
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]
+ snippet, _, _ := bytes.Cut(out, []byte("\n"))
return true, fmt.Errorf("%#q generated broken executable: %v\n%s", strings.Join(cmd.Args, " "), err, snippet)
}
@@ -450,3 +472,14 @@ func mSanSupported(goos, goarch string) bool {
return false
}
}
+
+// aSanSupported is a copy of the function cmd/internal/sys.ASanSupported,
+// because the internal pacakage can't be used here.
+func aSanSupported(goos, goarch string) bool {
+ switch goos {
+ case "linux":
+ return goarch == "amd64" || goarch == "arm64"
+ default:
+ return false
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/testdata/asan1_fail.go b/libgo/misc/cgo/testsanitizers/testdata/asan1_fail.go
new file mode 100644
index 00000000000..80289e5c304
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/testdata/asan1_fail.go
@@ -0,0 +1,28 @@
+// Copyright 2021 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
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+
+int *p;
+int* test() {
+ p = (int *)malloc(2 * sizeof(int));
+ free(p);
+ return p;
+}
+*/
+import "C"
+import "fmt"
+
+func main() {
+ // C passes Go an invalid pointer.
+ a := C.test()
+ // Use after free
+ *a = 2 // BOOM
+ // We shouldn't get here; asan should stop us first.
+ fmt.Println(*a)
+}
diff --git a/libgo/misc/cgo/testsanitizers/testdata/asan2_fail.go b/libgo/misc/cgo/testsanitizers/testdata/asan2_fail.go
new file mode 100644
index 00000000000..3ab06085710
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/testdata/asan2_fail.go
@@ -0,0 +1,34 @@
+// Copyright 2021 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
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+
+int *p;
+int* f() {
+ int i;
+ p = (int *)malloc(5*sizeof(int));
+ for (i = 0; i < 5; i++) {
+ p[i] = i+10;
+ }
+ return p;
+}
+*/
+import "C"
+import (
+ "fmt"
+ "unsafe"
+)
+
+func main() {
+ a := C.f()
+ q5 := (*C.int)(unsafe.Add(unsafe.Pointer(a), 4*5))
+ // Access to C pointer out of bounds.
+ *q5 = 100 // BOOM
+ // We shouldn't get here; asan should stop us first.
+ fmt.Printf("q5: %d, %x\n", *q5, q5)
+}
diff --git a/libgo/misc/cgo/testsanitizers/testdata/asan3_fail.go b/libgo/misc/cgo/testsanitizers/testdata/asan3_fail.go
new file mode 100644
index 00000000000..9f6d26dd89d
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/testdata/asan3_fail.go
@@ -0,0 +1,23 @@
+// Copyright 2021 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
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+
+void test(int *a) {
+ // Access Go pointer out of bounds.
+ int c = a[5]; // BOOM
+ // We shouldn't get here; asan should stop us first.
+ printf("a[5]=%d\n", c);
+}
+*/
+import "C"
+
+func main() {
+ cIntSlice := []C.int{200, 201, 203, 203, 204}
+ C.test(&cIntSlice[0])
+}
diff --git a/libgo/misc/cgo/testsanitizers/testdata/asan4_fail.go b/libgo/misc/cgo/testsanitizers/testdata/asan4_fail.go
new file mode 100644
index 00000000000..12098458ae9
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/testdata/asan4_fail.go
@@ -0,0 +1,22 @@
+// Copyright 2021 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
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+
+void test(int* a) {
+ // Access Go pointer out of bounds.
+ a[3] = 300; // BOOM
+ // We shouldn't get here; asan should stop us first.
+ printf("a[3]=%d\n", a[3]);
+}*/
+import "C"
+
+func main() {
+ var cIntArray [2]C.int
+ C.test(&cIntArray[0]) // cIntArray is moved to heap.
+}
diff --git a/libgo/misc/cgo/testsanitizers/testdata/asan5_fail.go b/libgo/misc/cgo/testsanitizers/testdata/asan5_fail.go
new file mode 100644
index 00000000000..d6853eab733
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/testdata/asan5_fail.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "unsafe"
+)
+
+func main() {
+ p := new([1024 * 1000]int)
+ p[0] = 10
+ r := bar(&p[1024*1000-1])
+ fmt.Printf("r value is %d", r)
+}
+
+func bar(a *int) int {
+ p := unsafe.Add(unsafe.Pointer(a), 2*unsafe.Sizeof(int(1)))
+ runtime.ASanWrite(p, 8) // BOOM
+ *((*int)(p)) = 10
+ return *((*int)(p))
+}
diff --git a/libgo/misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go b/libgo/misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go
new file mode 100644
index 00000000000..3d3d5a6ab1a
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go
@@ -0,0 +1,26 @@
+// Copyright 2021 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
+
+// The -fsanitize=address option of C compier can detect stack-use-after-return bugs.
+// In the following program, the local variable 'local' was moved to heap by the Go
+// compiler because foo() is returning the reference to 'local', and return stack of
+// foo() will be invalid. Thus for main() to use the reference to 'local', the 'local'
+// must be available even after foo() has finished. Therefore, Go has no such issue.
+
+import "fmt"
+
+var ptr *int
+
+func main() {
+ foo()
+ fmt.Printf("ptr=%x, %v", *ptr, ptr)
+}
+
+func foo() {
+ var local int
+ local = 1
+ ptr = &local // local is moved to heap.
+}
diff --git a/libgo/misc/cgo/testshared/shared_test.go b/libgo/misc/cgo/testshared/shared_test.go
index e77f8489154..b78083bc806 100644
--- a/libgo/misc/cgo/testshared/shared_test.go
+++ b/libgo/misc/cgo/testshared/shared_test.go
@@ -20,6 +20,7 @@ import (
"regexp"
"runtime"
"sort"
+ "strconv"
"strings"
"testing"
"time"
@@ -55,7 +56,7 @@ func runWithEnv(t *testing.T, msg string, env []string, args ...string) {
// t.Fatalf if the command fails.
func goCmd(t *testing.T, args ...string) string {
newargs := []string{args[0]}
- if *testX {
+ if *testX && args[0] != "env" {
newargs = append(newargs, "-x")
}
newargs = append(newargs, args[1:]...)
@@ -461,7 +462,9 @@ func TestTrivialExecutable(t *testing.T) {
run(t, "trivial executable", "../../bin/trivial")
AssertIsLinkedTo(t, "../../bin/trivial", soname)
AssertHasRPath(t, "../../bin/trivial", gorootInstallDir)
- checkSize(t, "../../bin/trivial", 100000) // it is 19K on linux/amd64, 100K should be enough
+ // It is 19K on linux/amd64, with separate-code in binutils ld and 64k being most common alignment
+ // 4*64k should be enough, but this might need revision eventually.
+ checkSize(t, "../../bin/trivial", 256000)
}
// Build a trivial program in PIE mode that links against the shared runtime and check it runs.
@@ -470,7 +473,9 @@ func TestTrivialExecutablePIE(t *testing.T) {
run(t, "trivial executable", "./trivial.pie")
AssertIsLinkedTo(t, "./trivial.pie", soname)
AssertHasRPath(t, "./trivial.pie", gorootInstallDir)
- checkSize(t, "./trivial.pie", 100000) // it is 19K on linux/amd64, 100K should be enough
+ // It is 19K on linux/amd64, with separate-code in binutils ld and 64k being most common alignment
+ // 4*64k should be enough, but this might need revision eventually.
+ checkSize(t, "./trivial.pie", 256000)
}
// Check that the file size does not exceed a limit.
@@ -694,7 +699,15 @@ func requireGccgo(t *testing.T) {
if err != nil {
t.Fatalf("%s -dumpversion failed: %v\n%s", gccgoPath, err, output)
}
- if string(output) < "5" {
+ dot := bytes.Index(output, []byte{'.'})
+ if dot > 0 {
+ output = output[:dot]
+ }
+ major, err := strconv.Atoi(string(output))
+ if err != nil {
+ t.Skipf("can't parse gccgo version number %s", output)
+ }
+ if major < 5 {
t.Skipf("gccgo too old (%s)", strings.TrimSpace(string(output)))
}
@@ -1033,7 +1046,7 @@ func TestGlobal(t *testing.T) {
// Run a test using -linkshared of an installed shared package.
// Issue 26400.
func TestTestInstalledShared(t *testing.T) {
- goCmd(nil, "test", "-linkshared", "-test.short", "sync/atomic")
+ goCmd(t, "test", "-linkshared", "-test.short", "sync/atomic")
}
// Test generated pointer method with -linkshared.
@@ -1045,8 +1058,8 @@ func TestGeneratedMethod(t *testing.T) {
// Test use of shared library struct with generated hash function.
// Issue 30768.
func TestGeneratedHash(t *testing.T) {
- goCmd(nil, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
- goCmd(nil, "test", "-linkshared", "./issue30768")
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
+ goCmd(t, "test", "-linkshared", "./issue30768")
}
// Test that packages can be added not in dependency order (here a depends on b, and a adds
@@ -1070,3 +1083,11 @@ func TestIssue44031(t *testing.T) {
goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/b")
goCmd(t, "run", "-linkshared", "./issue44031/main")
}
+
+// Test that we use a variable from shared libraries (which implement an
+// interface in shared libraries.). A weak reference is used in the itab
+// in main process. It can cause unreacheble panic. See issue 47873.
+func TestIssue47873(t *testing.T) {
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue47837/a")
+ goCmd(t, "run", "-linkshared", "./issue47837/main")
+}
diff --git a/libgo/misc/cgo/testshared/testdata/issue47837/a/a.go b/libgo/misc/cgo/testshared/testdata/issue47837/a/a.go
new file mode 100644
index 00000000000..68588eda2fa
--- /dev/null
+++ b/libgo/misc/cgo/testshared/testdata/issue47837/a/a.go
@@ -0,0 +1,19 @@
+// Copyright 2021 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 a
+
+type A interface {
+ M()
+}
+
+//go:noinline
+func TheFuncWithArgA(a A) {
+ a.M()
+}
+
+type ImplA struct{}
+
+//go:noinline
+func (A *ImplA) M() {}
diff --git a/libgo/misc/cgo/testshared/testdata/issue47837/main/main.go b/libgo/misc/cgo/testshared/testdata/issue47837/main/main.go
new file mode 100644
index 00000000000..77c6f343793
--- /dev/null
+++ b/libgo/misc/cgo/testshared/testdata/issue47837/main/main.go
@@ -0,0 +1,14 @@
+// Copyright 2021 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 (
+ "testshared/issue47837/a"
+)
+
+func main() {
+ var vara a.ImplA
+ a.TheFuncWithArgA(&vara)
+}
diff --git a/libgo/misc/cgo/testso/noso_test.go b/libgo/misc/cgo/testso/noso_test.go
index c88aebfb02a..1014534d62c 100644
--- a/libgo/misc/cgo/testso/noso_test.go
+++ b/libgo/misc/cgo/testso/noso_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !cgo
// +build !cgo
package so_test
diff --git a/libgo/misc/cgo/testsovar/noso_test.go b/libgo/misc/cgo/testsovar/noso_test.go
index c88aebfb02a..1014534d62c 100644
--- a/libgo/misc/cgo/testsovar/noso_test.go
+++ b/libgo/misc/cgo/testsovar/noso_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !cgo
// +build !cgo
package so_test
diff --git a/libgo/misc/cgo/testtls/tls_test.go b/libgo/misc/cgo/testtls/tls_test.go
index 3076c2d5943..a3b67c00441 100644
--- a/libgo/misc/cgo/testtls/tls_test.go
+++ b/libgo/misc/cgo/testtls/tls_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !windows
// +build !windows
package cgotlstest