doc/go1.20.html | 29 ++++++++++++++++++-----------
doc/go_spec.html | 240 ++++++++++++++++++++++++++++++++++++++++-------------
misc/cgo/testsanitizers/cc_test.go | 30 +++++++++++++++++++++++++++---
misc/cgo/testsanitizers/libfuzzer_test.go | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
misc/cgo/testsanitizers/testdata/libfuzzer1.go | 16 ++++++++++++++++
misc/cgo/testsanitizers/testdata/libfuzzer2.c | 11 +++++++++++
misc/cgo/testsanitizers/testdata/libfuzzer2.go | 16 ++++++++++++++++
misc/cgo/testshared/shared_test.go | 12 ++++++++++++
src/archive/tar/reader.go | 9 ---------
src/archive/zip/reader.go | 11 -----------
src/cmd/compile/internal/devirtualize/devirtualize.go | 3 +++
src/cmd/compile/internal/ssa/_gen/ARM64.rules | 4 ++--
src/cmd/compile/internal/ssa/_gen/LOONG64.rules | 3 ++-
src/cmd/compile/internal/ssa/_gen/MIPS64.rules | 3 ++-
src/cmd/compile/internal/ssa/_gen/PPC64.rules | 4 ++--
src/cmd/compile/internal/ssa/_gen/PPC64Ops.go | 4 ++--
src/cmd/compile/internal/ssa/_gen/RISCV64.rules | 2 +-
src/cmd/compile/internal/ssa/rewriteARM64.go | 6 +++---
src/cmd/compile/internal/ssa/rewriteLOONG64.go | 24 ++++++++++++++++++++++--
src/cmd/compile/internal/ssa/rewriteMIPS64.go | 24 ++++++++++++++++++++++--
src/cmd/compile/internal/ssa/rewritePPC64.go | 25 ++++++++++++++++---------
src/cmd/compile/internal/ssa/rewriteRISCV64.go | 24 ++++++++++++++++++++++--
src/cmd/compile/internal/types2/expr.go | 36 ++++++++++++++++++++++++++++++------
src/cmd/compile/internal/types2/infer.go | 40 ++++++++++++++--------------------------
src/cmd/compile/internal/types2/typeset.go | 2 +-
src/cmd/covdata/tool_test.go | 35 +++++++++++++++++++----------------
src/cmd/cover/cover.go | 3 ---
src/cmd/go/internal/test/test.go | 2 +-
src/cmd/go/terminal_test.go | 57 ++++++++++++++++++++++++++++++++---------------------
src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt | 4 ++--
src/cmd/go/testdata/script/cover_main_import_path.txt | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/cmd/go/testdata/script/test2json_interrupt.txt | 29 ++++++++++++++++-------------
src/cmd/link/internal/amd64/obj.go | 2 +-
src/cmd/link/internal/ld/data.go | 12 ++++++------
src/cmd/link/internal/ld/elf.go | 2 +-
src/crypto/x509/internal/macos/corefoundation.go | 7 +++++++
src/crypto/x509/internal/macos/corefoundation.s | 2 ++
src/crypto/x509/internal/macos/security.go | 19 ++++++++++++++-----
src/crypto/x509/root_darwin.go | 14 ++++++++++++--
src/crypto/x509/root_darwin_test.go | 10 +++++-----
src/debug/buildinfo/buildinfo.go | 4 +++-
src/debug/buildinfo/buildinfo_test.go | 12 ++++++++++++
src/go/types/expr.go | 36 ++++++++++++++++++++++++++++++------
src/go/types/infer.go | 40 ++++++++++++++--------------------------
src/go/types/typeset.go | 2 +-
src/internal/poll/sock_cloexec.go | 2 +-
src/internal/poll/sock_cloexec_accept.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/internal/safefilepath/path_other.go | 2 +-
src/internal/types/errors/codes.go | 2 +-
src/internal/types/testdata/fixedbugs/issue57155.go | 14 ++++++++++++++
src/internal/types/testdata/fixedbugs/issue57160.go | 10 ++++++++++
src/internal/types/testdata/fixedbugs/issue57486.go | 29 +++++++++++++++++++++++++++++
src/net/cgo_unix.go | 5 +++--
src/net/cgo_unix_cgo.go | 1 +
src/net/http/httputil/reverseproxy.go | 30 ++++++++++--------------------
src/net/http/httputil/reverseproxy_test.go | 47 ++---------------------------------------------
src/net/http/transport_test.go | 18 +++++++++++++-----
src/os/exec/lp_linux_test.go | 17 +++++++++++++++--
src/os/os_test.go | 11 +++++------
src/os/user/cgo_lookup_cgo.go | 38 ++++++++++++++++++++++----------------
src/os/user/cgo_lookup_unix.go | 4 ++++
src/runtime/coverage/emitdata_test.go | 9 ++++++---
src/runtime/coverage/testsupport.go | 15 +++++++++++++--
src/runtime/internal/atomic/atomic_test.go | 30 ++++++++++++++++++++++++++++++
src/runtime/internal/startlinetest/func_amd64.go | 3 +++
src/runtime/internal/startlinetest/func_amd64.s | 3 ++-
src/runtime/libfuzzer.go | 9 ++-------
src/runtime/mfinal_test.go | 26 +++++---------------------
src/runtime/os_darwin.go | 2 --
src/runtime/race/internal/amd64v1/doc.go | 2 ++
src/runtime/race/internal/amd64v3/doc.go | 2 ++
src/runtime/race/race_v1_amd64.go | 1 -
src/runtime/race/race_v3_amd64.go | 1 -
src/runtime/start_line_amd64_test.go | 2 ++
src/runtime/string_test.go | 27 +++++++++++++++++++++++++++
src/runtime/sys_darwin.go | 48 ------------------------------------------------
src/runtime/sys_darwin_amd64.s | 9 ---------
src/runtime/sys_darwin_arm64.s | 6 ------
src/sync/map_bench_test.go | 1 -
src/syscall/exec_freebsd.go | 2 +-
src/syscall/exec_libc2.go | 4 ++--
src/syscall/exec_linux.go | 6 +++---
src/syscall/exec_linux_test.go | 4 +++-
src/syscall/exec_plan9.go | 2 +-
src/syscall/syscall_darwin.go | 32 ++++++++++++++++++++++++++++++--
src/syscall/syscall_linux.go | 29 ++++++++++++-----------------
src/syscall/syscall_linux_accept.go | 34 ++++++++++++++++++++++++++++++++++
src/syscall/syscall_linux_accept4.go | 25 +++++++++++++++++++++++++
src/syscall/syscall_openbsd_libc.go | 6 +++++-
src/syscall/zsyscall_darwin_amd64.go | 22 ++++++++++++++++++----
src/syscall/zsyscall_darwin_amd64.s | 6 ++++--
src/syscall/zsyscall_darwin_arm64.go | 22 ++++++++++++++++++----
src/syscall/zsyscall_darwin_arm64.s | 6 ++++--
src/syscall/zsyscall_linux_arm.go | 13 ++++++++++++-
src/testing/testing.go | 5 +++--
test/fixedbugs/issue57184.go | 40 ++++++++++++++++++++++++++++++++++++++++
test/fixedbugs/issue57309.go | 23 +++++++++++++++++++++++
diff --git a/doc/go1.20.html b/doc/go1.20.html
index 28d3c8224dbbf005464e76bc9d102551454b902e..aec3e25285958993fa5af18540230f27c45c8388 100644
--- a/doc/go1.20.html
+++ b/doc/go1.20.html
@@ -30,7 +30,7 @@ Go 1.20 includes four changes to the language.
- Go 1.17 added conversions from slice to an array pointer.
+ Go 1.17 added conversions from slice to an array pointer.
Go 1.20 extends this to allow conversions from a slice to an array:
given a slice x, [4]byte(x) can now be written
instead of *(*[4]byte)(x).
@@ -67,9 +67,16 @@
Ports
+Windows
+
+
+ Go 1.20 is the last release that will run on any release of Windows 7, 8, Server 2008 and Server 2012.
+ Go 1.21 will require at least Windows 10 or Server 2016.
+
+
Darwin and iOS
-
+
Go 1.20 is the last release that will run on macOS 10.13 High Sierra or 10.14 Mojave.
Go 1.21 will require macOS 10.15 Catalina or later.
@@ -102,9 +109,9 @@ has been improved to make it more robust.
Programs that run go test -json
do not need any updates.
Programs that invoke go tool test2json
- directly should now run the test binary with -v=json
- (for example, go test -v=json
- or ./pkg.test -test.v=json)
+ directly should now run the test binary with -v=test2json
+ (for example, go test -v=test2json
+ or ./pkg.test -test.v=test2json)
instead of plain -v.
@@ -285,7 +292,7 @@
The runtime now has experimental support for memory-safe arena allocation
that makes it possible to eagerly free memory in bulk.
- When used appopriately, it has the potential to improve CPU performance by
+ When used appropriately, it has the potential to improve CPU performance by
up to 15% in memory-allocation-heavy applications.
To try it out, build your Go program with GOEXPERIMENT=arenas,
which will make the arena package visible to your program.
@@ -308,7 +315,7 @@
Go 1.20 adds a new runtime/coverage package
containing APIs for writing coverage profile data at
- runtime from a long-running and/or server programs that
+ runtime from long-running and/or server programs that
do not terminate via os.Exit().
@@ -374,7 +381,7 @@ previous versions of Go looked for a Go 1.4 or later bootstrap toolchain in the directory
$HOME/go1.4 (%HOMEDRIVE%%HOMEPATH%\go1.4 on Windows).
Go 1.18 and Go 1.19 looked first for $HOME/go1.17 or $HOME/sdk/go1.17
before falling back to $HOME/go1.4,
- in ancitipation of requiring Go 1.17 for use when bootstrapping Go 1.20.
+ in anticipation of requiring Go 1.17 for use when bootstrapping Go 1.20.
Go 1.20 does require a Go 1.17 release for bootstrapping, but we realized that we should
adopt the latest point release of the bootstrap toolchain, so it requires Go 1.17.13.
Go 1.20 looks for $HOME/go1.17.13 or $HOME/sdk/go1.17.13
@@ -417,7 +424,7 @@ have been updated to inspect multiply wrapped errors.
The fmt.Errorf function
- now supports multiple occurrances of the %w format verb,
+ now supports multiple occurrences of the %w format verb,
which will cause it to return an error that wraps all of those error operands.
@@ -808,7 +815,7 @@
The new Satisfies function reports
whether a type satisfies a constraint.
This change aligns with the new language semantics
- that distinguish satsifying a constraint from implementing an interface.
+ that distinguish satisfying a constraint from implementing an interface.
@@ -883,7 +890,7 @@ when using the pure Go resolver, LookupCNAME would return an error
if a CNAME record referred to a name that with no A,
AAAA, or CNAME record. This change modifies
LookupCNAME to match the previous behavior on Windows,
- allowing allowing LookupCNAME to succeed whenever a
+ allowing LookupCNAME to succeed whenever a
CNAME exists.
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 3bc610fb020ae25cebe447d03c6abd98772c3ce8..f93f2ab9f17f629e0245e0b38157a954f7d19eb3 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
@@ -944,6 +944,29 @@ [3][5]int
[2][2][2]float64 // same as [2]([2]([2]float64))
+
+An array type T may not have an element of type T,
+or of a type containing T as a component, directly or indirectly,
+if those containing types are only array or struct types.
+
+
+
+// invalid array types
+type (
+ T1 [10]T1 // element type of T1 is T1
+ T2 [10]struct{ f T2 } // T2 contains T2 as component of a struct
+ T3 [10]T4 // T3 contains T3 as component of a struct in T4
+ T4 struct{ f T3 } // T4 contains T4 as component of array T3 in a struct
+)
+
+// valid array types
+type (
+ T5 [10]*T5 // T5 contains T5 as component of a pointer
+ T6 [10]func() T6 // T6 contains T6 as component of a function type
+ T7 [10]struct{ f []T7 } // T7 contains T7 as component of a slice in a struct
+)
+
+
Slice types
@@ -1134,6 +1157,29 @@ struct {
microsec uint64 `protobuf:"1"`
serverIP6 uint64 `protobuf:"2"`
}
+
+
+
+A struct type T may not contain a field of type T,
+or of a type containing T as a component, directly or indirectly,
+if those containing types are only array or struct types.
+
+
+
+// invalid struct types
+type (
+ T1 struct{ T1 } // T1 contains a field of T1
+ T2 struct{ f [10]T2 } // T2 contains T2 as component of an array
+ T3 struct{ T4 } // T3 contains T3 as component of an array in struct T4
+ T4 struct{ f [10]T3 } // T4 contains T4 as component of struct T3 in an array
+)
+
+// valid struct types
+type (
+ T5 struct{ f *T5 } // T5 contains T5 as component of a pointer
+ T6 struct{ f func() T6 } // T6 contains T6 as component of a function type
+ T7 struct{ f [10][]T7 } // T7 contains T7 as component of a slice in an array
+)
Pointer types
@@ -1511,17 +1557,17 @@ }
-An interface type T may not embed any type element
-that is, contains, or embeds T, recursively.
+An interface type T may not embed a type element
+that is, contains, or embeds T, directly or indirectly.
-// illegal: Bad cannot embed itself
+// illegal: Bad may not embed itself
type Bad interface {
Bad
}
-// illegal: Bad1 cannot embed itself using Bad2
+// illegal: Bad1 may not embed itself using Bad2
type Bad1 interface {
Bad2
}
@@ -1529,10 +1575,15 @@ type Bad2 interface {
Bad1
}
-// illegal: Bad3 cannot embed a union containing Bad3
+// illegal: Bad3 may not embed a union containing Bad3
type Bad3 interface {
~int | ~string | Bad3
}
+
+// illegal: Bad4 may not embed an array containing Bad4 as element type
+type Bad4 interface {
+ [10]Bad4
+}
Implementing an interface
@@ -2644,15 +2695,26 @@ of a method declaration associated
with a generic type.
-
+
+Within a type parameter list of a generic type T, a type constraint
+may not (directly, or indirectly through the type parameter list of another
+generic type) refer to T.
+
+
+
+type T1[P T1[P]] … // illegal: T1 refers to itself
+type T2[P interface{ T2[int] }] … // illegal: T2 refers to itself
+type T3[P interface{ m(T3[int])}] … // illegal: T3 refers to itself
+type T4[P T5[P]] … // illegal: T4 refers to T5 and
+type T5[P T4[P]] … // T5 refers to T4
+
+type T6[P int] struct{ f *T6[P] } // ok: reference to T6 is not in type parameter list
+
Type constraints
-A type constraint is an interface that defines the
+A type constraint is an interface that defines the
set of permissible type arguments for the respective type parameter and controls the
operations supported by values of that type parameter.
@@ -2663,7 +2725,7 @@
If the constraint is an interface literal of the form interface{E} where
-E is an embedded type element (not a method), in a type parameter list
+E is an embedded type element (not a method), in a type parameter list
the enclosing interface{ … } may be omitted for convenience:
@@ -2671,7 +2733,7 @@
[T []P] // = [T interface{[]P}]
[T ~int] // = [T interface{~int}]
[T int|string] // = [T interface{int|string}]
-type Constraint ~int // illegal: ~int is not inside a type parameter list
+type Constraint ~int // illegal: ~int is not in a type parameter list
diff --git a/misc/cgo/testsanitizers/cc_test.go b/misc/cgo/testsanitizers/cc_test.go
index af85f99325cc097c115b1d27a315c936adfdf607..8eda1372f6ca9c15a7b6dcec475facf768510a13 100644
--- a/misc/cgo/testsanitizers/cc_test.go
+++ b/misc/cgo/testsanitizers/cc_test.go
@@ -353,6 +353,9 @@ c.goFlags = append(c.goFlags, "-asan")
// Set the debug mode to print the C stack trace.
c.cFlags = append(c.cFlags, "-g")
+ case "fuzzer":
+ c.goFlags = append(c.goFlags, "-tags=libfuzzer", "-gcflags=-d=libfuzzer")
+
default:
panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer))
}
@@ -405,6 +408,13 @@ return 0;
}
`)
+var cLibFuzzerInput = []byte(`
+#include
+int LLVMFuzzerTestOneInput(char *data, size_t size) {
+ return 0;
+}
+`)
+
func (c *config) checkCSanitizer() (skip bool, err error) {
dir, err := os.MkdirTemp("", c.sanitizer)
if err != nil {
@@ -413,7 +423,12 @@ }
defer os.RemoveAll(dir)
src := filepath.Join(dir, "return0.c")
- if err := os.WriteFile(src, cMain, 0600); err != nil {
+ cInput := cMain
+ if c.sanitizer == "fuzzer" {
+ // libFuzzer generates the main function itself, and uses a different input.
+ cInput = cLibFuzzerInput
+ }
+ if err := os.WriteFile(src, cInput, 0600); err != nil {
return false, fmt.Errorf("failed to write C source file: %v", err)
}
@@ -432,6 +447,11 @@ bytes.Contains(out, []byte("unsupported"))) {
return true, errors.New(string(out))
}
return true, fmt.Errorf("%#q failed: %v\n%s", strings.Join(cmd.Args, " "), err, out)
+ }
+
+ if c.sanitizer == "fuzzer" {
+ // For fuzzer, don't try running the test binary. It never finishes.
+ return false, nil
}
if out, err := exec.Command(dst).CombinedOutput(); err != nil {
@@ -505,6 +525,10 @@ t.Fatalf("Failed to remove temp dir: %v", err)
}
}
+func (d *tempDir) Base() string {
+ return d.base
+}
+
func (d *tempDir) Join(name string) string {
return filepath.Join(d.base, name)
}
@@ -535,7 +559,7 @@ return cmd
}
// mSanSupported is a copy of the function cmd/internal/sys.MSanSupported,
-// because the internal pacakage can't be used here.
+// because the internal package can't be used here.
func mSanSupported(goos, goarch string) bool {
switch goos {
case "linux":
@@ -548,7 +572,7 @@ }
}
// aSanSupported is a copy of the function cmd/internal/sys.ASanSupported,
-// because the internal pacakage can't be used here.
+// because the internal package can't be used here.
func aSanSupported(goos, goarch string) bool {
switch goos {
case "linux":
diff --git a/misc/cgo/testsanitizers/libfuzzer_test.go b/misc/cgo/testsanitizers/libfuzzer_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..345751b9c761ffd2f4d7451802051d5b8ac53d5c
--- /dev/null
+++ b/misc/cgo/testsanitizers/libfuzzer_test.go
@@ -0,0 +1,91 @@
+// Copyright 2022 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 TestLibFuzzer(t *testing.T) {
+ goos, err := goEnv("GOOS")
+ if err != nil {
+ t.Fatal(err)
+ }
+ goarch, err := goEnv("GOARCH")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !libFuzzerSupported(goos, goarch) {
+ t.Skipf("skipping on %s/%s; libfuzzer option is not supported.", goos, goarch)
+ }
+ config := configure("fuzzer")
+ config.skipIfCSanitizerBroken(t)
+
+ cases := []struct {
+ goSrc string
+ cSrc string
+ expectedError string
+ }{
+ {goSrc: "libfuzzer1.go", expectedError: "panic: found it"},
+ {goSrc: "libfuzzer2.go", cSrc: "libfuzzer2.c", expectedError: "panic: found it"},
+ }
+ for _, tc := range cases {
+ tc := tc
+ name := strings.TrimSuffix(tc.goSrc, ".go")
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+
+ dir := newTempDir(t)
+ defer dir.RemoveAll(t)
+
+ // build Go code in libfuzzer mode to a c-archive
+ outPath := dir.Join(name)
+ archivePath := dir.Join(name + ".a")
+ mustRun(t, config.goCmd("build", "-buildmode=c-archive", "-o", archivePath, srcPath(tc.goSrc)))
+
+ // build C code (if any) and link with Go code
+ cmd, err := cc(config.cFlags...)
+ if err != nil {
+ t.Fatalf("error running cc: %v", err)
+ }
+ cmd.Args = append(cmd.Args, config.ldFlags...)
+ cmd.Args = append(cmd.Args, "-o", outPath, "-I", dir.Base())
+ if tc.cSrc != "" {
+ cmd.Args = append(cmd.Args, srcPath(tc.cSrc))
+ }
+ cmd.Args = append(cmd.Args, archivePath)
+ mustRun(t, cmd)
+
+ cmd = hangProneCmd(outPath)
+ cmd.Dir = dir.Base()
+ outb, err := cmd.CombinedOutput()
+ out := string(outb)
+ if err == nil {
+ t.Fatalf("fuzzing succeeded unexpectedly; output:\n%s", out)
+ }
+ if !strings.Contains(out, tc.expectedError) {
+ t.Errorf("exited without expected error %q; got\n%s", tc.expectedError, out)
+ }
+ })
+ }
+}
+
+// libFuzzerSupported is a copy of the function internal/platform.FuzzInstrumented,
+// because the internal package can't be used here.
+func libFuzzerSupported(goos, goarch string) bool {
+ switch goarch {
+ case "amd64", "arm64":
+ // TODO(#14565): support more architectures.
+ switch goos {
+ case "darwin", "freebsd", "linux", "windows":
+ return true
+ default:
+ return false
+ }
+ default:
+ return false
+ }
+}
diff --git a/misc/cgo/testsanitizers/testdata/libfuzzer1.go b/misc/cgo/testsanitizers/testdata/libfuzzer1.go
new file mode 100644
index 0000000000000000000000000000000000000000..d178fb1ca0a3059a64a1f3c7307a876bd43946b4
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/libfuzzer1.go
@@ -0,0 +1,16 @@
+package main
+
+import "C"
+
+import "unsafe"
+
+//export LLVMFuzzerTestOneInput
+func LLVMFuzzerTestOneInput(p unsafe.Pointer, sz C.int) C.int {
+ b := C.GoBytes(p, sz)
+ if len(b) >= 6 && b[0] == 'F' && b[1] == 'u' && b[2] == 'z' && b[3] == 'z' && b[4] == 'M' && b[5] == 'e' {
+ panic("found it")
+ }
+ return 0
+}
+
+func main() {}
diff --git a/misc/cgo/testsanitizers/testdata/libfuzzer2.c b/misc/cgo/testsanitizers/testdata/libfuzzer2.c
new file mode 100644
index 0000000000000000000000000000000000000000..567ff5a1cccac5796183601002336decf82847ee
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/libfuzzer2.c
@@ -0,0 +1,11 @@
+#include
+
+#include "libfuzzer2.h"
+
+int LLVMFuzzerTestOneInput(char *data, size_t size) {
+ if (size > 0 && data[0] == 'H')
+ if (size > 1 && data[1] == 'I')
+ if (size > 2 && data[2] == '!')
+ FuzzMe(data, size);
+ return 0;
+}
diff --git a/misc/cgo/testsanitizers/testdata/libfuzzer2.go b/misc/cgo/testsanitizers/testdata/libfuzzer2.go
new file mode 100644
index 0000000000000000000000000000000000000000..c7a43259768574af6d00368632777d82703de13d
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/libfuzzer2.go
@@ -0,0 +1,16 @@
+package main
+
+import "C"
+
+import "unsafe"
+
+//export FuzzMe
+func FuzzMe(p unsafe.Pointer, sz C.int) {
+ b := C.GoBytes(p, sz)
+ b = b[3:]
+ if len(b) >= 4 && b[0] == 'f' && b[1] == 'u' && b[2] == 'z' && b[3] == 'z' {
+ panic("found it")
+ }
+}
+
+func main() {}
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
index cd8a144d73aa82c54c45e3068ac2aad0877eed89..b14fb1cb3a7b79d7cfafa4e29bd59790b89866e9 100644
--- a/misc/cgo/testshared/shared_test.go
+++ b/misc/cgo/testshared/shared_test.go
@@ -1105,3 +1105,15 @@ func TestIssue47873(t *testing.T) {
goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue47837/a")
goCmd(t, "run", "-linkshared", "./issue47837/main")
}
+
+// Test that we can build std in shared mode.
+func TestStd(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skip in short mode")
+ }
+ t.Parallel()
+ // Use a temporary pkgdir to not interfere with other tests, and not write to GOROOT.
+ // Cannot use goCmd as it runs with cloned GOROOT which is incomplete.
+ runWithEnv(t, "building std", []string{"GOROOT=" + oldGOROOT},
+ filepath.Join(oldGOROOT, "bin", "go"), "install", "-buildmode=shared", "-pkgdir="+t.TempDir(), "std")
+}
diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go
index 52a3150fc4f023f47da6fedda406711321b72401..82a5a5a293b9157d498576703c1b29fc2e86accc 100644
--- a/src/archive/tar/reader.go
+++ b/src/archive/tar/reader.go
@@ -45,15 +45,6 @@ // The Header.Size determines how many bytes can be read for the next file.
// Any remaining data in the current file is automatically discarded.
//
// io.EOF is returned at the end of the input.
-//
-// ErrInsecurePath and a valid *Header are returned if the next file's name is:
-//
-// - absolute;
-// - a relative path escaping the current directory, such as "../a"; or
-// - on Windows, a reserved file name such as "NUL".
-//
-// The caller may ignore the ErrInsecurePath error,
-// but is then responsible for sanitizing paths as appropriate.
func (tr *Reader) Next() (*Header, error) {
if tr.err != nil {
return nil, tr.err
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index 10e835fe86059972fb6b9bd5df43c1f383a525d3..a2ae74e541e366f6a3dd56490a0a3de2c9ed74e0 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -87,17 +87,6 @@ }
// NewReader returns a new Reader reading from r, which is assumed to
// have the given size in bytes.
-//
-// ErrInsecurePath and a valid *Reader are returned if the names of any
-// files in the archive:
-//
-// - are absolute;
-// - are a relative path escaping the current directory, such as "../a";
-// - contain a backslash (\) character; or
-// - on Windows, are a reserved file name such as "NUL".
-//
-// The caller may ignore the ErrInsecurePath error,
-// but is then responsible for sanitizing paths as appropriate.
func NewReader(r io.ReaderAt, size int64) (*Reader, error) {
if size < 0 {
return nil, errors.New("zip: size cannot be negative")
diff --git a/src/cmd/compile/internal/devirtualize/devirtualize.go b/src/cmd/compile/internal/devirtualize/devirtualize.go
index 7350a6f1714417df2392bff87eae0408b260b352..554e935c3e4072f54bc40e9519b416e52e0acf6f 100644
--- a/src/cmd/compile/internal/devirtualize/devirtualize.go
+++ b/src/cmd/compile/internal/devirtualize/devirtualize.go
@@ -152,4 +152,7 @@ call.SetType(ft.Results().Field(0).Type)
default:
call.SetType(ft.Results())
}
+
+ // Desugar OCALLMETH, if we created one (#57309).
+ typecheck.FixMethodCall(call)
}
diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64.rules b/src/cmd/compile/internal/ssa/_gen/ARM64.rules
index 727204d80a7405c2dc1b66658f16c9709df08658..0c5a2e66a8ca7545d0d2187c145fc1dd77aa4a2e 100644
--- a/src/cmd/compile/internal/ssa/_gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/ARM64.rules
@@ -342,9 +342,9 @@ (FCMPS (FMOVSconst [0]) x) => (InvertFlags (FCMPS0 x))
(FCMPD x (FMOVDconst [0])) => (FCMPD0 x)
(FCMPD (FMOVDconst [0]) x) => (InvertFlags (FCMPD0 x))
-// CSEL needs a flag-generating argument. Synthesize a CMPW if necessary.
+// CSEL needs a flag-generating argument. Synthesize a TSTW if necessary.
(CondSelect x y boolval) && flagArg(boolval) != nil => (CSEL [boolval.Op] x y flagArg(boolval))
-(CondSelect x y boolval) && flagArg(boolval) == nil => (CSEL [OpARM64NotEqual] x y (CMPWconst [0] boolval))
+(CondSelect x y boolval) && flagArg(boolval) == nil => (CSEL [OpARM64NotEqual] x y (TSTWconst [1] boolval))
(OffPtr [off] ptr:(SP)) && is32Bit(off) => (MOVDaddr [int32(off)] ptr)
(OffPtr [off] ptr) => (ADDconst [off] ptr)
diff --git a/src/cmd/compile/internal/ssa/_gen/LOONG64.rules b/src/cmd/compile/internal/ssa/_gen/LOONG64.rules
index 2810f0afe12a468c5a283b06f9a4295e0ae5e8ca..1caaf13600d47429d337281e42b00e8ae3ee2374 100644
--- a/src/cmd/compile/internal/ssa/_gen/LOONG64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/LOONG64.rules
@@ -400,7 +400,8 @@ (AtomicExchange(32|64) ...) => (LoweredAtomicExchange(32|64) ...)
(AtomicAdd(32|64) ...) => (LoweredAtomicAdd(32|64) ...)
-(AtomicCompareAndSwap(32|64) ...) => (LoweredAtomicCas(32|64) ...)
+(AtomicCompareAndSwap32 ptr old new mem) => (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
+(AtomicCompareAndSwap64 ...) => (LoweredAtomicCas64 ...)
// checks
(NilCheck ...) => (LoweredNilCheck ...)
diff --git a/src/cmd/compile/internal/ssa/_gen/MIPS64.rules b/src/cmd/compile/internal/ssa/_gen/MIPS64.rules
index 17634afd729d2c45b383380acab337a7ce653d82..a594df2b266838bfcbd677f5f4fb5b383b81f00a 100644
--- a/src/cmd/compile/internal/ssa/_gen/MIPS64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/MIPS64.rules
@@ -392,7 +392,8 @@ (AtomicExchange(32|64) ...) => (LoweredAtomicExchange(32|64) ...)
(AtomicAdd(32|64) ...) => (LoweredAtomicAdd(32|64) ...)
-(AtomicCompareAndSwap(32|64) ...) => (LoweredAtomicCas(32|64) ...)
+(AtomicCompareAndSwap32 ptr old new mem) => (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
+(AtomicCompareAndSwap64 ...) => (LoweredAtomicCas64 ...)
// checks
(NilCheck ...) => (LoweredNilCheck ...)
diff --git a/src/cmd/compile/internal/ssa/_gen/PPC64.rules b/src/cmd/compile/internal/ssa/_gen/PPC64.rules
index aee53d4f0fa206860cbec11564d86b926d2a770d..5a68de0ca4dadff18c19b4c37b09094998b9ecee 100644
--- a/src/cmd/compile/internal/ssa/_gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/PPC64.rules
@@ -409,9 +409,9 @@ ((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(OR x y)) yes no) && z.Uses == 1 => ((EQ|NE|LT|LE|GT|GE) (Select1 (ORCC x y)) yes no)
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(XOR x y)) yes no) && z.Uses == 1 => ((EQ|NE|LT|LE|GT|GE) (Select1 (XORCC x y)) yes no)
// Only lower after bool is lowered. It should always lower. This helps ensure the folding below happens reliably.
-(CondSelect x y bool) && flagArg(bool) == nil => (ISEL [6] x y (CMPWconst [0] bool))
+(CondSelect x y bool) && flagArg(bool) == nil => (ISEL [6] x y (Select1 (ANDCCconst [1] bool)))
// Fold any CR -> GPR -> CR transfers when applying the above rule.
-(ISEL [6] x y (CMPWconst [0] (ISELB [c] one cmp))) => (ISEL [c] x y cmp)
+(ISEL [6] x y (Select1 (ANDCCconst [1] (ISELB [c] one cmp)))) => (ISEL [c] x y cmp)
// Lowering loads
(Load ptr mem) && (is64BitInt(t) || isPtr(t)) => (MOVDload ptr mem)
diff --git a/src/cmd/compile/internal/ssa/_gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/_gen/PPC64Ops.go
index baa783e30b7515aba4e5eb4edfdfd782ccfec3bd..2d651dd780332eb885ec20ef7ac33b926fdacbf5 100644
--- a/src/cmd/compile/internal/ssa/_gen/PPC64Ops.go
+++ b/src/cmd/compile/internal/ssa/_gen/PPC64Ops.go
@@ -8,8 +8,8 @@ import "strings"
// Notes:
// - Less-than-64-bit integer types live in the low portion of registers.
-// For now, the upper portion is junk; sign/zero-extension might be optimized in the future, but not yet.
-// - Boolean types are zero or 1; stored in a byte, but loaded with AMOVBZ so the upper bytes of a register are zero.
+// The upper portion is junk.
+// - Boolean types are zero or 1; stored in a byte, with upper bytes of the register containing junk.
// - *const instructions may use a constant larger than the instruction can encode.
// In this case the assembler expands to multiple instructions and uses tmp
// register (R31).
diff --git a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
index 78c3375e2d60c849a9418bd5f113d73f9c0898f4..59f71be5bafd6e88a990024390729610c7f890af 100644
--- a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
@@ -577,7 +577,7 @@ (SLLI [3] (ANDI [3] ptr)))) mem)
(AtomicAnd32 ...) => (LoweredAtomicAnd32 ...)
-(AtomicCompareAndSwap32 ...) => (LoweredAtomicCas32 ...)
+(AtomicCompareAndSwap32 ptr old new mem) => (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
(AtomicCompareAndSwap64 ...) => (LoweredAtomicCas64 ...)
(AtomicExchange32 ...) => (LoweredAtomicExchange32 ...)
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index d7386729e7c9f44e636e40ad6e9ab2d4b94f9758..e82a49c33193e782e36729b0623c2434acd54260 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -23561,7 +23561,7 @@ return true
}
// match: (CondSelect x y boolval)
// cond: flagArg(boolval) == nil
- // result: (CSEL [OpARM64NotEqual] x y (CMPWconst [0] boolval))
+ // result: (CSEL [OpARM64NotEqual] x y (TSTWconst [1] boolval))
for {
x := v_0
y := v_1
@@ -23571,8 +23571,8 @@ break
}
v.reset(OpARM64CSEL)
v.AuxInt = opToAuxInt(OpARM64NotEqual)
- v0 := b.NewValue0(v.Pos, OpARM64CMPWconst, types.TypeFlags)
- v0.AuxInt = int32ToAuxInt(0)
+ v0 := b.NewValue0(v.Pos, OpARM64TSTWconst, types.TypeFlags)
+ v0.AuxInt = int32ToAuxInt(1)
v0.AddArg(boolval)
v.AddArg3(x, y, v0)
return true
diff --git a/src/cmd/compile/internal/ssa/rewriteLOONG64.go b/src/cmd/compile/internal/ssa/rewriteLOONG64.go
index 26d6594fef3fc8f1c8095d6a4dd92b3b64df2c07..f6da0b7ff0bd97711ac73560be6346bb20e5f0a4 100644
--- a/src/cmd/compile/internal/ssa/rewriteLOONG64.go
+++ b/src/cmd/compile/internal/ssa/rewriteLOONG64.go
@@ -52,8 +52,7 @@ case OpAtomicAdd64:
v.Op = OpLOONG64LoweredAtomicAdd64
return true
case OpAtomicCompareAndSwap32:
- v.Op = OpLOONG64LoweredAtomicCas32
- return true
+ return rewriteValueLOONG64_OpAtomicCompareAndSwap32(v)
case OpAtomicCompareAndSwap64:
v.Op = OpLOONG64LoweredAtomicCas64
return true
@@ -702,6 +701,27 @@ base := v_0
v.reset(OpLOONG64MOVVaddr)
v.Aux = symToAux(sym)
v.AddArg(base)
+ return true
+ }
+}
+func rewriteValueLOONG64_OpAtomicCompareAndSwap32(v *Value) bool {
+ v_3 := v.Args[3]
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (AtomicCompareAndSwap32 ptr old new mem)
+ // result: (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
+ for {
+ ptr := v_0
+ old := v_1
+ new := v_2
+ mem := v_3
+ v.reset(OpLOONG64LoweredAtomicCas32)
+ v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
+ v0.AddArg(old)
+ v.AddArg4(ptr, v0, new, mem)
return true
}
}
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
index 998b27dbb57bcda4597748c99c7b48e125312d06..c0d42b55f51ced071634c02b3df48f21ac2b0e44 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
@@ -52,8 +52,7 @@ case OpAtomicAdd64:
v.Op = OpMIPS64LoweredAtomicAdd64
return true
case OpAtomicCompareAndSwap32:
- v.Op = OpMIPS64LoweredAtomicCas32
- return true
+ return rewriteValueMIPS64_OpAtomicCompareAndSwap32(v)
case OpAtomicCompareAndSwap64:
v.Op = OpMIPS64LoweredAtomicCas64
return true
@@ -694,6 +693,27 @@ base := v_0
v.reset(OpMIPS64MOVVaddr)
v.Aux = symToAux(sym)
v.AddArg(base)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAtomicCompareAndSwap32(v *Value) bool {
+ v_3 := v.Args[3]
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (AtomicCompareAndSwap32 ptr old new mem)
+ // result: (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
+ for {
+ ptr := v_0
+ old := v_1
+ new := v_2
+ mem := v_3
+ v.reset(OpMIPS64LoweredAtomicCas32)
+ v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
+ v0.AddArg(old)
+ v.AddArg4(ptr, v0, new, mem)
return true
}
}
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 8b5ea14757afc8eefa8d2b0167f6290735c12c56..bc593128daf4ca6d1149f2700a2e952427e79895 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -1172,9 +1172,10 @@ v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
+ typ := &b.Func.Config.Types
// match: (CondSelect x y bool)
// cond: flagArg(bool) == nil
- // result: (ISEL [6] x y (CMPWconst [0] bool))
+ // result: (ISEL [6] x y (Select1 (ANDCCconst [1] bool)))
for {
x := v_0
y := v_1
@@ -1184,9 +1185,11 @@ break
}
v.reset(OpPPC64ISEL)
v.AuxInt = int32ToAuxInt(6)
- v0 := b.NewValue0(v.Pos, OpPPC64CMPWconst, types.TypeFlags)
- v0.AuxInt = int32ToAuxInt(0)
- v0.AddArg(bool)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.NewTuple(typ.Int, types.TypeFlags))
+ v1.AuxInt = int64ToAuxInt(1)
+ v1.AddArg(bool)
+ v0.AddArg(v1)
v.AddArg3(x, y, v0)
return true
}
@@ -5355,7 +5358,7 @@ v0.AddArg(y)
v.AddArg(v0)
return true
}
- // match: (ISEL [6] x y (CMPWconst [0] (ISELB [c] one cmp)))
+ // match: (ISEL [6] x y (Select1 (ANDCCconst [1] (ISELB [c] one cmp))))
// result: (ISEL [c] x y cmp)
for {
if auxIntToInt32(v.AuxInt) != 6 {
@@ -5363,15 +5366,19 @@ break
}
x := v_0
y := v_1
- if v_2.Op != OpPPC64CMPWconst || auxIntToInt32(v_2.AuxInt) != 0 {
+ if v_2.Op != OpSelect1 {
break
}
v_2_0 := v_2.Args[0]
- if v_2_0.Op != OpPPC64ISELB {
+ if v_2_0.Op != OpPPC64ANDCCconst || auxIntToInt64(v_2_0.AuxInt) != 1 {
break
}
- c := auxIntToInt32(v_2_0.AuxInt)
- cmp := v_2_0.Args[1]
+ v_2_0_0 := v_2_0.Args[0]
+ if v_2_0_0.Op != OpPPC64ISELB {
+ break
+ }
+ c := auxIntToInt32(v_2_0_0.AuxInt)
+ cmp := v_2_0_0.Args[1]
v.reset(OpPPC64ISEL)
v.AuxInt = int32ToAuxInt(c)
v.AddArg3(x, y, cmp)
diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
index f94e90f01ad82faa8e985dbc281d727029866235..961230d8bb320c8503696c62b94356f5395b92cb 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -61,8 +61,7 @@ return true
case OpAtomicAnd8:
return rewriteValueRISCV64_OpAtomicAnd8(v)
case OpAtomicCompareAndSwap32:
- v.Op = OpRISCV64LoweredAtomicCas32
- return true
+ return rewriteValueRISCV64_OpAtomicCompareAndSwap32(v)
case OpAtomicCompareAndSwap64:
v.Op = OpRISCV64LoweredAtomicCas64
return true
@@ -773,6 +772,27 @@ v5.AddArg(v6)
v2.AddArg2(v3, v5)
v1.AddArg(v2)
v.AddArg3(v0, v1, mem)
+ return true
+ }
+}
+func rewriteValueRISCV64_OpAtomicCompareAndSwap32(v *Value) bool {
+ v_3 := v.Args[3]
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (AtomicCompareAndSwap32 ptr old new mem)
+ // result: (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
+ for {
+ ptr := v_0
+ old := v_1
+ new := v_2
+ mem := v_3
+ v.reset(OpRISCV64LoweredAtomicCas32)
+ v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
+ v0.AddArg(old)
+ v.AddArg4(ptr, v0, new, mem)
return true
}
}
diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go
index 40d6e5da695228dd7fbc613624bae6e202cc2eb9..9a0348e0250a4fbd9441d47c292bfc805083b132 100644
--- a/src/cmd/compile/internal/types2/expr.go
+++ b/src/cmd/compile/internal/types2/expr.go
@@ -1103,26 +1103,50 @@ check.shift(x, &y, e, op)
return
}
- // TODO(gri) make canMix more efficient - called for each binary operation
- canMix := func(x, y *operand) bool {
+ // mayConvert reports whether the operands x and y may
+ // possibly have matching types after converting one
+ // untyped operand to the type of the other.
+ // If mayConvert returns true, we try to convert the
+ // operands to each other's types, and if that fails
+ // we report a conversion failure.
+ // If mayConvert returns false, we continue without an
+ // attempt at conversion, and if the operand types are
+ // not compatible, we report a type mismatch error.
+ mayConvert := func(x, y *operand) bool {
+ // If both operands are typed, there's no need for an implicit conversion.
+ if isTyped(x.typ) && isTyped(y.typ) {
+ return false
+ }
+ // An untyped operand may convert to its default type when paired with an empty interface
+ // TODO(gri) This should only matter for comparisons (the only binary operation that is
+ // valid with interfaces), but in that case the assignability check should take
+ // care of the conversion. Verify and possibly eliminate this extra test.
if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) {
return true
}
+ // A boolean type can only convert to another boolean type.
if allBoolean(x.typ) != allBoolean(y.typ) {
return false
}
+ // A string type can only convert to another string type.
if allString(x.typ) != allString(y.typ) {
return false
}
- if x.isNil() && !hasNil(y.typ) {
- return false
+ // Untyped nil can only convert to a type that has a nil.
+ if x.isNil() {
+ return hasNil(y.typ)
}
- if y.isNil() && !hasNil(x.typ) {
+ if y.isNil() {
+ return hasNil(x.typ)
+ }
+ // An untyped operand cannot convert to a pointer.
+ // TODO(gri) generalize to type parameters
+ if isPointer(x.typ) || isPointer(y.typ) {
return false
}
return true
}
- if canMix(x, &y) {
+ if mayConvert(x, &y) {
check.convertUntyped(x, y.typ)
if x.mode == invalid {
return
diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go
index 1075457acaf097664114704ec4c442c38f6d35f3..5750ece32f55ab70abcc45b6b55002dcb731373e 100644
--- a/src/cmd/compile/internal/types2/infer.go
+++ b/src/cmd/compile/internal/types2/infer.go
@@ -89,34 +89,22 @@ // func f2[P interface{*Q}, Q any](p P, q Q) {
// f(p)
// }
//
- // We can turn the first example into the second example by renaming type
- // parameters in the original signature to give them a new identity. As an
- // optimization, we do this only for self-recursive calls.
-
- // We can detect if we are in a self-recursive call by comparing the
- // identity of the first type parameter in the current function with the
- // first type parameter in tparams. This works because type parameters are
- // unique to their type parameter list.
- selfRecursive := check.sig != nil && check.sig.tparams.Len() > 0 && tparams[0] == check.sig.tparams.At(0)
-
- if selfRecursive {
- // In self-recursive inference, rename the type parameters with new type
- // parameters that are the same but for their pointer identity.
- tparams2 := make([]*TypeParam, len(tparams))
- for i, tparam := range tparams {
- tname := NewTypeName(tparam.Obj().Pos(), tparam.Obj().Pkg(), tparam.Obj().Name(), nil)
- tparams2[i] = NewTypeParam(tname, nil)
- tparams2[i].index = tparam.index // == i
- }
-
- renameMap := makeRenameMap(tparams, tparams2)
- for i, tparam := range tparams {
- tparams2[i].bound = check.subst(pos, tparam.bound, renameMap, nil, check.context())
- }
+ // We turn the first example into the second example by renaming type
+ // parameters in the original signature to give them a new identity.
+ tparams2 := make([]*TypeParam, len(tparams))
+ for i, tparam := range tparams {
+ tname := NewTypeName(tparam.Obj().Pos(), tparam.Obj().Pkg(), tparam.Obj().Name(), nil)
+ tparams2[i] = NewTypeParam(tname, nil)
+ tparams2[i].index = tparam.index // == i
+ }
- tparams = tparams2
- params = check.subst(pos, params, renameMap, nil, check.context()).(*Tuple)
+ renameMap := makeRenameMap(tparams, tparams2)
+ for i, tparam := range tparams {
+ tparams2[i].bound = check.subst(pos, tparam.bound, renameMap, nil, check.context())
}
+
+ tparams = tparams2
+ params = check.subst(pos, params, renameMap, nil, check.context()).(*Tuple)
}
// If we have more than 2 arguments, we may have arguments with named and unnamed types.
diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go
index 391ea8cd79541db7f0eb8b11f93c5926142d37ba..673cadca902058625a517b87e11617ea39f805c3 100644
--- a/src/cmd/compile/internal/types2/typeset.go
+++ b/src/cmd/compile/internal/types2/typeset.go
@@ -352,7 +352,7 @@ // only keep comparable terms
i := 0
for _, t := range terms {
assert(t.typ != nil)
- if Comparable(t.typ) {
+ if comparable(t.typ, false /* strictly comparable */, nil, nil) {
terms[i] = t
i++
}
diff --git a/src/cmd/covdata/tool_test.go b/src/cmd/covdata/tool_test.go
index 9396266776b57ab4899816d8b3f3cdcd553461dd..42334eae9499be7b4924d7b72304ee198894e6b8 100644
--- a/src/cmd/covdata/tool_test.go
+++ b/src/cmd/covdata/tool_test.go
@@ -111,6 +111,8 @@ t.Fatalf("writing %q: %v", dst, err)
}
}
+const mainPkgPath = "prog"
+
func buildProg(t *testing.T, prog string, dir string, tag string, flags []string) (string, string) {
// Create subdirs.
subdir := filepath.Join(dir, prog+"dir"+tag)
@@ -132,7 +134,7 @@ emitFile(t, dep, indep)
// Emit go.mod.
mod := filepath.Join(subdir, "go.mod")
- modsrc := "\nmodule prog\n\ngo 1.19\n"
+ modsrc := "\nmodule " + mainPkgPath + "\n\ngo 1.19\n"
if err := os.WriteFile(mod, []byte(modsrc), 0666); err != nil {
t.Fatal(err)
}
@@ -305,7 +307,7 @@ }
func testDump(t *testing.T, s state) {
// Run the dumper on the two dirs we generated.
- dargs := []string{"-pkg=main", "-live", "-i=" + s.outdirs[0] + "," + s.outdirs[1]}
+ dargs := []string{"-pkg=" + mainPkgPath, "-live", "-i=" + s.outdirs[0] + "," + s.outdirs[1]}
lines := runToolOp(t, s, "debugdump", dargs)
// Sift through the output to make sure it has some key elements.
@@ -319,7 +321,7 @@ regexp.MustCompile(`^data file .+ GOOS=.+ GOARCH=.+ program args: .+$`),
},
{
"main package",
- regexp.MustCompile(`^Package path: main\s*$`),
+ regexp.MustCompile(`^Package path: ` + mainPkgPath + `\s*$`),
},
{
"main function",
@@ -337,7 +339,7 @@ break
}
}
if !found {
- t.Errorf("dump output regexp match failed for %s", testpoint.tag)
+ t.Errorf("dump output regexp match failed for %q", testpoint.tag)
bad = true
}
}
@@ -348,7 +350,7 @@ }
func testPercent(t *testing.T, s state) {
// Run the dumper on the two dirs we generated.
- dargs := []string{"-pkg=main", "-i=" + s.outdirs[0] + "," + s.outdirs[1]}
+ dargs := []string{"-pkg=" + mainPkgPath, "-i=" + s.outdirs[0] + "," + s.outdirs[1]}
lines := runToolOp(t, s, "percent", dargs)
// Sift through the output to make sure it has the needful.
@@ -380,11 +382,12 @@ if bad {
dumplines(lines)
}
}
+
func testPkgList(t *testing.T, s state) {
dargs := []string{"-i=" + s.outdirs[0] + "," + s.outdirs[1]}
lines := runToolOp(t, s, "pkglist", dargs)
- want := []string{"main", "prog/dep"}
+ want := []string{mainPkgPath, mainPkgPath + "/dep"}
bad := false
if len(lines) != 2 {
t.Errorf("expect pkglist to return two lines")
@@ -405,7 +408,7 @@ }
func testTextfmt(t *testing.T, s state) {
outf := s.dir + "/" + "t.txt"
- dargs := []string{"-pkg=main", "-i=" + s.outdirs[0] + "," + s.outdirs[1],
+ dargs := []string{"-pkg=" + mainPkgPath, "-i=" + s.outdirs[0] + "," + s.outdirs[1],
"-o", outf}
lines := runToolOp(t, s, "textfmt", dargs)
@@ -426,7 +429,7 @@ if lines[0] != want0 {
dumplines(lines[0:10])
t.Errorf("textfmt: want %s got %s", want0, lines[0])
}
- want1 := "prog/prog1.go:13.14,15.2 1 1"
+ want1 := mainPkgPath + "/prog1.go:13.14,15.2 1 1"
if lines[1] != want1 {
dumplines(lines[0:10])
t.Errorf("textfmt: want %s got %s", want1, lines[1])
@@ -571,7 +574,7 @@ re: regexp.MustCompile(`^2: L24:C12 -- L26:C3 NS=1 = (\d+)$`),
nonzero: true,
},
}
- flags := []string{"-live", "-pkg=main"}
+ flags := []string{"-live", "-pkg=" + mainPkgPath}
runDumpChecks(t, s, outdir, flags, testpoints)
}
@@ -585,7 +588,7 @@ // Merge two input dirs into a final result, but filter
// based on package.
ins := fmt.Sprintf("-i=%s,%s", indir1, indir2)
out := fmt.Sprintf("-o=%s", outdir)
- margs := []string{"-pkg=prog/dep", ins, out}
+ margs := []string{"-pkg=" + mainPkgPath + "/dep", ins, out}
lines := runToolOp(t, s, "merge", margs)
if len(lines) != 0 {
t.Errorf("merge run produced %d lines of unexpected output", len(lines))
@@ -600,9 +603,9 @@ if len(lines) == 0 {
t.Fatalf("dump run produced no output")
}
want := map[string]int{
- "Package path: prog/dep": 0,
- "Func: Dep1": 0,
- "Func: PDep": 0,
+ "Package path: " + mainPkgPath + "/dep": 0,
+ "Func: Dep1": 0,
+ "Func: PDep": 0,
}
bad := false
for _, line := range lines {
@@ -696,7 +699,7 @@ re: regexp.MustCompile(`^Func: sixth\s*$`),
},
}
- flags := []string{"-live", "-pkg=main"}
+ flags := []string{"-live", "-pkg=" + mainPkgPath}
runDumpChecks(t, s, moutdir, flags, testpoints)
}
@@ -717,7 +720,7 @@ t.Errorf("subtract run produced unexpected output: %+v", lines)
}
// Dump the files in the subtract output dir and examine the result.
- dargs := []string{"-pkg=main", "-live", "-i=" + soutdir}
+ dargs := []string{"-pkg=" + mainPkgPath, "-live", "-i=" + soutdir}
lines = runToolOp(t, s, "debugdump", dargs)
if len(lines) == 0 {
t.Errorf("dump run produced no output")
@@ -774,7 +777,7 @@ t.Errorf("intersect run produced unexpected output: %+v", lines)
}
// Dump the files in the subtract output dir and examine the result.
- dargs := []string{"-pkg=main", "-live", "-i=" + ioutdir}
+ dargs := []string{"-pkg=" + mainPkgPath, "-live", "-i=" + ioutdir}
lines = runToolOp(t, s, "debugdump", dargs)
if len(lines) == 0 {
t.Errorf("dump run produced no output")
diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go
index 989c109a79ab6d9734480d13b66ea65229bde6f9..f4f225ef20859cfb02fa774f303d2d1dd54266f8 100644
--- a/src/cmd/cover/cover.go
+++ b/src/cmd/cover/cover.go
@@ -542,9 +542,6 @@ var p *Package
if *pkgcfg != "" {
pp := pkgconfig.PkgPath
pn := pkgconfig.PkgName
- if pn == "main" {
- pp = "main"
- }
mp := pkgconfig.ModulePath
mdb, err := encodemeta.NewCoverageMetaDataBuilder(pp, pn, mp)
if err != nil {
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 5a5600982941a15b328da17e46656f51062483e1..0051970cfc65a3a2c7879e88a5bedaaedadde086 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -1306,6 +1306,7 @@ }
cmd.Env = env
}
+ base.StartSigHandlers()
t0 := time.Now()
err = cmd.Start()
@@ -1314,7 +1315,6 @@ // stop wedged test binaries, to keep the builders
// running.
if err == nil {
tick := time.NewTimer(testKillTimeout)
- base.StartSigHandlers()
done := make(chan error)
go func() {
done <- cmd.Wait()
diff --git a/src/cmd/go/terminal_test.go b/src/cmd/go/terminal_test.go
index 03ca7727007514cd3c957365186aad4d1a557f3a..a5ad9191c2a470880d4e12d36bd964364055eab6 100644
--- a/src/cmd/go/terminal_test.go
+++ b/src/cmd/go/terminal_test.go
@@ -71,31 +71,37 @@ cmd := testenv.Command(t, testGo, "test", "-run=^$")
cmd.Env = append(cmd.Environ(), "GO_TEST_TERMINAL_PASSTHROUGH=1")
cmd.Stdout = w
cmd.Stderr = w
+
+ // The behavior of reading from a PTY after the child closes it is very
+ // strange: on Linux, Read returns EIO, and on at least some versions of
+ // macOS, unread output may be discarded (see https://go.dev/issue/57141).
+ //
+ // To avoid that situation, we keep the child process running until the
+ // parent has finished reading from the PTY, at which point we unblock the
+ // child by closing its stdin pipe.
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+
t.Logf("running %s", cmd)
- err := cmd.Start()
+ err = cmd.Start()
if err != nil {
t.Fatalf("starting subprocess: %s", err)
}
w.Close()
- // Read the subprocess output. The behavior of reading from a PTY after the
- // child closes it is very strange (e.g., on Linux, read returns EIO), so we
- // ignore errors as long as we get everything we need. We still try to read
- // all of the output so we can report it in case of failure.
- buf, err := io.ReadAll(r)
- if len(buf) != 2 || !(buf[0] == '1' || buf[0] == 'X') || !(buf[1] == '2' || buf[1] == 'X') {
- t.Errorf("expected exactly 2 bytes matching [1X][2X]")
- if err != nil {
- // An EIO here might be expected depending on OS.
- t.Errorf("error reading from subprocess: %s", err)
+ t.Cleanup(func() {
+ stdin.Close()
+ if err := cmd.Wait(); err != nil {
+ t.Errorf("suprocess failed with: %s", err)
}
- }
- err = cmd.Wait()
- if err != nil {
- t.Errorf("suprocess failed with: %s", err)
- }
- if t.Failed() {
- t.Logf("subprocess output:\n%s", string(buf))
- t.FailNow()
+ })
+
+ buf := make([]byte, 2)
+ n, err := io.ReadFull(r, buf)
+ if err != nil || !(buf[0] == '1' || buf[0] == 'X') || !(buf[1] == '2' || buf[1] == 'X') {
+ t.Logf("read error: %v", err)
+ t.Fatalf("expected 2 bytes matching `[1X][2X]`; got %q", buf[:n])
}
return buf[0] == '1', buf[1] == '2'
}
@@ -106,14 +112,19 @@ return
}
if term.IsTerminal(1) {
- print("1")
+ os.Stdout.WriteString("1")
} else {
- print("X")
+ os.Stdout.WriteString("X")
}
if term.IsTerminal(2) {
- print("2")
+ os.Stdout.WriteString("2")
} else {
- print("X")
+ os.Stdout.WriteString("X")
}
+
+ // Before exiting, wait for the parent process to read the PTY output,
+ // at which point it will close stdin.
+ io.Copy(io.Discard, os.Stdin)
+
os.Exit(0)
}
diff --git a/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt b/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt
index 4748a85f5ef32124a8d779aad0a330d1f2970aba..ba382639e9cdf2e82d5f500afa541e2b456fc1bf 100644
--- a/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt
+++ b/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt
@@ -26,7 +26,7 @@
# Check to make sure we instrumented just the main package, not
# any dependencies.
go tool covdata pkglist -i=$WORK/covdata
-stdout main
+stdout cmd/nm
! stdout cmd/internal/goobj pkglist.txt
# ... now collect a coverage profile from a Go file
@@ -41,7 +41,7 @@ env GOCOVERDIR=$SAVEGOCOVERDIR
# Check to make sure we instrumented just the main package.
go tool covdata pkglist -i=$WORK/covdata2
-stdout main
+stdout command-line-arguments
! stdout fmt
-- go.mod --
diff --git a/src/cmd/go/testdata/script/cover_main_import_path.txt b/src/cmd/go/testdata/script/cover_main_import_path.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3a2f3c3ee28feeaf37bac3821e934fc865c7c975
--- /dev/null
+++ b/src/cmd/go/testdata/script/cover_main_import_path.txt
@@ -0,0 +1,54 @@
+
+# This test is intended to verify that coverage reporting is consistent
+# between "go test -cover" and "go build -cover" with respect to how
+# the "main" package is handled. See issue 57169 for details.
+
+[short] skip
+
+# Build this program with -cover and run to collect a profile.
+
+go build -cover -o $WORK/prog.exe .
+
+# Save off old GOCOVERDIR setting
+env SAVEGOCOVERDIR=$GOCOVERDIR
+
+mkdir $WORK/covdata
+env GOCOVERDIR=$WORK/covdata
+exec $WORK/prog.exe
+
+# Restore previous GOCOVERDIR setting
+env GOCOVERDIR=$SAVEGOCOVERDIR
+
+# Report percent lines covered.
+go tool covdata percent -i=$WORK/covdata
+stdout '\s*mainwithtest\s+coverage:'
+! stdout 'main\s+coverage:'
+
+# Go test -cover should behave the same way.
+go test -cover .
+stdout 'ok\s+mainwithtest\s+\S+\s+coverage:'
+! stdout 'ok\s+main\s+.*'
+
+
+-- go.mod --
+module mainwithtest
+
+go 1.20
+-- mymain.go --
+package main
+
+func main() {
+ println("hi mom")
+}
+
+func Mainer() int {
+ return 42
+}
+-- main_test.go --
+package main
+
+import "testing"
+
+func TestCoverage(t *testing.T) {
+ println(Mainer())
+}
diff --git a/src/cmd/go/testdata/script/test2json_interrupt.txt b/src/cmd/go/testdata/script/test2json_interrupt.txt
index 5828e86136792bb4d3f33c53a1c0d6dc3ffda687..763c3369914226e32632c684eb8f229aa1f09892 100644
--- a/src/cmd/go/testdata/script/test2json_interrupt.txt
+++ b/src/cmd/go/testdata/script/test2json_interrupt.txt
@@ -7,8 +7,8 @@ stdout -count=1 '"Action":"pass","Package":"example","Test":"FuzzInterrupt"'
stdout -count=1 '"Action":"pass","Package":"example","Elapsed":'
mkdir $WORK/fuzzcache
-go test -c . -fuzz=. -o test2json_interrupt_obj
-? go tool test2json -p example -t ./test2json_interrupt_obj -test.v -test.paniconexit0 -test.fuzzcachedir $WORK/fuzzcache -test.fuzz FuzzInterrupt -test.run '^$' -test.parallel 1
+go test -c . -fuzz=. -o example_test.exe
+? go tool test2json -p example -t ./example_test.exe -test.v -test.paniconexit0 -test.fuzzcachedir $WORK/fuzzcache -test.fuzz FuzzInterrupt -test.run '^$' -test.parallel 1
stdout -count=1 '"Action":"pass","Package":"example","Test":"FuzzInterrupt"'
stdout -count=1 '"Action":"pass","Package":"example","Elapsed":'
@@ -37,19 +37,22 @@ ppid := os.Getppid()
os.Setenv("GO_TEST_INTERRUPT_PIDS", fmt.Sprintf("%d,%d", ppid, pid))
}
+ sentInterrupt := false
f.Fuzz(func(t *testing.T, orig string) {
- // Simulate a ctrl-C on the keyboard by sending SIGINT
- // to the main test process and its parent.
- for _, pid := range strings.Split(pids, ",") {
- i, err := strconv.Atoi(pid)
- if err != nil {
- t.Fatal(err)
- }
- if p, err := os.FindProcess(i); err == nil {
- p.Signal(os.Interrupt)
- time.Sleep(10 * time.Millisecond)
- pids = "" // Only interrupt once.
+ if !sentInterrupt {
+ // Simulate a ctrl-C on the keyboard by sending SIGINT
+ // to the main test process and its parent.
+ for _, pid := range strings.Split(pids, ",") {
+ i, err := strconv.Atoi(pid)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if p, err := os.FindProcess(i); err == nil {
+ p.Signal(os.Interrupt)
+ sentInterrupt = true // Only send interrupts once.
+ }
}
}
+ time.Sleep(1 * time.Millisecond) // Delay the fuzzer a bit to avoid wasting CPU.
})
}
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index f46045bc9dd9e33096b7be96fcebe3e2e115dbbc..c5e2117f90af110bd4b80201d5abf7e78e80be9c 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -65,7 +65,7 @@ PEreloc1: pereloc1,
TLSIEtoLE: tlsIEtoLE,
Linuxdynld: "/lib64/ld-linux-x86-64.so.2",
- LinuxdynldMusl: "/lib/ld-musl-x84_64.so.1",
+ LinuxdynldMusl: "/lib/ld-musl-x86_64.so.1",
Freebsddynld: "/libexec/ld-elf.so.1",
Openbsddynld: "/usr/libexec/ld.so",
Netbsddynld: "/libexec/ld.elf_so",
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index faae153babc899a3c1b767b92531ef316c16fb37..94f8fc32d6e2d61bedc2ffd1571efc9dbe4e7ff9 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -1860,9 +1860,9 @@ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.ecovctrs", 0), sect)
// Coverage instrumentation counters for libfuzzer.
if len(state.data[sym.SLIBFUZZER_8BIT_COUNTER]) > 0 {
- sect := state.allocateNamedSectionAndAssignSyms(&Segdata, "__sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, sym.Sxxx, 06)
- ldr.SetSymSect(ldr.LookupOrCreateSym("__start___sancov_cntrs", 0), sect)
- ldr.SetSymSect(ldr.LookupOrCreateSym("__stop___sancov_cntrs", 0), sect)
+ sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".go.fuzzcntrs", sym.SLIBFUZZER_8BIT_COUNTER, sym.Sxxx, 06)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.__start___sancov_cntrs", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.__stop___sancov_cntrs", 0), sect)
ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._counters", 0), sect)
ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._ecounters", 0), sect)
}
@@ -2643,7 +2643,7 @@ case ".bss":
bss = s
case ".noptrbss":
noptrbss = s
- case "__sancov_cntrs":
+ case ".go.fuzzcntrs":
fuzzCounters = s
}
}
@@ -2764,8 +2764,8 @@ ctxt.xdefine("runtime.ecovctrs", sym.SCOVERAGE_COUNTER, int64(noptrbss.Vaddr+covCounterDataStartOff+covCounterDataLen))
ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
if fuzzCounters != nil {
- ctxt.xdefine("__start___sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr))
- ctxt.xdefine("__stop___sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
+ ctxt.xdefine("runtime.__start___sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr))
+ ctxt.xdefine("runtime.__stop___sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
ctxt.xdefine("internal/fuzz._counters", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr))
ctxt.xdefine("internal/fuzz._ecounters", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 082adcc3c7f7a8ec2e7ae74ad01ffb0462432c9f..a1ae7eab57fe96f670a9759145a94f51b8e092ea 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -1371,7 +1371,7 @@ shstrtab.Addstring(".noptrdata")
shstrtab.Addstring(".data")
shstrtab.Addstring(".bss")
shstrtab.Addstring(".noptrbss")
- shstrtab.Addstring("__sancov_cntrs")
+ shstrtab.Addstring(".go.fuzzcntrs")
shstrtab.Addstring(".go.buildinfo")
if ctxt.IsMIPS() {
shstrtab.Addstring(".MIPS.abiflags")
diff --git a/src/crypto/x509/internal/macos/corefoundation.go b/src/crypto/x509/internal/macos/corefoundation.go
index 5387c5a015834ecb6c74b4bc82e5ec8de6399c7d..b4032a5d91c2a0ebbf73468000c220a69eb21082 100644
--- a/src/crypto/x509/internal/macos/corefoundation.go
+++ b/src/crypto/x509/internal/macos/corefoundation.go
@@ -186,6 +186,13 @@ return CFRef(ret)
}
func x509_CFErrorCopyDescription_trampoline()
+//go:cgo_import_dynamic x509_CFErrorGetCode CFErrorGetCode "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFErrorGetCode(errRef CFRef) int {
+ return int(syscall(abi.FuncPCABI0(x509_CFErrorGetCode_trampoline), uintptr(errRef), 0, 0, 0, 0, 0))
+}
+func x509_CFErrorGetCode_trampoline()
+
//go:cgo_import_dynamic x509_CFStringCreateExternalRepresentation CFStringCreateExternalRepresentation "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
func CFStringCreateExternalRepresentation(strRef CFRef) (CFRef, error) {
diff --git a/src/crypto/x509/internal/macos/corefoundation.s b/src/crypto/x509/internal/macos/corefoundation.s
index d69f72f795cd949504851c32a9b4be7599076f59..49cd084467b2c396e22cb2a06c983c6966dc8d7c 100644
--- a/src/crypto/x509/internal/macos/corefoundation.s
+++ b/src/crypto/x509/internal/macos/corefoundation.s
@@ -37,5 +37,7 @@ TEXT ·x509_CFDataCreate_trampoline(SB),NOSPLIT,$0-0
JMP x509_CFDataCreate(SB)
TEXT ·x509_CFErrorCopyDescription_trampoline(SB),NOSPLIT,$0-0
JMP x509_CFErrorCopyDescription(SB)
+TEXT ·x509_CFErrorGetCode_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFErrorGetCode(SB)
TEXT ·x509_CFStringCreateExternalRepresentation_trampoline(SB),NOSPLIT,$0-0
JMP x509_CFStringCreateExternalRepresentation(SB)
diff --git a/src/crypto/x509/internal/macos/security.go b/src/crypto/x509/internal/macos/security.go
index 0fc218c552da279a89e1d7ee331aa9b6b544bdf1..a6972c0c09dfe28ee44b167145d0d912f0a3ca02 100644
--- a/src/crypto/x509/internal/macos/security.go
+++ b/src/crypto/x509/internal/macos/security.go
@@ -8,7 +8,6 @@ package macOS
import (
"errors"
- "fmt"
"internal/abi"
"strconv"
"unsafe"
@@ -50,6 +49,15 @@ const (
SecTrustSettingsDomainUser SecTrustSettingsDomain = iota
SecTrustSettingsDomainAdmin
SecTrustSettingsDomainSystem
+)
+
+const (
+ // various macOS error codes that can be returned from
+ // SecTrustEvaluateWithError that we can map to Go cert
+ // verification error types.
+ ErrSecCertificateExpired = -67818
+ ErrSecHostNameMismatch = -67602
+ ErrSecNotTrusted = -67843
)
type OSStatus struct {
@@ -191,17 +199,18 @@ func x509_SecTrustGetResult_trampoline()
//go:cgo_import_dynamic x509_SecTrustEvaluateWithError SecTrustEvaluateWithError "/System/Library/Frameworks/Security.framework/Versions/A/Security"
-func SecTrustEvaluateWithError(trustObj CFRef) error {
+func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
var errRef CFRef
ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluateWithError_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&errRef)), 0, 0, 0, 0)
if int32(ret) != 1 {
errStr := CFErrorCopyDescription(errRef)
- err := fmt.Errorf("x509: %s", CFStringToString(errStr))
+ err := errors.New(CFStringToString(errStr))
+ errCode := CFErrorGetCode(errRef)
CFRelease(errRef)
CFRelease(errStr)
- return err
+ return errCode, err
}
- return nil
+ return 0, nil
}
func x509_SecTrustEvaluateWithError_trampoline()
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
index 20f627c27707007124101db61bb19df4907e0b19..de2ff894a92aa2d4e552a2945344c62e0c6e2d89 100644
--- a/src/crypto/x509/root_darwin.go
+++ b/src/crypto/x509/root_darwin.go
@@ -7,6 +7,7 @@
import (
macOS "crypto/x509/internal/macos"
"errors"
+ "fmt"
)
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
@@ -57,8 +58,17 @@ // set them via SecTrustSetSignedCertificateTimestamps, since Apple will
// always enforce its SCT requirements, and there are still _some_ people
// using TLS or OCSP for that.
- if err := macOS.SecTrustEvaluateWithError(trustObj); err != nil {
- return nil, err
+ if ret, err := macOS.SecTrustEvaluateWithError(trustObj); err != nil {
+ switch ret {
+ case macOS.ErrSecCertificateExpired:
+ return nil, CertificateInvalidError{c, Expired, err.Error()}
+ case macOS.ErrSecHostNameMismatch:
+ return nil, HostnameError{c, opts.DNSName}
+ case macOS.ErrSecNotTrusted:
+ return nil, UnknownAuthorityError{Cert: c}
+ default:
+ return nil, fmt.Errorf("x509: %s", err)
+ }
}
chain := [][]*Certificate{{}}
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index 90a464f624960a75bd39d390d7e1d492a499a511..299cecf5563f682a2f18f1d51b440c0329d7b41c 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -42,23 +42,23 @@ },
{
name: "expired leaf",
host: "expired.badssl.com",
- expectedErr: "x509: “*.badssl.com” certificate is expired",
+ expectedErr: "x509: certificate has expired or is not yet valid: “*.badssl.com” certificate is expired",
},
{
name: "wrong host for leaf",
host: "wrong.host.badssl.com",
verifyName: "wrong.host.badssl.com",
- expectedErr: "x509: “*.badssl.com” certificate name does not match input",
+ expectedErr: "x509: certificate is valid for *.badssl.com, badssl.com, not wrong.host.badssl.com",
},
{
name: "self-signed leaf",
host: "self-signed.badssl.com",
- expectedErr: "x509: “*.badssl.com” certificate is not trusted",
+ expectedErr: "x509: certificate signed by unknown authority",
},
{
name: "untrusted root",
host: "untrusted-root.badssl.com",
- expectedErr: "x509: “BadSSL Untrusted Root Certificate Authority” certificate is not trusted",
+ expectedErr: "x509: certificate signed by unknown authority",
},
{
name: "revoked leaf",
@@ -74,7 +74,7 @@ {
name: "expired leaf (custom time)",
host: "google.com",
verifyTime: time.Time{}.Add(time.Hour),
- expectedErr: "x509: “*.google.com” certificate is expired",
+ expectedErr: "x509: certificate has expired or is not yet valid: “*.google.com” certificate is expired",
},
{
name: "valid chain (custom time)",
diff --git a/src/debug/buildinfo/buildinfo.go b/src/debug/buildinfo/buildinfo.go
index 255e6d3d503736da6f5b325263e8cdda4ad5ff74..8bc5753a2d71ce31e71b8856037d8e32dceb2ece 100644
--- a/src/debug/buildinfo/buildinfo.go
+++ b/src/debug/buildinfo/buildinfo.go
@@ -192,8 +192,10 @@ }
var readPtr func([]byte) uint64
if ptrSize == 4 {
readPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) }
- } else {
+ } else if ptrSize == 8 {
readPtr = bo.Uint64
+ } else {
+ return "", "", errNotGoExe
}
vers = readString(x, ptrSize, readPtr, readPtr(data[16:]))
mod = readString(x, ptrSize, readPtr, readPtr(data[16+ptrSize:]))
diff --git a/src/debug/buildinfo/buildinfo_test.go b/src/debug/buildinfo/buildinfo_test.go
index ae04b4cb1dc92c26f20e5c6b885c722fe1d4cef9..290e3705bc32fa3042c52f2e4a6c939d328bfaa3 100644
--- a/src/debug/buildinfo/buildinfo_test.go
+++ b/src/debug/buildinfo/buildinfo_test.go
@@ -248,6 +248,18 @@ })
}
}
+// FuzzIssue57002 is a regression test for golang.org/issue/57002.
+//
+// The cause of issue 57002 is when pointerSize is not being checked,
+// the read can panic with slice bounds out of range
+func FuzzIssue57002(f *testing.F) {
+ // input from issue
+ f.Add([]byte{0x4d, 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x45, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x20, 0x20, 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0x20, 0x3f, 0x0, 0x20, 0x0, 0x0, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb, 0x20, 0x20, 0x20, 0xfc, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x9, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x20, 0x20, 0x20, 0x20, 0xef, 0x20, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, 0x0, 0x2, 0x0, 0x20, 0x0, 0x0, 0x9, 0x0, 0x4, 0x0, 0x20, 0xf6, 0x0, 0xd3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x1, 0x0, 0x0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 0x20, 0xa, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0xff, 0x20, 0x47, 0x6f, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x6e, 0x66, 0x3a, 0xde, 0xb5, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x7f, 0x7f, 0x7f, 0x20, 0xf4, 0xb2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x20, 0x20, 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0x20, 0x3f, 0x27, 0x20, 0x0, 0xd, 0x0, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0, 0x20, 0x20, 0x0, 0x0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20})
+ f.Fuzz(func(t *testing.T, input []byte) {
+ buildinfo.Read(bytes.NewReader(input))
+ })
+}
+
// TestIssue54968 is a regression test for golang.org/issue/54968.
//
// The cause of issue 54968 is when the first buildInfoMagic is invalid, it
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index da9cd67826f6db59326833e157e68229ec87dd80..e09b461d8c6b9c41abcf05bb9bf1fe84129223e7 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -1084,26 +1084,50 @@ check.shift(x, &y, e, op)
return
}
- // TODO(gri) make canMix more efficient - called for each binary operation
- canMix := func(x, y *operand) bool {
+ // mayConvert reports whether the operands x and y may
+ // possibly have matching types after converting one
+ // untyped operand to the type of the other.
+ // If mayConvert returns true, we try to convert the
+ // operands to each other's types, and if that fails
+ // we report a conversion failure.
+ // If mayConvert returns false, we continue without an
+ // attempt at conversion, and if the operand types are
+ // not compatible, we report a type mismatch error.
+ mayConvert := func(x, y *operand) bool {
+ // If both operands are typed, there's no need for an implicit conversion.
+ if isTyped(x.typ) && isTyped(y.typ) {
+ return false
+ }
+ // An untyped operand may convert to its default type when paired with an empty interface
+ // TODO(gri) This should only matter for comparisons (the only binary operation that is
+ // valid with interfaces), but in that case the assignability check should take
+ // care of the conversion. Verify and possibly eliminate this extra test.
if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) {
return true
}
+ // A boolean type can only convert to another boolean type.
if allBoolean(x.typ) != allBoolean(y.typ) {
return false
}
+ // A string type can only convert to another string type.
if allString(x.typ) != allString(y.typ) {
return false
}
- if x.isNil() && !hasNil(y.typ) {
- return false
+ // Untyped nil can only convert to a type that has a nil.
+ if x.isNil() {
+ return hasNil(y.typ)
}
- if y.isNil() && !hasNil(x.typ) {
+ if y.isNil() {
+ return hasNil(x.typ)
+ }
+ // An untyped operand cannot convert to a pointer.
+ // TODO(gri) generalize to type parameters
+ if isPointer(x.typ) || isPointer(y.typ) {
return false
}
return true
}
- if canMix(x, &y) {
+ if mayConvert(x, &y) {
check.convertUntyped(x, y.typ)
if x.mode == invalid {
return
diff --git a/src/go/types/infer.go b/src/go/types/infer.go
index 1c1d4e03fcdf1403d80bd39c505836132f12c323..dc87902c4c31ade806bc19eb3904365af692f4ca 100644
--- a/src/go/types/infer.go
+++ b/src/go/types/infer.go
@@ -89,34 +89,22 @@ // func f2[P interface{*Q}, Q any](p P, q Q) {
// f(p)
// }
//
- // We can turn the first example into the second example by renaming type
- // parameters in the original signature to give them a new identity. As an
- // optimization, we do this only for self-recursive calls.
-
- // We can detect if we are in a self-recursive call by comparing the
- // identity of the first type parameter in the current function with the
- // first type parameter in tparams. This works because type parameters are
- // unique to their type parameter list.
- selfRecursive := check.sig != nil && check.sig.tparams.Len() > 0 && tparams[0] == check.sig.tparams.At(0)
-
- if selfRecursive {
- // In self-recursive inference, rename the type parameters with new type
- // parameters that are the same but for their pointer identity.
- tparams2 := make([]*TypeParam, len(tparams))
- for i, tparam := range tparams {
- tname := NewTypeName(tparam.Obj().Pos(), tparam.Obj().Pkg(), tparam.Obj().Name(), nil)
- tparams2[i] = NewTypeParam(tname, nil)
- tparams2[i].index = tparam.index // == i
- }
-
- renameMap := makeRenameMap(tparams, tparams2)
- for i, tparam := range tparams {
- tparams2[i].bound = check.subst(posn.Pos(), tparam.bound, renameMap, nil, check.context())
- }
+ // We turn the first example into the second example by renaming type
+ // parameters in the original signature to give them a new identity.
+ tparams2 := make([]*TypeParam, len(tparams))
+ for i, tparam := range tparams {
+ tname := NewTypeName(tparam.Obj().Pos(), tparam.Obj().Pkg(), tparam.Obj().Name(), nil)
+ tparams2[i] = NewTypeParam(tname, nil)
+ tparams2[i].index = tparam.index // == i
+ }
- tparams = tparams2
- params = check.subst(posn.Pos(), params, renameMap, nil, check.context()).(*Tuple)
+ renameMap := makeRenameMap(tparams, tparams2)
+ for i, tparam := range tparams {
+ tparams2[i].bound = check.subst(posn.Pos(), tparam.bound, renameMap, nil, check.context())
}
+
+ tparams = tparams2
+ params = check.subst(posn.Pos(), params, renameMap, nil, check.context()).(*Tuple)
}
// If we have more than 2 arguments, we may have arguments with named and unnamed types.
diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go
index 35a32972e0bacbe21ccab51da44397d989dd7fac..d68446df66d7f49f44d97e7e9b0099dcdf715fe3 100644
--- a/src/go/types/typeset.go
+++ b/src/go/types/typeset.go
@@ -350,7 +350,7 @@ // only keep comparable terms
i := 0
for _, t := range terms {
assert(t.typ != nil)
- if Comparable(t.typ) {
+ if comparable(t.typ, false /* strictly comparable */, nil, nil) {
terms[i] = t
i++
}
diff --git a/src/internal/poll/sock_cloexec.go b/src/internal/poll/sock_cloexec.go
index 4fb9f004bbfe4a5d300bd739d0adca3e34390697..f5be2aa5f2634ed24efed3eb338b93d2f361aa01 100644
--- a/src/internal/poll/sock_cloexec.go
+++ b/src/internal/poll/sock_cloexec.go
@@ -5,7 +5,7 @@
// This file implements accept for platforms that provide a fast path for
// setting SetNonblock and CloseOnExec.
-//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris
+//go:build dragonfly || freebsd || (linux && !arm) || netbsd || openbsd || solaris
package poll
diff --git a/src/internal/poll/sock_cloexec_accept.go b/src/internal/poll/sock_cloexec_accept.go
new file mode 100644
index 0000000000000000000000000000000000000000..4b86de59e092997bc7bc99abfedd5e6ad646bc3e
--- /dev/null
+++ b/src/internal/poll/sock_cloexec_accept.go
@@ -0,0 +1,51 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements accept for platforms that provide a fast path for
+// setting SetNonblock and CloseOnExec, but don't necessarily have accept4.
+// This is the code we used for accept in Go 1.17 and earlier.
+// On Linux the accept4 system call was introduced in 2.6.28 kernel,
+// and our minimum requirement is 2.6.32, so we simplified the function.
+// Unfortunately, on ARM accept4 wasn't added until 2.6.36, so for ARM
+// only we continue using the older code.
+
+//go:build linux && arm
+
+package poll
+
+import "syscall"
+
+// Wrapper around the accept system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func accept(s int) (int, syscall.Sockaddr, string, error) {
+ ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+ switch err {
+ case nil:
+ return ns, sa, "", nil
+ default: // errors other than the ones listed
+ return -1, sa, "accept4", err
+ case syscall.ENOSYS: // syscall missing
+ case syscall.EINVAL: // some Linux use this instead of ENOSYS
+ case syscall.EACCES: // some Linux use this instead of ENOSYS
+ case syscall.EFAULT: // some Linux use this instead of ENOSYS
+ }
+
+ // See ../syscall/exec_unix.go for description of ForkLock.
+ // It is probably okay to hold the lock across syscall.Accept
+ // because we have put fd.sysfd into non-blocking mode.
+ // However, a call to the File method will put it back into
+ // blocking mode. We can't take that risk, so no use of ForkLock here.
+ ns, sa, err = AcceptFunc(s)
+ if err == nil {
+ syscall.CloseOnExec(ns)
+ }
+ if err != nil {
+ return -1, nil, "accept", err
+ }
+ if err = syscall.SetNonblock(ns, true); err != nil {
+ CloseFunc(ns)
+ return -1, nil, "setnonblock", err
+ }
+ return ns, sa, "", nil
+}
diff --git a/src/internal/safefilepath/path_other.go b/src/internal/safefilepath/path_other.go
index f93da18680d01c1fc30b8613183905acc20efac1..974e7751a290e682487a89ef1a0e2d963d148928 100644
--- a/src/internal/safefilepath/path_other.go
+++ b/src/internal/safefilepath/path_other.go
@@ -11,7 +11,7 @@
func fromFS(path string) (string, error) {
if runtime.GOOS == "plan9" {
if len(path) > 0 && path[0] == '#' {
- return path, errInvalidPath
+ return "", errInvalidPath
}
}
for i := range path {
diff --git a/src/internal/types/errors/codes.go b/src/internal/types/errors/codes.go
index 7a0c0e16b83929108382fc3567d4c9e35cc189e2..acddcbb9c50deca0acf6130571b50ccf72cc1f31 100644
--- a/src/internal/types/errors/codes.go
+++ b/src/internal/types/errors/codes.go
@@ -882,7 +882,7 @@ // conversion from an untyped value satisfying the type constraints of the
// context in which it is used.
//
// Example:
- // var _ = 1 + new(int)
+ // var _ = 1 + []int{}
InvalidUntypedConversion
// BadOffsetofSyntax occurs when unsafe.Offsetof is called with an argument
diff --git a/src/internal/types/testdata/fixedbugs/issue57155.go b/src/internal/types/testdata/fixedbugs/issue57155.go
new file mode 100644
index 0000000000000000000000000000000000000000..ec9fb2bad3ff57381c0c6c9df3a6a973b4837e21
--- /dev/null
+++ b/src/internal/types/testdata/fixedbugs/issue57155.go
@@ -0,0 +1,14 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f[P *Q, Q any](p P, q Q) {
+ func() {
+ _ = f[P]
+ f(p, q)
+ f[P](p, q)
+ f[P, Q](p, q)
+ }()
+}
diff --git a/src/internal/types/testdata/fixedbugs/issue57160.go b/src/internal/types/testdata/fixedbugs/issue57160.go
new file mode 100644
index 0000000000000000000000000000000000000000..446d019900c2a6c7fdf7a818790aa0286e8c98c8
--- /dev/null
+++ b/src/internal/types/testdata/fixedbugs/issue57160.go
@@ -0,0 +1,10 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func _(x *int) {
+ _ = 0 < x // ERROR "invalid operation"
+ _ = x < 0 // ERROR "invalid operation"
+}
diff --git a/src/internal/types/testdata/fixedbugs/issue57486.go b/src/internal/types/testdata/fixedbugs/issue57486.go
new file mode 100644
index 0000000000000000000000000000000000000000..ff9e3d1db5611699afdb468c7a6deaf85720e89a
--- /dev/null
+++ b/src/internal/types/testdata/fixedbugs/issue57486.go
@@ -0,0 +1,29 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type C1 interface {
+ comparable
+}
+
+type C2 interface {
+ comparable
+ [2]any | int
+}
+
+func G1[T C1](t T) { _ = t == t }
+func G2[T C2](t T) { _ = t == t }
+
+func F1[V [2]any](v V) {
+ _ = G1[V /* ERROR "V does not implement comparable" */]
+ _ = G1[[2]any]
+ _ = G1[int]
+}
+
+func F2[V [2]any](v V) {
+ _ = G2[V /* ERROR "V does not implement C2" */]
+ _ = G2[[ /* ERROR "\[2\]any does not implement C2 \(\[2\]any missing in int\)" */ 2]any]
+ _ = G2[int]
+}
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
index 5b0df56eae8a57bf7266a47215813ad6aa8f37e2..6a2c369c668d0d1dc279a6defe37390346fd1aed 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -383,8 +383,9 @@
s := _C_CString(hostname)
defer _C_FreeCString(s)
+ var size int
for {
- size, _ := _C_res_nsearch(state, s, class, rtype, buf, bufSize)
+ size, _ = _C_res_nsearch(state, s, class, rtype, buf, bufSize)
if size <= 0 || size > 0xffff {
return nil, errors.New("res_nsearch failure")
}
@@ -399,7 +400,7 @@ buf = (*_C_uchar)(_C_malloc(uintptr(bufSize)))
}
var p dnsmessage.Parser
- if _, err := p.Start(unsafe.Slice((*byte)(unsafe.Pointer(buf)), bufSize)); err != nil {
+ if _, err := p.Start(unsafe.Slice((*byte)(unsafe.Pointer(buf)), size)); err != nil {
return nil, err
}
p.SkipAllQuestions()
diff --git a/src/net/cgo_unix_cgo.go b/src/net/cgo_unix_cgo.go
index 3e7282b5794e974d3a626371bae4dfc3f4cdaaa2..97427e695d37594baf90dc77c6ea2990cf05e1e2 100644
--- a/src/net/cgo_unix_cgo.go
+++ b/src/net/cgo_unix_cgo.go
@@ -7,6 +7,7 @@
package net
/*
+#cgo CFLAGS: -fno-stack-protector
#include
#include
#include
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 190279ca007d6c49228ff8d55571184b1276a888..58064a53322627d393d9d183681b21524c99b480 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -131,17 +131,17 @@ // back to the original client unmodified.
// Director must not access the provided Request
// after returning.
//
- // By default, the X-Forwarded-For, X-Forwarded-Host, and
- // X-Forwarded-Proto headers of the ourgoing request are
- // set as by the ProxyRequest.SetXForwarded function.
- //
- // If an X-Forwarded-For header already exists, the client IP is
- // appended to the existing values. To prevent IP spoofing, be
- // sure to delete any pre-existing X-Forwarded-For header
- // coming from the client or an untrusted proxy.
+ // By default, the X-Forwarded-For header is set to the
+ // value of the client IP address. If an X-Forwarded-For
+ // header already exists, the client IP is appended to the
+ // existing values. As a special case, if the header
+ // exists in the Request.Header map but has a nil value
+ // (such as when set by the Director func), the X-Forwarded-For
+ // header is not modified.
//
- // If a header exists in the Request.Header map but has a nil value
- // (such as when set by the Director func), it is not modified.
+ // To prevent IP spoofing, be sure to delete any pre-existing
+ // X-Forwarded-For header coming from the client or
+ // an untrusted proxy.
//
// Hop-by-hop headers are removed from the request after
// Director returns, which can remove headers added by
@@ -444,16 +444,6 @@ clientIP = strings.Join(prior, ", ") + ", " + clientIP
}
if !omit {
outreq.Header.Set("X-Forwarded-For", clientIP)
- }
- }
- if prior, ok := outreq.Header["X-Forwarded-Host"]; !(ok && prior == nil) {
- outreq.Header.Set("X-Forwarded-Host", req.Host)
- }
- if prior, ok := outreq.Header["X-Forwarded-Proto"]; !(ok && prior == nil) {
- if req.TLS == nil {
- outreq.Header.Set("X-Forwarded-Proto", "http")
- } else {
- outreq.Header.Set("X-Forwarded-Proto", "https")
}
}
}
diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
index 5b882d3a45638c54aee1bbba4fdfad13fe8b9502..d5b0fb4244c6e0dc9894f678aa303f516a104b97 100644
--- a/src/net/http/httputil/reverseproxy_test.go
+++ b/src/net/http/httputil/reverseproxy_test.go
@@ -52,12 +52,6 @@ }
if r.Header.Get("X-Forwarded-For") == "" {
t.Errorf("didn't get X-Forwarded-For header")
}
- if r.Header.Get("X-Forwarded-Host") == "" {
- t.Errorf("didn't get X-Forwarded-Host header")
- }
- if r.Header.Get("X-Forwarded-Proto") == "" {
- t.Errorf("didn't get X-Forwarded-Proto header")
- }
if c := r.Header.Get("Connection"); c != "" {
t.Errorf("handler got Connection header value %q", c)
}
@@ -307,7 +301,6 @@ func TestXForwardedFor(t *testing.T) {
const prevForwardedFor = "client ip"
const backendResponse = "I am the backend"
const backendStatus = 404
- const host = "some-name"
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-Forwarded-For") == "" {
t.Errorf("didn't get X-Forwarded-For header")
@@ -315,12 +308,6 @@ }
if !strings.Contains(r.Header.Get("X-Forwarded-For"), prevForwardedFor) {
t.Errorf("X-Forwarded-For didn't contain prior data")
}
- if got, want := r.Header.Get("X-Forwarded-Host"), host; got != want {
- t.Errorf("X-Forwarded-Host = %q, want %q", got, want)
- }
- if got, want := r.Header.Get("X-Forwarded-Proto"), "http"; got != want {
- t.Errorf("X-Forwarded-Proto = %q, want %q", got, want)
- }
w.WriteHeader(backendStatus)
w.Write([]byte(backendResponse))
}))
@@ -334,7 +321,6 @@ frontend := httptest.NewServer(proxyHandler)
defer frontend.Close()
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
- getReq.Host = host
getReq.Header.Set("Connection", "close")
getReq.Header.Set("X-Forwarded-For", prevForwardedFor)
getReq.Close = true
@@ -351,36 +337,11 @@ t.Errorf("got body %q; expected %q", g, e)
}
}
-func TestXForwardedProtoTLS(t *testing.T) {
- backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if got, want := r.Header.Get("X-Forwarded-Proto"), "https"; got != want {
- t.Errorf("X-Forwarded-Proto = %q, want %q", got, want)
- }
- }))
- defer backend.Close()
- backendURL, err := url.Parse(backend.URL)
- if err != nil {
- t.Fatal(err)
- }
- proxyHandler := NewSingleHostReverseProxy(backendURL)
- frontend := httptest.NewTLSServer(proxyHandler)
- defer frontend.Close()
-
- getReq, _ := http.NewRequest("GET", frontend.URL, nil)
- getReq.Host = "some-host"
- _, err = frontend.Client().Do(getReq)
- if err != nil {
- t.Fatalf("Get: %v", err)
- }
-}
-
// Issue 38079: don't append to X-Forwarded-For if it's present but nil
func TestXForwardedFor_Omit(t *testing.T) {
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- for _, h := range []string{"X-Forwarded-For", "X-Forwarded-Host", "X-Forwarded-Proto"} {
- if v := r.Header.Get(h); v != "" {
- t.Errorf("got %v header: %q", h, v)
- }
+ if v := r.Header.Get("X-Forwarded-For"); v != "" {
+ t.Errorf("got X-Forwarded-For header: %q", v)
}
w.Write([]byte("hi"))
}))
@@ -396,8 +357,6 @@
oldDirector := proxyHandler.Director
proxyHandler.Director = func(r *http.Request) {
r.Header["X-Forwarded-For"] = nil
- r.Header["X-Forwarded-Host"] = nil
- r.Header["X-Forwarded-Proto"] = nil
oldDirector(r)
}
@@ -1106,8 +1065,6 @@
for _, h := range []string{
"From-Director",
"X-Forwarded-For",
- "X-Forwarded-Host",
- "X-Forwarded-Proto",
} {
if req.Header.Get(h) != "" {
t.Errorf("%v header mutation modified caller's request", h)
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 2bc83fd42b290e848b71b30e63b14f8d57ac69ac..245f73bc9fec42a21facd68ca139a0e54b9b232b 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -6565,7 +6565,8 @@
var wg sync.WaitGroup
wg.Add(1)
- putidlec := make(chan chan struct{})
+ putidlec := make(chan chan struct{}, 1)
+ reqerrc := make(chan error, 1)
go func() {
defer wg.Done()
ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
@@ -6574,24 +6575,31 @@ // Signal that the idle conn has been returned to the pool,
// and wait for the order to proceed.
ch := make(chan struct{})
putidlec <- ch
+ close(putidlec) // panic if PutIdleConn runs twice for some reason
<-ch
},
})
req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil)
res, err := client.Do(req)
+ reqerrc <- err
if err == nil {
res.Body.Close()
}
- if err != nil {
- t.Errorf("request 1: got err %v, want nil", err)
- }
}()
// Wait for the first request to receive a response and return the
// connection to the idle pool.
r1c := <-reqc
close(r1c)
- idlec := <-putidlec
+ var idlec chan struct{}
+ select {
+ case err := <-reqerrc:
+ if err != nil {
+ t.Fatalf("request 1: got err %v, want nil", err)
+ }
+ idlec = <-putidlec
+ case idlec = <-putidlec:
+ }
wg.Add(1)
cancelctx, cancel := context.WithCancel(context.Background())
diff --git a/src/os/exec/lp_linux_test.go b/src/os/exec/lp_linux_test.go
index 98c3a7b9e0bb85262257ac297556fa516ad0ad92..845573fb14a4d2dca972740dfffc32e2a61beaca 100644
--- a/src/os/exec/lp_linux_test.go
+++ b/src/os/exec/lp_linux_test.go
@@ -5,6 +5,7 @@
package exec
import (
+ "errors"
"internal/syscall/unix"
"os"
"path/filepath"
@@ -48,8 +49,20 @@ if err != nil {
t.Fatalf("findExecutable: got %v, want nil", err)
}
- if err := Command(path).Run(); err != nil {
- t.Fatalf("exec: got %v, want nil", err)
+ for {
+ err = Command(path).Run()
+ if err == nil {
+ break
+ }
+ if errors.Is(err, syscall.ETXTBSY) {
+ // A fork+exec in another process may be holding open the FD that we used
+ // to write the executable (see https://go.dev/issue/22315).
+ // Since the descriptor should have CLOEXEC set, the problem should resolve
+ // as soon as the forked child reaches its exec call.
+ // Keep retrying until that happens.
+ } else {
+ t.Fatalf("exec: got %v, want nil", err)
+ }
}
// Remount with noexec flag.
diff --git a/src/os/os_test.go b/src/os/os_test.go
index f4103907faebf8cf14f8036042e1dbf7115267c8..277b2455e66dea36da2656c1cf3fc57dd4d3f4bb 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -274,9 +274,11 @@ }
if !equal(sfname, dir.Name()) {
t.Error("name should be ", sfname, "; is", dir.Name())
}
- filesize := size(path, t)
- if dir.Size() != filesize {
- t.Error("size should be", filesize, "; is", dir.Size())
+ if dir.Mode()&ModeSymlink == 0 {
+ filesize := size(path, t)
+ if dir.Size() != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size())
+ }
}
}
@@ -2606,9 +2608,6 @@ func TestReaddirSmallSeek(t *testing.T) {
// See issue 37161. Read only one entry from a directory,
// seek to the beginning, and read again. We should not see
// duplicate entries.
- if runtime.GOOS == "windows" {
- testenv.SkipFlaky(t, 36019)
- }
wd, err := Getwd()
if err != nil {
t.Fatal(err)
diff --git a/src/os/user/cgo_lookup_cgo.go b/src/os/user/cgo_lookup_cgo.go
index 17995738d24d7a95cdad44190fa9355f104ae1e0..4f78dcad23dbd9ff547a1e759a34c771e8a1b59b 100644
--- a/src/os/user/cgo_lookup_cgo.go
+++ b/src/os/user/cgo_lookup_cgo.go
@@ -12,42 +12,48 @@ )
/*
#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
+#cgo CFLAGS: -fno-stack-protector
#include
#include
#include
#include
#include
+#include
static struct passwd mygetpwuid_r(int uid, char *buf, size_t buflen, int *found, int *perr) {
struct passwd pwd;
- struct passwd *result;
- *perr = getpwuid_r(uid, &pwd, buf, buflen, &result);
- *found = result != NULL;
- return pwd;
+ struct passwd *result;
+ memset (&pwd, 0, sizeof(pwd));
+ *perr = getpwuid_r(uid, &pwd, buf, buflen, &result);
+ *found = result != NULL;
+ return pwd;
}
static struct passwd mygetpwnam_r(const char *name, char *buf, size_t buflen, int *found, int *perr) {
struct passwd pwd;
- struct passwd *result;
- *perr = getpwnam_r(name, &pwd, buf, buflen, &result);
- *found = result != NULL;
- return pwd;
+ struct passwd *result;
+ memset(&pwd, 0, sizeof(pwd));
+ *perr = getpwnam_r(name, &pwd, buf, buflen, &result);
+ *found = result != NULL;
+ return pwd;
}
static struct group mygetgrgid_r(int gid, char *buf, size_t buflen, int *found, int *perr) {
struct group grp;
- struct group *result;
- *perr = getgrgid_r(gid, &grp, buf, buflen, &result);
- *found = result != NULL;
- return grp;
+ struct group *result;
+ memset(&grp, 0, sizeof(grp));
+ *perr = getgrgid_r(gid, &grp, buf, buflen, &result);
+ *found = result != NULL;
+ return grp;
}
static struct group mygetgrnam_r(const char *name, char *buf, size_t buflen, int *found, int *perr) {
struct group grp;
- struct group *result;
- *perr = getgrnam_r(name, &grp, buf, buflen, &result);
- *found = result != NULL;
- return grp;
+ struct group *result;
+ memset(&grp, 0, sizeof(grp));
+ *perr = getgrnam_r(name, &grp, buf, buflen, &result);
+ *found = result != NULL;
+ return grp;
}
*/
import "C"
diff --git a/src/os/user/cgo_lookup_unix.go b/src/os/user/cgo_lookup_unix.go
index b745ffd9cf44ea8675de0abe5d0912af822de280..3735971eb4b7b4b87a456ea1d6b0117c6f087889 100644
--- a/src/os/user/cgo_lookup_unix.go
+++ b/src/os/user/cgo_lookup_unix.go
@@ -8,6 +8,7 @@ package user
import (
"fmt"
+ "runtime"
"strconv"
"strings"
"syscall"
@@ -170,6 +171,9 @@ for {
errno := f(buf)
if errno == 0 {
return nil
+ } else if runtime.GOOS == "aix" && errno+1 == 0 {
+ // On AIX getpwuid_r appears to return -1,
+ // not ERANGE, on buffer overflow.
} else if errno != syscall.ERANGE {
return errno
}
diff --git a/src/runtime/coverage/emitdata_test.go b/src/runtime/coverage/emitdata_test.go
index 0ccb2d27b0c831bd97427443666485afcb329334..3839e4437f8d7aa56500e0dd004fec60056d27b6 100644
--- a/src/runtime/coverage/emitdata_test.go
+++ b/src/runtime/coverage/emitdata_test.go
@@ -157,7 +157,7 @@ }
func testForSpecificFunctions(t *testing.T, dir string, want []string, avoid []string) string {
args := []string{"tool", "covdata", "debugdump",
- "-live", "-pkg=main", "-i=" + dir}
+ "-live", "-pkg=command-line-arguments", "-i=" + dir}
t.Logf("running: go %v\n", args)
cmd := exec.Command(testenv.GoToolPath(t), args...)
b, err := cmd.CombinedOutput()
@@ -167,17 +167,20 @@ }
output := string(b)
rval := ""
for _, f := range want {
- wf := "Func: " + f
+ wf := "Func: " + f + "\n"
if strings.Contains(output, wf) {
continue
}
rval += fmt.Sprintf("error: output should contain %q but does not\n", wf)
}
for _, f := range avoid {
- wf := "Func: " + f
+ wf := "Func: " + f + "\n"
if strings.Contains(output, wf) {
rval += fmt.Sprintf("error: output should not contain %q but does\n", wf)
}
+ }
+ if rval != "" {
+ t.Logf("=-= begin output:\n" + output + "\n=-= end output\n")
}
return rval
}
diff --git a/src/runtime/coverage/testsupport.go b/src/runtime/coverage/testsupport.go
index 462d06c878fe1a85590e2d6be51db2b101785686..1d90ebd7a299bf6bbeef863c272f38d2fa499ef3 100644
--- a/src/runtime/coverage/testsupport.go
+++ b/src/runtime/coverage/testsupport.go
@@ -136,13 +136,16 @@ if err := ts.cm.SetModeAndGranularity(p.MetaFile, cmode, newgran); err != nil {
return err
}
- // Read counter data files.
+ // A map to store counter data, indexed by pkgid/fnid tuple.
pmm := make(map[pkfunc][]uint32)
- for _, cdf := range p.CounterDataFiles {
+
+ // Helper to read a single counter data file.
+ readcdf := func(cdf string) error {
cf, err := os.Open(cdf)
if err != nil {
return fmt.Errorf("opening counter data file %s: %s", cdf, err)
}
+ defer cf.Close()
var cdr *decodecounter.CounterDataReader
cdr, err = decodecounter.NewCounterDataReader(cdf, cf)
if err != nil {
@@ -169,6 +172,14 @@ }
c := ts.AllocateCounters(len(data.Counters))
copy(c, data.Counters)
pmm[key] = c
+ }
+ return nil
+ }
+
+ // Read counter data files.
+ for _, cdf := range p.CounterDataFiles {
+ if err := readcdf(cdf); err != nil {
+ return err
}
}
diff --git a/src/runtime/internal/atomic/atomic_test.go b/src/runtime/internal/atomic/atomic_test.go
index 2ae60b8507ef5831e2d5345514224696c0b85623..2427bfd211ee9cd84e858783d3a2c63473b7c2fe 100644
--- a/src/runtime/internal/atomic/atomic_test.go
+++ b/src/runtime/internal/atomic/atomic_test.go
@@ -345,6 +345,36 @@ }
}
}
+func TestCasRel(t *testing.T) {
+ const _magic = 0x5a5aa5a5
+ var x struct {
+ before uint32
+ i uint32
+ after uint32
+ o uint32
+ n uint32
+ }
+
+ x.before = _magic
+ x.after = _magic
+ for j := 0; j < 32; j += 1 {
+ x.i = (1 << j) + 0
+ x.o = (1 << j) + 0
+ x.n = (1 << j) + 1
+ if !atomic.CasRel(&x.i, x.o, x.n) {
+ t.Fatalf("should have swapped %#x %#x", x.o, x.n)
+ }
+
+ if x.i != x.n {
+ t.Fatalf("wrong x.i after swap: x.i=%#x x.n=%#x", x.i, x.n)
+ }
+
+ if x.before != _magic || x.after != _magic {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, _magic, _magic)
+ }
+ }
+}
+
func TestStorepNoWB(t *testing.T) {
var p [2]*int
for i := range p {
diff --git a/src/runtime/internal/startlinetest/func_amd64.go b/src/runtime/internal/startlinetest/func_amd64.go
index 6cd9a3f417e9db4ea4baddee1b1b52f3d7990f50..ab7063d615fc37fcf3b3cb7ef634587a18ef6a29 100644
--- a/src/runtime/internal/startlinetest/func_amd64.go
+++ b/src/runtime/internal/startlinetest/func_amd64.go
@@ -8,3 +8,6 @@
// Defined in func_amd64.s, this is a trivial assembly function that calls
// runtime_test.callerStartLine.
func AsmFunc() int
+
+// Provided by runtime_test.
+var CallerStartLine func(bool) int
diff --git a/src/runtime/internal/startlinetest/func_amd64.s b/src/runtime/internal/startlinetest/func_amd64.s
index ace5b34e70f833efa4533a90b62536054128ec8e..96982bedab82c502d3a6e846238bb2d0e1926094 100644
--- a/src/runtime/internal/startlinetest/func_amd64.s
+++ b/src/runtime/internal/startlinetest/func_amd64.s
@@ -23,5 +23,6 @@
TEXT ·AsmFunc(SB),NOSPLIT,$8-0
NO_LOCAL_POINTERS
MOVQ $0, AX // wantInlined
- CALL runtime_test·callerStartLine(SB)
+ MOVQ ·CallerStartLine(SB), DX
+ CALL (DX)
RET
diff --git a/src/runtime/libfuzzer.go b/src/runtime/libfuzzer.go
index 013e7165b21fff6b01807dfc5503157fe0953b18..0ece035405f7aa7e6de881c6262e6f7013d60d83 100644
--- a/src/runtime/libfuzzer.go
+++ b/src/runtime/libfuzzer.go
@@ -148,13 +148,8 @@ //go:linkname __sanitizer_cov_8bit_counters_init __sanitizer_cov_8bit_counters_init
//go:cgo_import_static __sanitizer_cov_8bit_counters_init
var __sanitizer_cov_8bit_counters_init byte
-//go:linkname __start___sancov_cntrs __start___sancov_cntrs
-//go:cgo_import_static __start___sancov_cntrs
-var __start___sancov_cntrs byte
-
-//go:linkname __stop___sancov_cntrs __stop___sancov_cntrs
-//go:cgo_import_static __stop___sancov_cntrs
-var __stop___sancov_cntrs byte
+// start, stop markers of counters, set by the linker
+var __start___sancov_cntrs, __stop___sancov_cntrs byte
//go:linkname __sanitizer_cov_pcs_init __sanitizer_cov_pcs_init
//go:cgo_import_static __sanitizer_cov_pcs_init
diff --git a/src/runtime/mfinal_test.go b/src/runtime/mfinal_test.go
index 902ccc57f87880be9d5ac480ebe930f895d0617b..61d625ac27775516abfc1a27134fdeb4d395fbb7 100644
--- a/src/runtime/mfinal_test.go
+++ b/src/runtime/mfinal_test.go
@@ -53,7 +53,7 @@ return [4]int64{}
}},
}
- for i, tt := range finalizerTests {
+ for _, tt := range finalizerTests {
done := make(chan bool, 1)
go func() {
// allocate struct with pointer to avoid hitting tinyalloc.
@@ -71,11 +71,7 @@ done <- true
}()
<-done
runtime.GC()
- select {
- case <-ch:
- case <-time.After(time.Second * 4):
- t.Errorf("#%d: finalizer for type %T didn't run", i, tt.finalizer)
- }
+ <-ch
}
}
@@ -109,11 +105,7 @@ done <- true
}()
<-done
runtime.GC()
- select {
- case <-ch:
- case <-time.After(4 * time.Second):
- t.Errorf("finalizer for type *bigValue didn't run")
- }
+ <-ch
}
func fin(v *int) {
@@ -188,11 +180,7 @@
fin := make(chan bool, 1)
runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
runtime.GC()
- select {
- case <-fin:
- case <-time.After(4 * time.Second):
- t.Errorf("finalizer of next object in memory didn't run")
- }
+ <-fin
xsglobal = xs // keep empty slice alive until here
}
@@ -220,11 +208,7 @@ fin := make(chan bool, 1)
// set finalizer on string contents of y
runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
runtime.GC()
- select {
- case <-fin:
- case <-time.After(4 * time.Second):
- t.Errorf("finalizer of next string in memory didn't run")
- }
+ <-fin
ssglobal = ss // keep 0-length string live until here
}
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index c4f3bb6a818585ca78284c39cc4011fbeaabe141..af5c18c30195c1b70c4aa173c79972b709d34789 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -136,8 +136,6 @@ // can look at the environment first.
ncpu = getncpu()
physPageSize = getPageSize()
-
- osinit_hack()
}
func sysctlbynameInt32(name []byte) (int32, int32) {
diff --git a/src/runtime/race/internal/amd64v1/doc.go b/src/runtime/race/internal/amd64v1/doc.go
index 130b290bdb8eb3907fbcd13a0691a53f2c7cb336..ccb088cc46cca66e41886f31af4edb5c1de3e955 100644
--- a/src/runtime/race/internal/amd64v1/doc.go
+++ b/src/runtime/race/internal/amd64v1/doc.go
@@ -5,4 +5,6 @@
// This package holds the race detector .syso for
// amd64 architectures with GOAMD64=v3.
+//go:build amd64 && linux && amd64.v3
+
package amd64v3
diff --git a/src/runtime/race/race_v1_amd64.go b/src/runtime/race/race_v1_amd64.go
index b8a20315fdc9f54df857d6f399285f2646538887..7c40db1dcf7713e9eac67d37037355a4f1f512b6 100644
--- a/src/runtime/race/race_v1_amd64.go
+++ b/src/runtime/race/race_v1_amd64.go
@@ -3,7 +3,6 @@ // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (linux && !amd64.v3) || darwin || freebsd || netbsd || openbsd || windows
-// +build linux,!amd64.v3 darwin freebsd netbsd openbsd windows
package race
diff --git a/src/runtime/race/race_v3_amd64.go b/src/runtime/race/race_v3_amd64.go
index 913bb77f484909eb24d8113d43ab8abd01adb6fe..80728d834a67e7825a297af3bf17e9f1054ae232 100644
--- a/src/runtime/race/race_v3_amd64.go
+++ b/src/runtime/race/race_v3_amd64.go
@@ -3,7 +3,6 @@ // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && amd64.v3
-// +build linux,amd64.v3
package race
diff --git a/src/runtime/start_line_amd64_test.go b/src/runtime/start_line_amd64_test.go
index 57001e71de92759cd8492ffc6487f8d7785411b7..305ed0b126621f24942fc13bfa16822b3ca3d037 100644
--- a/src/runtime/start_line_amd64_test.go
+++ b/src/runtime/start_line_amd64_test.go
@@ -13,6 +13,8 @@ // TestStartLineAsm tests the start line metadata of an assembly function. This
// is only tested on amd64 to avoid the need for a proliferation of per-arch
// copies of this function.
func TestStartLineAsm(t *testing.T) {
+ startlinetest.CallerStartLine = callerStartLine
+
const wantLine = 23
got := startlinetest.AsmFunc()
if got != wantLine {
diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go
index 1ea7f5e481cc0d49f09624881b58e36bb381cd2c..cfc0ad7cde87864195aaccf84c3aba0b61e13ec1 100644
--- a/src/runtime/string_test.go
+++ b/src/runtime/string_test.go
@@ -223,6 +223,19 @@ t.Fatalf("output does not start with %q:\n%s", want, output)
}
}
+func TestConcatTempString(t *testing.T) {
+ s := "bytes"
+ b := []byte(s)
+ n := testing.AllocsPerRun(1000, func() {
+ if "prefix "+string(b)+" suffix" != "prefix bytes suffix" {
+ t.Fatalf("strings are not equal: '%v' and '%v'", "prefix "+string(b)+" suffix", "prefix bytes suffix")
+ }
+ })
+ if n != 0 {
+ t.Fatalf("want 0 allocs, got %v", n)
+ }
+}
+
func TestCompareTempString(t *testing.T) {
s := strings.Repeat("x", sizeNoStack)
b := []byte(s)
@@ -230,7 +243,21 @@ n := testing.AllocsPerRun(1000, func() {
if string(b) != s {
t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
}
+ if string(b) < s {
+ t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
+ }
+ if string(b) > s {
+ t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
+ }
if string(b) == s {
+ } else {
+ t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
+ }
+ if string(b) <= s {
+ } else {
+ t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
+ }
+ if string(b) >= s {
} else {
t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
}
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index 28dc2915966c4b2655610d5338a10662b28d74dd..61b7f8c728ffab4197c9c60ed09a2303d654e7e2 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -179,51 +179,6 @@ return
}
func pthread_kill_trampoline()
-// osinit_hack is a clumsy hack to work around Apple libc bugs
-// causing fork+exec to hang in the child process intermittently.
-// See go.dev/issue/33565 and go.dev/issue/56784 for a few reports.
-//
-// The stacks obtained from the hung child processes are in
-// libSystem_atfork_child, which is supposed to reinitialize various
-// parts of the C library in the new process.
-//
-// One common stack dies in _notify_fork_child calling _notify_globals
-// (inlined) calling _os_alloc_once, because _os_alloc_once detects that
-// the once lock is held by the parent process and then calls
-// _os_once_gate_corruption_abort. The allocation is setting up the
-// globals for the notification subsystem. See the source code at [1].
-// To work around this, we can allocate the globals earlier in the Go
-// program's lifetime, before any execs are involved, by calling any
-// notify routine that is exported, calls _notify_globals, and doesn't do
-// anything too expensive otherwise. notify_is_valid_token(0) fits the bill.
-//
-// The other common stack dies in xpc_atfork_child calling
-// _objc_msgSend_uncached which ends up in
-// WAITING_FOR_ANOTHER_THREAD_TO_FINISH_CALLING_+initialize. Of course,
-// whatever thread the child is waiting for is in the parent process and
-// is not going to finish anything in the child process. There is no
-// public source code for these routines, so it is unclear exactly what
-// the problem is. However, xpc_atfork_child turns out to be exported
-// (for use by libSystem_atfork_child, which is in a different library,
-// so xpc_atfork_child is unlikely to be unexported any time soon).
-// It also stands to reason that since xpc_atfork_child is called at the
-// start of any forked child process, it can't be too harmful to call at
-// the start of an ordinary Go process. And whatever caches it needs for
-// a non-deadlocking fast path during exec empirically do get initialized
-// by calling it at startup.
-//
-// So osinit_hack_trampoline (in sys_darwin_$GOARCH.s) calls
-// notify_is_valid_token(0) and xpc_atfork_child(), which makes the
-// fork+exec hangs stop happening. If Apple fixes the libc bug in
-// some future version of macOS, then we can remove this awful code.
-//
-//go:nosplit
-func osinit_hack() {
- libcCall(unsafe.Pointer(abi.FuncPCABI0(osinit_hack_trampoline)), nil)
- return
-}
-func osinit_hack_trampoline()
-
// mmap is used to do low-level memory allocation via mmap. Don't allow stack
// splits, since this function (used by sysAlloc) is called in a lot of low-level
// parts of the runtime and callers often assume it won't acquire any locks.
@@ -593,6 +548,3 @@ //go:cgo_import_dynamic libc_pthread_cond_init pthread_cond_init "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_cond_wait pthread_cond_wait "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_cond_timedwait_relative_np pthread_cond_timedwait_relative_np "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_cond_signal pthread_cond_signal "/usr/lib/libSystem.B.dylib"
-
-//go:cgo_import_dynamic libc_notify_is_valid_token notify_is_valid_token "/usr/lib/libSystem.B.dylib"
-//go:cgo_import_dynamic libc_xpc_atfork_child xpc_atfork_child "/usr/lib/libSystem.B.dylib"
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index 16783a481941eec1881a704d41af791288978b47..369b12e8f9f86d86b3b9f63d432c5abaa01f9a11 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -597,15 +597,6 @@ CALL libc_pthread_kill(SB)
POPQ BP
RET
-TEXT runtime·osinit_hack_trampoline(SB),NOSPLIT,$0
- PUSHQ BP
- MOVQ SP, BP
- MOVQ $0, DI // arg 1 val
- CALL libc_notify_is_valid_token(SB)
- CALL libc_xpc_atfork_child(SB)
- POPQ BP
- RET
-
// syscall calls a function in libc on behalf of the syscall package.
// syscall takes a pointer to a struct like:
// struct {
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index 3cbac773941060585c6933d8820881c703e9e70c..4fa99cc0f98cff8d8f02b9a8eb446239aeb67e47 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -458,12 +458,6 @@ MOVD 0(R0), R0 // arg 1 key
BL libc_pthread_setspecific(SB)
RET
-TEXT runtime·osinit_hack_trampoline(SB),NOSPLIT,$0
- MOVD $0, R0 // arg 1 val
- BL libc_notify_is_valid_token(SB)
- BL libc_xpc_atfork_child(SB)
- RET
-
// syscall calls a function in libc on behalf of the syscall package.
// syscall takes a pointer to a struct like:
// struct {
diff --git a/src/sync/map_bench_test.go b/src/sync/map_bench_test.go
index 4815f57349ec179d7e54c668937014f340bd2b0a..eebec3bacfccc27ac05a15dee3509d127044a84e 100644
--- a/src/sync/map_bench_test.go
+++ b/src/sync/map_bench_test.go
@@ -389,7 +389,6 @@ })
}
func BenchmarkCompareAndSwapValueNotEqual(b *testing.B) {
- const n = 1 << 10
benchMap(b, bench{
setup: func(_ *testing.B, m mapInterface) {
m.Store(0, 0)
diff --git a/src/syscall/exec_freebsd.go b/src/syscall/exec_freebsd.go
index b85bcd93a82bca9b8841b9cce2716c6548f0a5ac..af5a4158f04fec01ed1a9408b7ee2e89ed0869ee 100644
--- a/src/syscall/exec_freebsd.go
+++ b/src/syscall/exec_freebsd.go
@@ -205,7 +205,7 @@ // using SIGKILL.
r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
if r1 != ppid {
pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
- _, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
+ _, _, err1 = RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
if err1 != 0 {
goto childerror
}
diff --git a/src/syscall/exec_libc2.go b/src/syscall/exec_libc2.go
index 41bc79a721e7d4fa186d1896888f5f0b88e90732..6e3c2bf9d7608f6671e33731248470d7a18a1577 100644
--- a/src/syscall/exec_libc2.go
+++ b/src/syscall/exec_libc2.go
@@ -78,7 +78,7 @@
// About to call fork.
// No more allocation or calls of non-assembly functions.
runtime_BeforeFork()
- r1, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0)
+ r1, _, err1 = rawSyscall(forkTrampoline, 0, 0, 0)
if err1 != 0 {
runtime_AfterFork()
return 0, err1
@@ -276,6 +276,6 @@ childerror:
// send error code on pipe
rawSyscall(abi.FuncPCABI0(libc_write_trampoline), uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
for {
- rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), 253, 0, 0)
+ rawSyscall(exitTrampoline, 253, 0, 0)
}
}
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index b61b51dff1d42bc7b8de72b1e90114e07b89633e..7e0c3d250bcb984e481f828cda1db52efec15a4d 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -470,7 +470,7 @@ // Ambient capabilities were added in the 4.3 kernel,
// so it is safe to always use _LINUX_CAPABILITY_VERSION_3.
caps.hdr.version = _LINUX_CAPABILITY_VERSION_3
- if _, _, err1 := RawSyscall(SYS_CAPGET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); err1 != 0 {
+ if _, _, err1 = RawSyscall(SYS_CAPGET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); err1 != 0 {
goto childerror
}
@@ -481,7 +481,7 @@ caps.data[capToIndex(c)].permitted |= capToMask(c)
caps.data[capToIndex(c)].inheritable |= capToMask(c)
}
- if _, _, err1 := RawSyscall(SYS_CAPSET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); err1 != 0 {
+ if _, _, err1 = RawSyscall(SYS_CAPSET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); err1 != 0 {
goto childerror
}
@@ -514,7 +514,7 @@ // using SIGKILL.
r1, _ = rawSyscallNoError(SYS_GETPPID, 0, 0, 0)
if r1 != ppid {
pid, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0)
- _, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
+ _, _, err1 = RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
if err1 != 0 {
goto childerror
}
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index a035d415ed539a83495b77317c54664ff9369e4b..1e21fffaef9f1c8ae56eee2959caa373d451f534 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -8,6 +8,7 @@ package syscall_test
import (
"bytes"
+ "errors"
"flag"
"fmt"
"internal/testenv"
@@ -504,7 +505,8 @@
// Need an ability to create a sub-cgroup.
subCgroup, err := os.MkdirTemp(prefix+string(bytes.TrimSpace(cg)), "subcg-")
if err != nil {
- if os.IsPermission(err) {
+ // Running in an unprivileged container, this may also return EROFS #57262.
+ if os.IsPermission(err) || errors.Is(err, syscall.EROFS) {
t.Skip(err)
}
t.Fatal(err)
diff --git a/src/syscall/exec_plan9.go b/src/syscall/exec_plan9.go
index d6b7890f55137f44c019a28743d72ecfa6c1e362..8f28b5aa22adbefc2d7f18f356e7323e4c9aa51a 100644
--- a/src/syscall/exec_plan9.go
+++ b/src/syscall/exec_plan9.go
@@ -276,7 +276,7 @@ }
// Pass 3: close fd[i] if it was moved in the previous pass.
for i = 0; i < len(fd); i++ {
- if fd[i] >= 0 && fd[i] != int(i) {
+ if fd[i] >= len(fd) {
RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0)
}
}
diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go
index a39e99dc633a86df864a1d1e820bcc138b2db4c2..5ec311962a5a42d7b5018e5bb6992ced9963b3ee 100644
--- a/src/syscall/syscall_darwin.go
+++ b/src/syscall/syscall_darwin.go
@@ -22,7 +22,34 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
-var dupTrampoline = abi.FuncPCABI0(libc_dup2_trampoline)
+// These are called from exec_libc2.go in the child of fork.
+// The names differ between macOS and OpenBSD, so we need
+// to declare the specific ones used here to keep the exec_libc2.go
+// code portable.
+//
+// We use __fork and __exit, not fork and exit, to avoid the libc atfork
+// and atexit handlers. The atfork handlers have caused fork child
+// hangs in the past (see #33565, #56784). The atexit handlers have
+// not, but the non-libc ports all invoke the system call, so doing
+// the same here makes sense. In general we wouldn't expect
+// atexit handlers to work terribly well in a fork child anyway.
+// (Also, perhaps the atfork handlers clear the atexit handlers,
+// in which case we definitely need to avoid calling the libc exit
+// if we bypass the libc fork.)
+//
+// Other calls that are made in the child after the fork are
+// ptrace, setsid, setpgid, getpid, ioctl, chroot, setgroups,
+// setgid, setuid, chdir, dup2, fcntl, close, execve, and write.
+// Those are all simple kernel wrappers that should be safe
+// to be called directly. The fcntl and ioctl functions do run
+// some code around the kernel call, but they don't call any
+// other functions, so for now we keep using them instead of
+// calling the lower-level __fcntl and __ioctl functions.
+var (
+ dupTrampoline = abi.FuncPCABI0(libc_dup2_trampoline)
+ exitTrampoline = abi.FuncPCABI0(libc___exit_trampoline)
+ forkTrampoline = abi.FuncPCABI0(libc___fork_trampoline)
+)
type SockaddrDatalink struct {
Len uint8
@@ -210,11 +237,12 @@ //sys write(fd int, p []byte) (n int, err error)
//sys writev(fd int, iovecs []Iovec) (cnt uintptr, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
//sys munmap(addr uintptr, length uintptr) (err error)
-//sysnb fork() (pid int, err error)
+//sysnb __fork() (pid int, err error)
//sysnb ioctl(fd int, req int, arg int) (err error)
//sysnb ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_ioctl
//sysnb execve(path *byte, argv **byte, envp **byte) (err error)
//sysnb exit(res int) (err error)
+//sysnb __exit(res int) (err error)
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error)
//sys fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) = SYS_fcntl
//sys unlinkat(fd int, path string, flags int) (err error)
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index bdee570ddaef73bd44a5821c6463cd82b409faff..d4cc34bdee0b2f1c5c9f128e76e2a14fd65838f1 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -13,6 +13,7 @@ package syscall
import (
"internal/itoa"
+ "runtime"
"unsafe"
)
@@ -145,8 +146,17 @@ if flags == 0 {
return faccessat(dirfd, path, mode)
}
- if err := faccessat2(dirfd, path, mode, flags); err != ENOSYS && err != EPERM {
- return err
+ // Attempt to use the newer faccessat2, which supports flags directly,
+ // falling back if it doesn't exist.
+ //
+ // Don't attempt on Android, which does not allow faccessat2 through
+ // its seccomp policy [1] on any version of Android as of 2022-12-20.
+ //
+ // [1] https://cs.android.com/android/platform/superproject/+/master:bionic/libc/SECCOMP_BLOCKLIST_APP.TXT;l=4;drc=dbb8670dfdcc677f7e3b9262e93800fa14c4e417
+ if runtime.GOOS != "android" {
+ if err := faccessat2(dirfd, path, mode, flags); err != ENOSYS && err != EPERM {
+ return err
+ }
}
// The Linux kernel faccessat system call does not take any flags.
@@ -641,21 +651,6 @@ sa.Addr = pp.Addr
return sa, nil
}
return nil, EAFNOSUPPORT
-}
-
-func Accept(fd int) (nfd int, sa Sockaddr, err error) {
- var rsa RawSockaddrAny
- var len _Socklen = SizeofSockaddrAny
- nfd, err = accept4(fd, &rsa, &len, 0)
- if err != nil {
- return
- }
- sa, err = anyToSockaddr(&rsa)
- if err != nil {
- Close(nfd)
- nfd = 0
- }
- return
}
func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
diff --git a/src/syscall/syscall_linux_accept.go b/src/syscall/syscall_linux_accept.go
new file mode 100644
index 0000000000000000000000000000000000000000..66c0f84cb8e5d1f824d44d7f353938c583c7ec36
--- /dev/null
+++ b/src/syscall/syscall_linux_accept.go
@@ -0,0 +1,34 @@
+// Copyright 2009 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 require Linux kernel version 2.6.32. The accept4 system call was
+// added in version 2.6.28, so in general we can use accept4.
+// Unfortunately, for ARM only, accept4 was added in version 2.6.36.
+// Handle that case here, by using a copy of the Accept function that
+// we used in Go 1.17.
+
+//go:build linux && arm
+
+package syscall
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ // Try accept4 first for Android and newer kernels.
+ nfd, err = accept4(fd, &rsa, &len, 0)
+ if err == ENOSYS {
+ nfd, err = accept(fd, &rsa, &len)
+ }
+ if err != nil {
+ return
+ }
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
diff --git a/src/syscall/syscall_linux_accept4.go b/src/syscall/syscall_linux_accept4.go
new file mode 100644
index 0000000000000000000000000000000000000000..74898672c0466ab26de838467788458747783e79
--- /dev/null
+++ b/src/syscall/syscall_linux_accept4.go
@@ -0,0 +1,25 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides the Accept function used on all systems
+// other than arm. See syscall_linux_accept.go for why.
+
+//go:build linux && !arm
+
+package syscall
+
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, err = accept4(fd, &rsa, &len, 0)
+ if err != nil {
+ return
+ }
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
diff --git a/src/syscall/syscall_openbsd_libc.go b/src/syscall/syscall_openbsd_libc.go
index 516d02975c530a3ea1aea3b826039f7891797c80..6358a9a390a0c3298946e6e6bc139adc5a21317c 100644
--- a/src/syscall/syscall_openbsd_libc.go
+++ b/src/syscall/syscall_openbsd_libc.go
@@ -10,7 +10,11 @@ import (
"internal/abi"
)
-var dupTrampoline = abi.FuncPCABI0(libc_dup3_trampoline)
+var (
+ dupTrampoline = abi.FuncPCABI0(libc_dup3_trampoline)
+ exitTrampoline = abi.FuncPCABI0(libc_exit_trampoline)
+ forkTrampoline = abi.FuncPCABI0(libc_fork_trampoline)
+)
func init() {
execveOpenBSD = execve
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
index 6b3fff3f3726a224ad1c6bbdc856eec18e73fdfe..5e3f6cccf0053b24db7c6b3bc5bc3df228f6f5f0 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -1734,8 +1734,8 @@ //go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fork() (pid int, err error) {
- r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0)
+func __fork() (pid int, err error) {
+ r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc___fork_trampoline), 0, 0, 0)
pid = int(r0)
if e1 != 0 {
err = errnoErr(e1)
@@ -1743,9 +1743,9 @@ }
return
}
-func libc_fork_trampoline()
+func libc___fork_trampoline()
-//go:cgo_import_dynamic libc_fork fork "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc___fork __fork "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
@@ -1798,6 +1798,20 @@
func libc_exit_trampoline()
//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func __exit(res int) (err error) {
+ _, _, e1 := rawSyscall(abi.FuncPCABI0(libc___exit_trampoline), uintptr(res), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func libc___exit_trampoline()
+
+//go:cgo_import_dynamic libc___exit __exit "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
diff --git a/src/syscall/zsyscall_darwin_amd64.s b/src/syscall/zsyscall_darwin_amd64.s
index 90e51fb9a4f43a63b4fff6150a47626b4d6c1135..cbb4496a50ed16b6347b9aeaba30bf6552d552b4 100644
--- a/src/syscall/zsyscall_darwin_amd64.s
+++ b/src/syscall/zsyscall_darwin_amd64.s
@@ -221,14 +221,16 @@ TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0
JMP libc_mmap(SB)
TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0
JMP libc_munmap(SB)
-TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0
- JMP libc_fork(SB)
+TEXT ·libc___fork_trampoline(SB),NOSPLIT,$0-0
+ JMP libc___fork(SB)
TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0
JMP libc_ioctl(SB)
TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0
JMP libc_execve(SB)
TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0
JMP libc_exit(SB)
+TEXT ·libc___exit_trampoline(SB),NOSPLIT,$0-0
+ JMP libc___exit(SB)
TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0
JMP libc_sysctl(SB)
TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0
diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go
index 61601449a04043f185cd640cd3599af492d565cd..d4c56be8188518e6702f10d59ee74ea7f4d54c68 100644
--- a/src/syscall/zsyscall_darwin_arm64.go
+++ b/src/syscall/zsyscall_darwin_arm64.go
@@ -1734,8 +1734,8 @@ //go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fork() (pid int, err error) {
- r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0)
+func __fork() (pid int, err error) {
+ r0, _, e1 := rawSyscall(abi.FuncPCABI0(libc___fork_trampoline), 0, 0, 0)
pid = int(r0)
if e1 != 0 {
err = errnoErr(e1)
@@ -1743,9 +1743,9 @@ }
return
}
-func libc_fork_trampoline()
+func libc___fork_trampoline()
-//go:cgo_import_dynamic libc_fork fork "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc___fork __fork "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
@@ -1798,6 +1798,20 @@
func libc_exit_trampoline()
//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func __exit(res int) (err error) {
+ _, _, e1 := rawSyscall(abi.FuncPCABI0(libc___exit_trampoline), uintptr(res), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func libc___exit_trampoline()
+
+//go:cgo_import_dynamic libc___exit __exit "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
diff --git a/src/syscall/zsyscall_darwin_arm64.s b/src/syscall/zsyscall_darwin_arm64.s
index f00747939efa36d38d2f920b79169fe31eab8e64..ce1850e0aef5a81d1694d2eb59f24c8dc3adb3bb 100644
--- a/src/syscall/zsyscall_darwin_arm64.s
+++ b/src/syscall/zsyscall_darwin_arm64.s
@@ -221,14 +221,16 @@ TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0
JMP libc_mmap(SB)
TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0
JMP libc_munmap(SB)
-TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0
- JMP libc_fork(SB)
+TEXT ·libc___fork_trampoline(SB),NOSPLIT,$0-0
+ JMP libc___fork(SB)
TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0
JMP libc_ioctl(SB)
TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0
JMP libc_execve(SB)
TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0
JMP libc_exit(SB)
+TEXT ·libc___exit_trampoline(SB),NOSPLIT,$0-0
+ JMP libc___exit(SB)
TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0
JMP libc_sysctl(SB)
TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0
diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go
index db5ec6044822be91a1b60d106084b347685cfad2..69f811a0ec7c31aecd0c1a86a8b3b226cc5fa658 100644
--- a/src/syscall/zsyscall_linux_arm.go
+++ b/src/syscall/zsyscall_linux_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 -arm -tags linux,arm syscall_linux.go syscall_linux_arm.go
+// mksyscall.pl -l32 -arm -tags linux,arm syscall_linux.go syscall_linux_arm.go syscall_linux_accept.go
// Code generated by the command above; DO NOT EDIT.
//go:build linux && arm
@@ -1601,3 +1601,14 @@ err = errnoErr(e1)
}
return
}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index acd28667c2803dc82e6ee9540028fb7641f58ef7..fc34cbf28b57f2f901dac992d687e503e73aba4c 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -13,8 +13,9 @@ // serves to identify the test routine.
//
// Within these functions, use the Error, Fail or related methods to signal failure.
//
-// To write a new test suite, create a file whose name ends _test.go that
-// contains the TestXxx functions as described here.
+// To write a new test suite, create a file that
+// contains the TestXxx functions as described here,
+// and give that file a name ending in "_test.go".
// The file will be excluded from regular
// package builds but will be included when the "go test" command is run.
//
diff --git a/test/fixedbugs/issue57184.go b/test/fixedbugs/issue57184.go
new file mode 100644
index 0000000000000000000000000000000000000000..1384b50be8779df1624128c301d1411f2c94a7d9
--- /dev/null
+++ b/test/fixedbugs/issue57184.go
@@ -0,0 +1,40 @@
+// run
+
+// Copyright 2022 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 (
+ "log"
+ "reflect"
+ "sort"
+)
+
+func main() {
+ const length = 257
+ x := make([]int64, length)
+ for i := 0; i < length; i++ {
+ x[i] = int64(i) * 27644437 % int64(length)
+ }
+
+ isLessStatic := func(i, j int) bool {
+ return x[i] < x[j]
+ }
+
+ isLessReflect := reflect.MakeFunc(reflect.TypeOf(isLessStatic), func(args []reflect.Value) []reflect.Value {
+ i := args[0].Int()
+ j := args[1].Int()
+ b := x[i] < x[j]
+ return []reflect.Value{reflect.ValueOf(b)}
+ }).Interface().(func(i, j int) bool)
+
+ sort.SliceStable(x, isLessReflect)
+
+ for i := 0; i < length-1; i++ {
+ if x[i] >= x[i+1] {
+ log.Fatalf("not sorted! (length=%v, idx=%v)\n%v\n", length, i, x)
+ }
+ }
+}
diff --git a/test/fixedbugs/issue57309.go b/test/fixedbugs/issue57309.go
new file mode 100644
index 0000000000000000000000000000000000000000..ec6a397574aa652708bc1b758f7ae662669c3a2e
--- /dev/null
+++ b/test/fixedbugs/issue57309.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2022 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
+
+type I interface {
+ M()
+}
+
+type S struct {
+}
+
+func (*S) M() {
+}
+
+func main() {
+ func() {
+ I(&S{}).M()
+ }()
+}