summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--VERSION4
-rw-r--r--src/archive/zip/reader.go8
-rw-r--r--src/archive/zip/reader_test.go8
-rw-r--r--src/archive/zip/testdata/comment-truncated.zipbin0 -> 216 bytes
-rw-r--r--src/cmd/cgo/internal/testplugin/plugin_test.go19
-rw-r--r--src/cmd/compile/internal/compare/compare.go7
-rw-r--r--src/cmd/compile/internal/noder/irgen.go26
-rw-r--r--src/cmd/compile/internal/walk/assign.go43
-rw-r--r--src/cmd/go/internal/toolchain/select.go11
-rw-r--r--src/cmd/go/testdata/script/build_issue48319.txt7
-rw-r--r--src/cmd/go/testdata/script/build_plugin_reproducible.txt7
-rw-r--r--src/cmd/go/testdata/script/gotoolchain_issue66175.txt109
-rw-r--r--src/cmd/link/internal/ld/macho.go20
-rw-r--r--src/crypto/x509/root_darwin_test.go131
-rw-r--r--src/crypto/x509/root_windows_test.go127
-rw-r--r--src/net/netip/inlining_test.go2
-rw-r--r--src/net/netip/netip.go26
-rw-r--r--src/net/netip/netip_test.go50
-rw-r--r--src/os/file_unix.go4
-rw-r--r--src/os/removeall_at.go34
-rw-r--r--src/runtime/cgo/gcc_stack_unix.c5
-rw-r--r--src/runtime/metrics_test.go35
-rw-r--r--src/runtime/mgcsweep.go23
-rw-r--r--src/syscall/zerrors_solaris_amd64.go1
-rw-r--r--test/fixedbugs/issue67141.go15
-rw-r--r--test/fixedbugs/issue67160.go32
-rw-r--r--test/fixedbugs/issue67255.go33
27 files changed, 451 insertions, 336 deletions
diff --git a/VERSION b/VERSION
index e2a3741..4d7d2d8 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-go1.22.3
-time 2024-05-01T19:49:47Z
+go1.22.4
+time 2024-05-30T19:26:07Z
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index ff6fedf..60b34b7 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -699,9 +699,13 @@ func findSignatureInBlock(b []byte) int {
if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
// n is length of comment
n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
- if n+directoryEndLen+i <= len(b) {
- return i
+ if n+directoryEndLen+i > len(b) {
+ // Truncated comment.
+ // Some parsers (such as Info-ZIP) ignore the truncated comment
+ // rather than treating it as a hard error.
+ return -1
}
+ return i
}
}
return -1
diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go
index 631515c..9a77c1a 100644
--- a/src/archive/zip/reader_test.go
+++ b/src/archive/zip/reader_test.go
@@ -570,6 +570,14 @@ var tests = []ZipTest{
},
},
},
+ // Issue 66869: Don't skip over an EOCDR with a truncated comment.
+ // The test file sneakily hides a second EOCDR before the first one;
+ // previously we would extract one file ("file") from this archive,
+ // while most other tools would reject the file or extract a different one ("FILE").
+ {
+ Name: "comment-truncated.zip",
+ Error: ErrFormat,
+ },
}
func TestReader(t *testing.T) {
diff --git a/src/archive/zip/testdata/comment-truncated.zip b/src/archive/zip/testdata/comment-truncated.zip
new file mode 100644
index 0000000..1bc19a8
--- /dev/null
+++ b/src/archive/zip/testdata/comment-truncated.zip
Binary files differ
diff --git a/src/cmd/cgo/internal/testplugin/plugin_test.go b/src/cmd/cgo/internal/testplugin/plugin_test.go
index 1e32ff8..4900ada 100644
--- a/src/cmd/cgo/internal/testplugin/plugin_test.go
+++ b/src/cmd/cgo/internal/testplugin/plugin_test.go
@@ -74,6 +74,7 @@ func testMain(m *testing.M) int {
}
defer os.RemoveAll(GOPATH)
tmpDir = GOPATH
+ fmt.Printf("TMPDIR=%s\n", tmpDir)
modRoot := filepath.Join(GOPATH, "src", "testplugin")
altRoot := filepath.Join(GOPATH, "alt", "src", "testplugin")
@@ -395,3 +396,21 @@ func TestIssue62430(t *testing.T) {
goCmd(t, "build", "-o", "issue62430.exe", "./issue62430/main.go")
run(t, "./issue62430.exe")
}
+
+func TestTextSectionSplit(t *testing.T) {
+ globalSkip(t)
+ if runtime.GOOS != "darwin" || runtime.GOARCH != "arm64" {
+ t.Skipf("text section splitting is not done in %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+
+ // Use -ldflags=-debugtextsize=262144 to let the linker split text section
+ // at a smaller size threshold, so it actually splits for the test binary.
+ goCmd(nil, "build", "-ldflags=-debugtextsize=262144", "-o", "host-split.exe", "./host")
+ run(t, "./host-split.exe")
+
+ // Check that we did split text sections.
+ syms := goCmd(nil, "tool", "nm", "host-split.exe")
+ if !strings.Contains(syms, "runtime.text.1") {
+ t.Errorf("runtime.text.1 not found, text section not split?")
+ }
+}
diff --git a/src/cmd/compile/internal/compare/compare.go b/src/cmd/compile/internal/compare/compare.go
index e165cd6..cb2f84e 100644
--- a/src/cmd/compile/internal/compare/compare.go
+++ b/src/cmd/compile/internal/compare/compare.go
@@ -148,7 +148,7 @@ func calculateCostForType(t *types.Type) int64 {
return EqStructCost(t)
case types.TSLICE:
// Slices are not comparable.
- base.Fatalf("eqStructFieldCost: unexpected slice type")
+ base.Fatalf("calculateCostForType: unexpected slice type")
case types.TARRAY:
elemCost := calculateCostForType(t.Elem())
cost = t.NumElem() * elemCost
@@ -371,6 +371,11 @@ func eqmem(p, q ir.Node, field int, size int64) ir.Node {
}
func eqmemfunc(size int64, t *types.Type) (fn *ir.Name, needsize bool) {
+ if !base.Ctxt.Arch.CanMergeLoads && t.Alignment() < int64(base.Ctxt.Arch.Alignment) && t.Alignment() < t.Size() {
+ // We can't use larger comparisons if the value might not be aligned
+ // enough for the larger comparison. See issues 46283 and 67160.
+ size = 0
+ }
switch size {
case 1, 2, 4, 8, 16:
buf := fmt.Sprintf("memequal%d", int(size)*8)
diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go
index e0b7bb9..145bcc8 100644
--- a/src/cmd/compile/internal/noder/irgen.go
+++ b/src/cmd/compile/internal/noder/irgen.go
@@ -34,7 +34,13 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
posBaseMap := make(map[*syntax.PosBase]*syntax.File)
for i, p := range noders {
files[i] = p.file
- posBaseMap[p.file.Pos().Base()] = p.file
+ // The file.Pos() is the position of the package clause.
+ // If there's a //line directive before that, file.Pos().Base()
+ // refers to that directive, not the file itself.
+ // Make sure to consistently map back to file base, here and
+ // when we look for a file in the conf.Error handler below,
+ // otherwise the file may not be found (was go.dev/issue/67141).
+ posBaseMap[fileBase(p.file.Pos())] = p.file
}
// typechecking
@@ -68,13 +74,12 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
terr := err.(types2.Error)
msg := terr.Msg
if versionErrorRx.MatchString(msg) {
- posBase := terr.Pos.Base()
- for !posBase.IsFileBase() { // line directive base
- posBase = posBase.Pos().Base()
- }
+ posBase := fileBase(terr.Pos)
fileVersion := info.FileVersions[posBase]
file := posBaseMap[posBase]
- if file.GoVersion == fileVersion {
+ if file == nil {
+ // This should never happen, but be careful and don't crash.
+ } else if file.GoVersion == fileVersion {
// If we have a version error caused by //go:build, report it.
msg = fmt.Sprintf("%s (file declares //go:build %s)", msg, fileVersion)
} else {
@@ -149,6 +154,15 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
return pkg, info
}
+// fileBase returns a file's position base given a position in the file.
+func fileBase(pos syntax.Pos) *syntax.PosBase {
+ base := pos.Base()
+ for !base.IsFileBase() { // line directive base
+ base = base.Pos().Base()
+ }
+ return base
+}
+
// A cycleFinder detects anonymous interface cycles (go.dev/issue/56103).
type cycleFinder struct {
cyclic map[*types2.Interface]bool
diff --git a/src/cmd/compile/internal/walk/assign.go b/src/cmd/compile/internal/walk/assign.go
index fc3b858..63b6a1d 100644
--- a/src/cmd/compile/internal/walk/assign.go
+++ b/src/cmd/compile/internal/walk/assign.go
@@ -623,21 +623,23 @@ func isAppendOfMake(n ir.Node) bool {
// panicmakeslicelen()
// }
// s := l1
-// n := len(s) + l2
-// // Compare n and s as uint so growslice can panic on overflow of len(s) + l2.
-// // cap is a positive int and n can become negative when len(s) + l2
-// // overflows int. Interpreting n when negative as uint makes it larger
-// // than cap(s). growslice will check the int n arg and panic if n is
-// // negative. This prevents the overflow from being undetected.
-// if uint(n) <= uint(cap(s)) {
-// s = s[:n]
-// } else {
-// s = growslice(T, s.ptr, n, s.cap, l2, T)
+// if l2 != 0 {
+// n := len(s) + l2
+// // Compare n and s as uint so growslice can panic on overflow of len(s) + l2.
+// // cap is a positive int and n can become negative when len(s) + l2
+// // overflows int. Interpreting n when negative as uint makes it larger
+// // than cap(s). growslice will check the int n arg and panic if n is
+// // negative. This prevents the overflow from being undetected.
+// if uint(n) <= uint(cap(s)) {
+// s = s[:n]
+// } else {
+// s = growslice(T, s.ptr, n, s.cap, l2, T)
+// }
+// // clear the new portion of the underlying array.
+// hp := &s[len(s)-l2]
+// hn := l2 * sizeof(T)
+// memclr(hp, hn)
// }
-// // clear the new portion of the underlying array.
-// hp := &s[len(s)-l2]
-// hn := l2 * sizeof(T)
-// memclr(hp, hn)
// }
// s
//
@@ -671,11 +673,18 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
s := typecheck.TempAt(base.Pos, ir.CurFunc, l1.Type())
nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, l1))
+ // if l2 != 0 {
+ // Avoid work if we're not appending anything. But more importantly,
+ // avoid allowing hp to be a past-the-end pointer when clearing. See issue 67255.
+ nifnz := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.ONE, l2, ir.NewInt(base.Pos, 0)), nil, nil)
+ nifnz.Likely = true
+ nodes = append(nodes, nifnz)
+
elemtype := s.Type().Elem()
// n := s.len + l2
nn := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
- nodes = append(nodes, ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), l2)))
+ nifnz.Body = append(nifnz.Body, ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), l2)))
// if uint(n) <= uint(s.cap)
nuint := typecheck.Conv(nn, types.Types[types.TUINT])
@@ -697,7 +706,7 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
l2)),
}
- nodes = append(nodes, nif)
+ nifnz.Body = append(nifnz.Body, nif)
// hp := &s[s.len - l2]
// TODO: &s[s.len] - hn?
@@ -723,7 +732,7 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
// if growslice isn't called do we need to do the zeroing ourselves.
nif.Body = append(nif.Body, clr...)
} else {
- nodes = append(nodes, clr...)
+ nifnz.Body = append(nifnz.Body, clr...)
}
typecheck.Stmts(nodes)
diff --git a/src/cmd/go/internal/toolchain/select.go b/src/cmd/go/internal/toolchain/select.go
index dcf3be9..14a8d3c 100644
--- a/src/cmd/go/internal/toolchain/select.go
+++ b/src/cmd/go/internal/toolchain/select.go
@@ -184,6 +184,13 @@ func Select() {
}
if gover.Compare(goVers, minVers) > 0 {
gotoolchain = "go" + goVers
+ // Starting with Go 1.21, the first released version has a .0 patch version suffix.
+ // Don't try to download a language version (sans patch component), such as go1.22.
+ // Instead, use the first toolchain of that language version, such as 1.22.0.
+ // See golang.org/issue/62278.
+ if gover.IsLang(goVers) && gover.Compare(goVers, "1.21") >= 0 {
+ gotoolchain += ".0"
+ }
gover.Startup.AutoGoVersion = goVers
gover.Startup.AutoToolchain = "" // in case we are overriding it for being too old
}
@@ -312,6 +319,10 @@ func Exec(gotoolchain string) {
dir, err := modfetch.Download(context.Background(), m)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
+ toolVers := gover.FromToolchain(gotoolchain)
+ if gover.IsLang(toolVers) && gover.Compare(toolVers, "1.21") >= 0 {
+ base.Fatalf("invalid toolchain: %s is a language version but not a toolchain version (%s.x)", gotoolchain, gotoolchain)
+ }
base.Fatalf("download %s for %s/%s: toolchain not available", gotoolchain, runtime.GOOS, runtime.GOARCH)
}
base.Fatalf("download %s: %v", gotoolchain, err)
diff --git a/src/cmd/go/testdata/script/build_issue48319.txt b/src/cmd/go/testdata/script/build_issue48319.txt
index 4543303..148d8f0 100644
--- a/src/cmd/go/testdata/script/build_issue48319.txt
+++ b/src/cmd/go/testdata/script/build_issue48319.txt
@@ -4,6 +4,13 @@
[short] skip
[!cgo] skip
+# This test has problems when run on the LUCI darwin longtest builder,
+# which uses a more contemporary Xcode version that is unfriendly to
+# reproducible builds (see issue #64947 for the gory details). Note
+# that individual developers running "go test cmd/go" on Darwin may
+# still run into failures depending on their Xcode version.
+[GOOS:darwin] [go-builder] skip
+
# This test is sensitive to cache invalidation,
# so use a separate build cache that we can control.
env GOCACHE=$WORK/gocache
diff --git a/src/cmd/go/testdata/script/build_plugin_reproducible.txt b/src/cmd/go/testdata/script/build_plugin_reproducible.txt
index 5369954..aa489df 100644
--- a/src/cmd/go/testdata/script/build_plugin_reproducible.txt
+++ b/src/cmd/go/testdata/script/build_plugin_reproducible.txt
@@ -1,6 +1,13 @@
[!buildmode:plugin] skip
[short] skip
+# This test has problems when run on the LUCI darwin longtest builder,
+# which uses a more contemporary Xcode version that is unfriendly to
+# reproducible builds (see issue #64947 for the gory details). Note
+# that individual developers running "go test cmd/go" on Darwin may
+# still run into failures depending on their Xcode version.
+[GOOS:darwin] [go-builder] skip
+
go build -trimpath -buildvcs=false -buildmode=plugin -o a.so main.go
go build -trimpath -buildvcs=false -buildmode=plugin -o b.so main.go
cmp -q a.so b.so
diff --git a/src/cmd/go/testdata/script/gotoolchain_issue66175.txt b/src/cmd/go/testdata/script/gotoolchain_issue66175.txt
new file mode 100644
index 0000000..5db4dbf
--- /dev/null
+++ b/src/cmd/go/testdata/script/gotoolchain_issue66175.txt
@@ -0,0 +1,109 @@
+env TESTGO_VERSION=go1.14
+
+# Clear the path so this test doesn't fail if the system running it\
+# has a binary named go1.21 or go1.22 on its path.
+[GOOS:plan9] env path=
+[!GOOS:plan9] env PATH=
+
+# check for invalid toolchain in go.mod
+go mod init m
+go mod edit -go=1.14 -toolchain=go1.22
+! go version
+stderr 'go: invalid toolchain: go1.22 is a language version but not a toolchain version \(go1.22.x\)'
+
+rm go.mod
+go mod init m
+go mod edit -go=1.14 -toolchain=go1.21
+! go version
+stderr 'go: invalid toolchain: go1.21 is a language version but not a toolchain version \(go1.21.x\)'
+
+rm go.mod
+go mod init m
+go mod edit -go=1.14 -toolchain=go1.20
+! go version
+stderr 'go: downloading go1.20 '
+
+
+# check for invalid GOTOOLCHAIN
+env GOTOOLCHAIN=go1.14
+go version
+stdout 'go1.14'
+
+env GOTOOLCHAIN=go1.20
+! go version
+stderr 'go: downloading go1.20 '
+
+env GOTOOLCHAIN=go1.21
+! go version
+stderr 'go: invalid toolchain: go1.21 is a language version but not a toolchain version \(go1.21.x\)'
+
+env GOTOOLCHAIN=go1.22
+! go version
+stderr 'go: invalid toolchain: go1.22 is a language version but not a toolchain version \(go1.22.x\)'
+
+env GOTOOLCHAIN=go1.20+auto
+! go version
+stderr 'go: downloading go1.20 '
+
+env GOTOOLCHAIN=go1.21+auto
+! go version
+stderr 'go: invalid toolchain: go1.21 is a language version but not a toolchain version \(go1.21.x\)'
+
+env GOTOOLCHAIN=go1.22+auto
+! go version
+stderr 'go: invalid toolchain: go1.22 is a language version but not a toolchain version \(go1.22.x\)'
+
+env GOTOOLCHAIN=go1.21rc3
+! go version
+stderr 'go: downloading go1.21rc3 '
+
+env GOTOOLCHAIN=go1.22rc2
+! go version
+stderr 'go: downloading go1.22rc2 '
+
+env GOTOOLCHAIN=go1.66
+! go version
+stderr 'go: invalid toolchain: go1.66 is a language version but not a toolchain version \(go1.66.x\)'
+
+env GOTOOLCHAIN=go1.18beta2
+! go version
+stderr 'go: downloading go1.18beta2 '
+
+# go1.X is okay for path lookups
+env GOTOOLCHAIN=go1.20+path
+! go version
+stderr 'go: cannot find "go1.20" in PATH'
+
+env GOTOOLCHAIN=go1.21+path
+! go version
+stderr 'go: cannot find "go1.21" in PATH'
+
+env GOTOOLCHAIN=go1.22+path
+! go version
+stderr 'go: cannot find "go1.22" in PATH'
+
+# When a toolchain download takes place, download 1.X.0
+env GOTOOLCHAIN=auto
+rm go.mod
+go mod init m
+go mod edit -go=1.300 -toolchain=none
+! go version
+stderr 'go: downloading go1.300.0 '
+
+rm go.mod
+go mod init m
+go mod edit -go=1.21 -toolchain=none
+! go version
+stderr 'go: downloading go1.21.0 '
+
+rm go.mod
+go mod init m
+go mod edit -go=1.22 -toolchain=none
+! go version
+stderr 'go: downloading go1.22.0 '
+
+rm go.mod
+go mod init m
+go mod edit -go=1.15 -toolchain=none
+! go version
+stderr 'go: downloading go1.15 '
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index fc38b0d..a36043c 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -901,21 +901,25 @@ func collectmachosyms(ctxt *Link) {
// Add special runtime.text and runtime.etext symbols (which are local).
// We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
// See data.go:/textaddress
+ // NOTE: runtime.text.N symbols (if we split text sections) are not added, though,
+ // so we handle them here.
if !*FlagS {
if !ctxt.DynlinkingGo() {
s := ldr.Lookup("runtime.text", 0)
if ldr.SymType(s) == sym.STEXT {
addsym(s)
}
- for n := range Segtext.Sections[1:] {
- s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
- if s != 0 {
- addsym(s)
- } else {
- break
- }
+ }
+ for n := range Segtext.Sections[1:] {
+ s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
+ if s != 0 {
+ addsym(s)
+ } else {
+ break
}
- s = ldr.Lookup("runtime.etext", 0)
+ }
+ if !ctxt.DynlinkingGo() {
+ s := ldr.Lookup("runtime.etext", 0)
if ldr.SymType(s) == sym.STEXT {
addsym(s)
}
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
deleted file mode 100644
index e6b52e9..0000000
--- a/src/crypto/x509/root_darwin_test.go
+++ /dev/null
@@ -1,131 +0,0 @@
-// 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.
-
-package x509_test
-
-import (
- "crypto/tls"
- "crypto/x509"
- "internal/testenv"
- "testing"
- "time"
-)
-
-func TestPlatformVerifierLegacy(t *testing.T) {
- // TODO(#52108): This can be removed once the synthetic test root is deployed on
- // builders.
- if !testenv.HasExternalNetwork() {
- t.Skip()
- }
-
- getChain := func(host string) []*x509.Certificate {
- t.Helper()
- c, err := tls.Dial("tcp", host+":443", &tls.Config{InsecureSkipVerify: true})
- if err != nil {
- t.Fatalf("tls connection failed: %s", err)
- }
- return c.ConnectionState().PeerCertificates
- }
-
- tests := []struct {
- name string
- host string
- verifyName string
- verifyTime time.Time
- verifyEKU []x509.ExtKeyUsage
- expectedErr string
- skip string
- }{
- {
- // whatever google.com serves should, hopefully, be trusted
- name: "valid chain",
- host: "google.com",
- },
- {
- name: "expired leaf",
- host: "expired.badssl.com",
- 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: certificate is valid for *.badssl.com, badssl.com, not wrong.host.badssl.com",
- },
- {
- name: "self-signed leaf",
- host: "self-signed.badssl.com",
- expectedErr: "x509: certificate signed by unknown authority",
- },
- {
- name: "untrusted root",
- host: "untrusted-root.badssl.com",
- expectedErr: "x509: certificate signed by unknown authority",
- },
- {
- name: "revoked leaf",
- host: "revoked.badssl.com",
- expectedErr: "x509: “revoked.badssl.com” certificate is revoked",
- skip: "skipping; broken on recent versions of macOS. See issue 57428.",
- },
- {
- name: "leaf missing SCTs",
- host: "no-sct.badssl.com",
- expectedErr: "x509: “no-sct.badssl.com” certificate is not standards compliant",
- skip: "skipping; broken on recent versions of macOS. See issue 57428.",
- },
- {
- name: "expired leaf (custom time)",
- host: "google.com",
- verifyTime: time.Time{}.Add(time.Hour),
- expectedErr: "x509: certificate has expired or is not yet valid: “*.google.com” certificate is expired",
- },
- {
- name: "valid chain (custom time)",
- host: "google.com",
- verifyTime: time.Now(),
- },
- {
- name: "leaf doesn't have acceptable ExtKeyUsage",
- host: "google.com",
- expectedErr: "x509: certificate specifies an incompatible key usage",
- verifyEKU: []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection},
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- if tc.skip != "" {
- t.Skip(tc.skip)
- }
-
- chain := getChain(tc.host)
- var opts x509.VerifyOptions
- if len(chain) > 1 {
- opts.Intermediates = x509.NewCertPool()
- for _, c := range chain[1:] {
- opts.Intermediates.AddCert(c)
- }
- }
- if tc.verifyName != "" {
- opts.DNSName = tc.verifyName
- }
- if !tc.verifyTime.IsZero() {
- opts.CurrentTime = tc.verifyTime
- }
- if len(tc.verifyEKU) > 0 {
- opts.KeyUsages = tc.verifyEKU
- }
-
- _, err := chain[0].Verify(opts)
- if err != nil && tc.expectedErr == "" {
- t.Errorf("unexpected verification error: %s", err)
- } else if err != nil && err.Error() != tc.expectedErr {
- t.Errorf("unexpected verification error: got %q, want %q", err.Error(), tc.expectedErr)
- } else if err == nil && tc.expectedErr != "" {
- t.Errorf("unexpected verification success: want %q", tc.expectedErr)
- }
- })
- }
-}
diff --git a/src/crypto/x509/root_windows_test.go b/src/crypto/x509/root_windows_test.go
deleted file mode 100644
index 1372c04..0000000
--- a/src/crypto/x509/root_windows_test.go
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package x509_test
-
-import (
- "crypto/tls"
- "crypto/x509"
- "errors"
- "internal/testenv"
- "net"
- "strings"
- "syscall"
- "testing"
- "time"
-)
-
-func TestPlatformVerifierLegacy(t *testing.T) {
- // TODO(#52108): This can be removed once the synthetic test root is deployed on
- // builders.
- if !testenv.HasExternalNetwork() {
- t.Skip()
- }
-
- getChain := func(t *testing.T, host string) []*x509.Certificate {
- t.Helper()
- c, err := tls.Dial("tcp", host+":443", &tls.Config{InsecureSkipVerify: true})
- if err != nil {
- // From https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2,
- // matching the error string observed in https://go.dev/issue/52094.
- const WSATRY_AGAIN syscall.Errno = 11002
- var errDNS *net.DNSError
- if strings.HasSuffix(host, ".badssl.com") && errors.As(err, &errDNS) && strings.HasSuffix(errDNS.Err, WSATRY_AGAIN.Error()) {
- t.Log(err)
- testenv.SkipFlaky(t, 52094)
- }
-
- t.Fatalf("tls connection failed: %s", err)
- }
- return c.ConnectionState().PeerCertificates
- }
-
- tests := []struct {
- name string
- host string
- verifyName string
- verifyTime time.Time
- expectedErr string
- }{
- {
- // whatever google.com serves should, hopefully, be trusted
- name: "valid chain",
- host: "google.com",
- },
- {
- name: "valid chain (dns check)",
- host: "google.com",
- verifyName: "google.com",
- },
- {
- name: "valid chain (fqdn dns check)",
- host: "google.com.",
- verifyName: "google.com.",
- },
- {
- name: "expired leaf",
- host: "expired.badssl.com",
- expectedErr: "x509: certificate has expired or is not yet valid: ",
- },
- {
- name: "wrong host for leaf",
- host: "wrong.host.badssl.com",
- verifyName: "wrong.host.badssl.com",
- 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: certificate signed by unknown authority",
- },
- {
- name: "untrusted root",
- host: "untrusted-root.badssl.com",
- expectedErr: "x509: certificate signed by unknown authority",
- },
- {
- name: "expired leaf (custom time)",
- host: "google.com",
- verifyTime: time.Time{}.Add(time.Hour),
- expectedErr: "x509: certificate has expired or is not yet valid: ",
- },
- {
- name: "valid chain (custom time)",
- host: "google.com",
- verifyTime: time.Now(),
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- chain := getChain(t, tc.host)
- var opts x509.VerifyOptions
- if len(chain) > 1 {
- opts.Intermediates = x509.NewCertPool()
- for _, c := range chain[1:] {
- opts.Intermediates.AddCert(c)
- }
- }
- if tc.verifyName != "" {
- opts.DNSName = tc.verifyName
- }
- if !tc.verifyTime.IsZero() {
- opts.CurrentTime = tc.verifyTime
- }
-
- _, err := chain[0].Verify(opts)
- if err != nil && tc.expectedErr == "" {
- t.Errorf("unexpected verification error: %s", err)
- } else if err != nil && err.Error() != tc.expectedErr {
- t.Errorf("unexpected verification error: got %q, want %q", err.Error(), tc.expectedErr)
- } else if err == nil && tc.expectedErr != "" {
- t.Errorf("unexpected verification success: want %q", tc.expectedErr)
- }
- })
- }
-}
diff --git a/src/net/netip/inlining_test.go b/src/net/netip/inlining_test.go
index b521eee..98584b0 100644
--- a/src/net/netip/inlining_test.go
+++ b/src/net/netip/inlining_test.go
@@ -36,8 +36,6 @@ func TestInlining(t *testing.T) {
"Addr.Is4",
"Addr.Is4In6",
"Addr.Is6",
- "Addr.IsLoopback",
- "Addr.IsMulticast",
"Addr.IsInterfaceLocalMulticast",
"Addr.IsValid",
"Addr.IsUnspecified",
diff --git a/src/net/netip/netip.go b/src/net/netip/netip.go
index 7a189e8..92cb57e 100644
--- a/src/net/netip/netip.go
+++ b/src/net/netip/netip.go
@@ -508,6 +508,10 @@ func (ip Addr) hasZone() bool {
// IsLinkLocalUnicast reports whether ip is a link-local unicast address.
func (ip Addr) IsLinkLocalUnicast() bool {
+ if ip.Is4In6() {
+ ip = ip.Unmap()
+ }
+
// Dynamic Configuration of IPv4 Link-Local Addresses
// https://datatracker.ietf.org/doc/html/rfc3927#section-2.1
if ip.Is4() {
@@ -523,6 +527,10 @@ func (ip Addr) IsLinkLocalUnicast() bool {
// IsLoopback reports whether ip is a loopback address.
func (ip Addr) IsLoopback() bool {
+ if ip.Is4In6() {
+ ip = ip.Unmap()
+ }
+
// Requirements for Internet Hosts -- Communication Layers (3.2.1.3 Addressing)
// https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3
if ip.Is4() {
@@ -538,6 +546,10 @@ func (ip Addr) IsLoopback() bool {
// IsMulticast reports whether ip is a multicast address.
func (ip Addr) IsMulticast() bool {
+ if ip.Is4In6() {
+ ip = ip.Unmap()
+ }
+
// Host Extensions for IP Multicasting (4. HOST GROUP ADDRESSES)
// https://datatracker.ietf.org/doc/html/rfc1112#section-4
if ip.Is4() {
@@ -556,7 +568,7 @@ func (ip Addr) IsMulticast() bool {
func (ip Addr) IsInterfaceLocalMulticast() bool {
// IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses)
// https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1
- if ip.Is6() {
+ if ip.Is6() && !ip.Is4In6() {
return ip.v6u16(0)&0xff0f == 0xff01
}
return false // zero value
@@ -564,6 +576,10 @@ func (ip Addr) IsInterfaceLocalMulticast() bool {
// IsLinkLocalMulticast reports whether ip is a link-local multicast address.
func (ip Addr) IsLinkLocalMulticast() bool {
+ if ip.Is4In6() {
+ ip = ip.Unmap()
+ }
+
// IPv4 Multicast Guidelines (4. Local Network Control Block (224.0.0/24))
// https://datatracker.ietf.org/doc/html/rfc5771#section-4
if ip.Is4() {
@@ -592,6 +608,10 @@ func (ip Addr) IsGlobalUnicast() bool {
return false
}
+ if ip.Is4In6() {
+ ip = ip.Unmap()
+ }
+
// Match package net's IsGlobalUnicast logic. Notably private IPv4 addresses
// and ULA IPv6 addresses are still considered "global unicast".
if ip.Is4() && (ip == IPv4Unspecified() || ip == AddrFrom4([4]byte{255, 255, 255, 255})) {
@@ -609,6 +629,10 @@ func (ip Addr) IsGlobalUnicast() bool {
// ip is in 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, or fc00::/7. This is the
// same as [net.IP.IsPrivate].
func (ip Addr) IsPrivate() bool {
+ if ip.Is4In6() {
+ ip = ip.Unmap()
+ }
+
// Match the stdlib's IsPrivate logic.
if ip.Is4() {
// RFC 1918 allocates 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 as
diff --git a/src/net/netip/netip_test.go b/src/net/netip/netip_test.go
index a748ac3..56a6c7d 100644
--- a/src/net/netip/netip_test.go
+++ b/src/net/netip/netip_test.go
@@ -591,10 +591,13 @@ func TestIPProperties(t *testing.T) {
ilm6 = mustIP("ff01::1")
ilmZone6 = mustIP("ff01::1%eth0")
- private4a = mustIP("10.0.0.1")
- private4b = mustIP("172.16.0.1")
- private4c = mustIP("192.168.1.1")
- private6 = mustIP("fd00::1")
+ private4a = mustIP("10.0.0.1")
+ private4b = mustIP("172.16.0.1")
+ private4c = mustIP("192.168.1.1")
+ private6 = mustIP("fd00::1")
+ private6mapped4a = mustIP("::ffff:10.0.0.1")
+ private6mapped4b = mustIP("::ffff:172.16.0.1")
+ private6mapped4c = mustIP("::ffff:192.168.1.1")
)
tests := []struct {
@@ -619,6 +622,11 @@ func TestIPProperties(t *testing.T) {
globalUnicast: true,
},
{
+ name: "unicast v6 mapped v4Addr",
+ ip: AddrFrom16(unicast4.As16()),
+ globalUnicast: true,
+ },
+ {
name: "unicast v6Addr",
ip: unicast6,
globalUnicast: true,
@@ -640,6 +648,12 @@ func TestIPProperties(t *testing.T) {
multicast: true,
},
{
+ name: "multicast v6 mapped v4Addr",
+ ip: AddrFrom16(multicast4.As16()),
+ linkLocalMulticast: true,
+ multicast: true,
+ },
+ {
name: "multicast v6Addr",
ip: multicast6,
linkLocalMulticast: true,
@@ -657,6 +671,11 @@ func TestIPProperties(t *testing.T) {
linkLocalUnicast: true,
},
{
+ name: "link-local unicast v6 mapped v4Addr",
+ ip: AddrFrom16(llu4.As16()),
+ linkLocalUnicast: true,
+ },
+ {
name: "link-local unicast v6Addr",
ip: llu6,
linkLocalUnicast: true,
@@ -682,6 +701,11 @@ func TestIPProperties(t *testing.T) {
loopback: true,
},
{
+ name: "loopback v6 mapped v4Addr",
+ ip: AddrFrom16(IPv6Loopback().As16()),
+ loopback: true,
+ },
+ {
name: "interface-local multicast v6Addr",
ip: ilm6,
interfaceLocalMulticast: true,
@@ -718,6 +742,24 @@ func TestIPProperties(t *testing.T) {
private: true,
},
{
+ name: "private v6 mapped v4Addr 10/8",
+ ip: private6mapped4a,
+ globalUnicast: true,
+ private: true,
+ },
+ {
+ name: "private v6 mapped v4Addr 172.16/12",
+ ip: private6mapped4b,
+ globalUnicast: true,
+ private: true,
+ },
+ {
+ name: "private v6 mapped v4Addr 192.168/16",
+ ip: private6mapped4c,
+ globalUnicast: true,
+ private: true,
+ },
+ {
name: "unspecified v4Addr",
ip: IPv4Unspecified(),
unspecified: true,
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index a527b23..649ec3e 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -157,7 +157,7 @@ const (
kindNonBlock
// kindNoPoll means that we should not put the descriptor into
// non-blocking mode, because we know it is not a pipe or FIFO.
- // Used by openFdAt for directories.
+ // Used by openDirAt for directories.
kindNoPoll
)
@@ -256,7 +256,7 @@ func epipecheck(file *File, e error) {
const DevNull = "/dev/null"
// openFileNolog is the Unix implementation of OpenFile.
-// Changes here should be reflected in openFdAt, if relevant.
+// Changes here should be reflected in openDirAt, if relevant.
func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
setSticky := false
if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go
index 8ea5df4..774ca15 100644
--- a/src/os/removeall_at.go
+++ b/src/os/removeall_at.go
@@ -74,22 +74,7 @@ func removeAllFrom(parent *File, base string) error {
if err != syscall.EISDIR && err != syscall.EPERM && err != syscall.EACCES {
return &PathError{Op: "unlinkat", Path: base, Err: err}
}
-
- // Is this a directory we need to recurse into?
- var statInfo syscall.Stat_t
- statErr := ignoringEINTR(func() error {
- return unix.Fstatat(parentFd, base, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
- })
- if statErr != nil {
- if IsNotExist(statErr) {
- return nil
- }
- return &PathError{Op: "fstatat", Path: base, Err: statErr}
- }
- if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR {
- // Not a directory; return the error from the unix.Unlinkat.
- return &PathError{Op: "unlinkat", Path: base, Err: err}
- }
+ uErr := err
// Remove the directory's entries.
var recurseErr error
@@ -98,11 +83,15 @@ func removeAllFrom(parent *File, base string) error {
var respSize int
// Open the directory to recurse into
- file, err := openFdAt(parentFd, base)
+ file, err := openDirAt(parentFd, base)
if err != nil {
if IsNotExist(err) {
return nil
}
+ if err == syscall.ENOTDIR {
+ // Not a directory; return the error from the unix.Unlinkat.
+ return &PathError{Op: "unlinkat", Path: base, Err: uErr}
+ }
recurseErr = &PathError{Op: "openfdat", Path: base, Err: err}
break
}
@@ -168,16 +157,19 @@ func removeAllFrom(parent *File, base string) error {
return &PathError{Op: "unlinkat", Path: base, Err: unlinkError}
}
-// openFdAt opens path relative to the directory in fd.
-// Other than that this should act like openFileNolog.
+// openDirAt opens a directory name relative to the directory referred to by
+// the file descriptor dirfd. If name is anything but a directory (this
+// includes a symlink to one), it should return an error. Other than that this
+// should act like openFileNolog.
+//
// This acts like openFileNolog rather than OpenFile because
// we are going to (try to) remove the file.
// The contents of this file are not relevant for test caching.
-func openFdAt(dirfd int, name string) (*File, error) {
+func openDirAt(dirfd int, name string) (*File, error) {
var r int
for {
var e error
- r, e = unix.Openat(dirfd, name, O_RDONLY|syscall.O_CLOEXEC, 0)
+ r, e = unix.Openat(dirfd, name, O_RDONLY|syscall.O_CLOEXEC|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
if e == nil {
break
}
diff --git a/src/runtime/cgo/gcc_stack_unix.c b/src/runtime/cgo/gcc_stack_unix.c
index f3fead9..98a75a1 100644
--- a/src/runtime/cgo/gcc_stack_unix.c
+++ b/src/runtime/cgo/gcc_stack_unix.c
@@ -18,6 +18,9 @@ x_cgo_getstackbound(uintptr bounds[2])
void *addr;
size_t size;
+ // Needed before pthread_getattr_np, too, since before glibc 2.32
+ // it did not call pthread_attr_init in all cases (see #65625).
+ pthread_attr_init(&attr);
#if defined(__GLIBC__) || (defined(__sun) && !defined(__illumos__))
// pthread_getattr_np is a GNU extension supported in glibc.
// Solaris is not glibc but does support pthread_getattr_np
@@ -25,11 +28,9 @@ x_cgo_getstackbound(uintptr bounds[2])
pthread_getattr_np(pthread_self(), &attr); // GNU extension
pthread_attr_getstack(&attr, &addr, &size); // low address
#elif defined(__illumos__)
- pthread_attr_init(&attr);
pthread_attr_get_np(pthread_self(), &attr);
pthread_attr_getstack(&attr, &addr, &size); // low address
#else
- pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
addr = __builtin_frame_address(0) + 4096 - size;
#endif
diff --git a/src/runtime/metrics_test.go b/src/runtime/metrics_test.go
index d7f4133..5866107 100644
--- a/src/runtime/metrics_test.go
+++ b/src/runtime/metrics_test.go
@@ -1290,3 +1290,38 @@ func (w *contentionWorker) run() {
for w.fn() {
}
}
+
+func TestMetricHeapUnusedLargeObjectOverflow(t *testing.T) {
+ // This test makes sure /memory/classes/heap/unused:bytes
+ // doesn't overflow when allocating and deallocating large
+ // objects. It is a regression test for #67019.
+ done := make(chan struct{})
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for {
+ for i := 0; i < 10; i++ {
+ runtime.Escape(make([]byte, 1<<20))
+ }
+ runtime.GC()
+ select {
+ case <-done:
+ return
+ default:
+ }
+ }
+ }()
+ s := []metrics.Sample{
+ {Name: "/memory/classes/heap/unused:bytes"},
+ }
+ for i := 0; i < 1000; i++ {
+ metrics.Read(s)
+ if s[0].Value.Uint64() > 1<<40 {
+ t.Errorf("overflow")
+ break
+ }
+ }
+ done <- struct{}{}
+ wg.Wait()
+}
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index 3dbe9bc..35be794 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -770,6 +770,19 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
if nfreed != 0 {
// Free large object span to heap.
+ // Count the free in the consistent, external stats.
+ //
+ // Do this before freeSpan, which might update heapStats' inHeap
+ // value. If it does so, then metrics that subtract object footprint
+ // from inHeap might overflow. See #67019.
+ stats := memstats.heapStats.acquire()
+ atomic.Xadd64(&stats.largeFreeCount, 1)
+ atomic.Xadd64(&stats.largeFree, int64(size))
+ memstats.heapStats.release()
+
+ // Count the free in the inconsistent, internal stats.
+ gcController.totalFree.Add(int64(size))
+
// NOTE(rsc,dvyukov): The original implementation of efence
// in CL 22060046 used sysFree instead of sysFault, so that
// the operating system would eventually give the memory
@@ -802,16 +815,6 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
// invalid pointer. See arena.go:(*mheap).allocUserArenaChunk.
*(*uintptr)(unsafe.Pointer(&s.largeType)) = 0
}
-
- // Count the free in the consistent, external stats.
- stats := memstats.heapStats.acquire()
- atomic.Xadd64(&stats.largeFreeCount, 1)
- atomic.Xadd64(&stats.largeFree, int64(size))
- memstats.heapStats.release()
-
- // Count the free in the inconsistent, internal stats.
- gcController.totalFree.Add(int64(size))
-
return true
}
diff --git a/src/syscall/zerrors_solaris_amd64.go b/src/syscall/zerrors_solaris_amd64.go
index 4a1d9c3..b2c81d9 100644
--- a/src/syscall/zerrors_solaris_amd64.go
+++ b/src/syscall/zerrors_solaris_amd64.go
@@ -634,6 +634,7 @@ const (
O_APPEND = 0x8
O_CLOEXEC = 0x800000
O_CREAT = 0x100
+ O_DIRECTORY = 0x1000000
O_DSYNC = 0x40
O_EXCL = 0x400
O_EXEC = 0x400000
diff --git a/test/fixedbugs/issue67141.go b/test/fixedbugs/issue67141.go
new file mode 100644
index 0000000..0464d1f
--- /dev/null
+++ b/test/fixedbugs/issue67141.go
@@ -0,0 +1,15 @@
+// errorcheck -lang=go1.22
+
+//go:build go1.21
+
+// We need a line directive before the package clause,
+// but don't change file name or position so that the
+// error message appears at the right place.
+
+//line issue67141.go:10
+package p
+
+func _() {
+ for range 10 { // ERROR "cannot range over 10"
+ }
+}
diff --git a/test/fixedbugs/issue67160.go b/test/fixedbugs/issue67160.go
new file mode 100644
index 0000000..be45a61
--- /dev/null
+++ b/test/fixedbugs/issue67160.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test to make sure that we don't try using larger loads for
+// generated equality functions on architectures that can't do
+// unaligned loads.
+
+package main
+
+// T has a big field that wants to be compared with larger loads/stores.
+// T is "special" because of the unnamed field, so it needs a generated equality function.
+// T is an odd number of bytes in size and has alignment 1.
+type T struct {
+ src [8]byte
+ _ byte
+}
+
+// U contains 8 copies of T, each at a different %8 alignment.
+type U [8]T
+
+//go:noinline
+func f(x, y *U) bool {
+ return *x == *y
+}
+
+func main() {
+ var a U
+ _ = f(&a, &a)
+}
diff --git a/test/fixedbugs/issue67255.go b/test/fixedbugs/issue67255.go
new file mode 100644
index 0000000..7ca7a23
--- /dev/null
+++ b/test/fixedbugs/issue67255.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2024 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
+
+var zero int
+
+var sink any
+
+func main() {
+ var objs [][]*byte
+ for i := 10; i < 200; i++ {
+ // The objects we're allocating here are pointer-ful. Some will
+ // max out their size class, which are the ones we want.
+ // We also allocate from small to large, so that the object which
+ // maxes out its size class is the last one allocated in that class.
+ // This allocation pattern leaves the next object in the class
+ // unallocated, which we need to reproduce the bug.
+ objs = append(objs, make([]*byte, i))
+ }
+ sink = objs // force heap allocation
+
+ // Bug will happen as soon as the write barrier turns on.
+ for range 10000 {
+ sink = make([]*byte, 1024)
+ for _, s := range objs {
+ s = append(s, make([]*byte, zero)...)
+ }
+ }
+}