summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-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/compile/internal/compare/compare.go7
-rw-r--r--src/cmd/go/internal/modfetch/codehost/git.go24
-rw-r--r--src/cmd/go/internal/toolchain/select.go11
-rw-r--r--src/cmd/go/testdata/script/get_issue53955.txt79
-rw-r--r--src/cmd/go/testdata/script/gotoolchain_issue66175.txt109
-rw-r--r--src/cmd/go/testdata/script/mod_download_git_bareRepository.txt17
-rw-r--r--src/cmd/go/testdata/script/mod_download_git_decorate_full.txt16
-rw-r--r--src/cmd/go/testdata/script/mod_download_issue51114.txt15
-rw-r--r--src/cmd/go/testdata/script/mod_download_private_vcs.txt15
-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/metrics_test.go35
-rw-r--r--src/runtime/mgcsweep.go23
-rw-r--r--src/syscall/zerrors_solaris_amd64.go1
-rw-r--r--test/fixedbugs/issue67160.go32
24 files changed, 451 insertions, 327 deletions
diff --git a/VERSION b/VERSION
index e8ac3fb..1194c3f 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-go1.21.10
-time 2024-05-01T19:49:47Z
+go1.21.11
+time 2024-05-30T19:26:07Z
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index 1fde1de..20356bd 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 a67c335..d892595 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/compile/internal/compare/compare.go b/src/cmd/compile/internal/compare/compare.go
index 1674065..e848e1c 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
@@ -374,6 +374,11 @@ func eqmem(p ir.Node, q ir.Node, field *types.Sym, 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 {
default:
fn = typecheck.LookupRuntime("memequal")
diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go
index d1a18a8..294e50f 100644
--- a/src/cmd/go/internal/modfetch/codehost/git.go
+++ b/src/cmd/go/internal/modfetch/codehost/git.go
@@ -18,6 +18,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
+ "slices"
"sort"
"strconv"
"strings"
@@ -154,7 +155,7 @@ type gitRepo struct {
refsErr error
localTagsOnce sync.Once
- localTags map[string]bool
+ localTags sync.Map // map[string]bool
}
const (
@@ -166,7 +167,6 @@ const (
// loadLocalTags loads tag references from the local git cache
// into the map r.localTags.
-// Should only be called as r.localTagsOnce.Do(r.loadLocalTags).
func (r *gitRepo) loadLocalTags(ctx context.Context) {
// The git protocol sends all known refs and ls-remote filters them on the client side,
// so we might as well record both heads and tags in one shot.
@@ -176,10 +176,9 @@ func (r *gitRepo) loadLocalTags(ctx context.Context) {
return
}
- r.localTags = make(map[string]bool)
for _, line := range strings.Split(string(out), "\n") {
if line != "" {
- r.localTags[line] = true
+ r.localTags.Store(line, true)
}
}
}
@@ -430,7 +429,7 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro
// Maybe rev is a tag we already have locally.
// (Note that we're excluding branches, which can be stale.)
r.localTagsOnce.Do(func() { r.loadLocalTags(ctx) })
- if r.localTags[rev] {
+ if _, ok := r.localTags.Load(rev); ok {
return r.statLocal(ctx, rev, "refs/tags/"+rev)
}
@@ -506,11 +505,18 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro
// Either way, try a local stat before falling back to network I/O.
if !didStatLocal {
if info, err := r.statLocal(ctx, rev, hash); err == nil {
- if after, found := strings.CutPrefix(ref, "refs/tags/"); found {
- // Make sure tag exists, so it will be in localTags next time the go command is run.
- Run(ctx, r.dir, "git", "tag", after, hash)
+ tag, fromTag := strings.CutPrefix(ref, "refs/tags/")
+ if fromTag && !slices.Contains(info.Tags, tag) {
+ // The local repo includes the commit hash we want, but it is missing
+ // the corresponding tag. Add that tag and try again.
+ _, err := Run(ctx, r.dir, "git", "tag", tag, hash)
+ if err != nil {
+ return nil, err
+ }
+ r.localTags.Store(tag, true)
+ return r.statLocal(ctx, rev, ref)
}
- return info, nil
+ return info, err
}
}
diff --git a/src/cmd/go/internal/toolchain/select.go b/src/cmd/go/internal/toolchain/select.go
index 3446a48..b1b8864 100644
--- a/src/cmd/go/internal/toolchain/select.go
+++ b/src/cmd/go/internal/toolchain/select.go
@@ -183,6 +183,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
}
@@ -311,6 +318,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/get_issue53955.txt b/src/cmd/go/testdata/script/get_issue53955.txt
new file mode 100644
index 0000000..685c6fa
--- /dev/null
+++ b/src/cmd/go/testdata/script/get_issue53955.txt
@@ -0,0 +1,79 @@
+# Regression test for https://go.dev/issue/53955.
+# New remote tags were erroneously added to the local clone of a repo
+# only *after* extracting version information for a locally-cached commit,
+# causing the version information to have incomplete Tags and Version fields.
+
+[short] skip 'constructs a local git repo'
+[!git] skip
+[!net:github.com] skip 'does not actually use github.com because of insteadOf, but silence network check just in case'
+
+# Redirect git to a test-specific .gitconfig.
+# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer.
+# For older git versions we also set $HOME.
+env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig
+env HOME=$WORK${/}home${/}gopher
+exec git config --global --show-origin user.name
+stdout 'Go Gopher'
+
+# Inject a local repo in place of a remote one, so that we can
+# add commits to the repo partway through the test.
+env GIT_ALLOW_PROTOCOL=file
+env GOPRIVATE=github.com/golang/issue53955
+
+[!GOOS:windows] exec git config --global 'url.file://'$WORK'/repo.insteadOf' 'https://github.com/golang/issue53955'
+[GOOS:windows] exec git config --global 'url.file:///'$WORK'/repo.insteadOf' 'https://github.com/golang/issue53955'
+
+cd $WORK/repo
+
+env GIT_AUTHOR_NAME='Go Gopher'
+env GIT_AUTHOR_EMAIL='gopher@golang.org'
+env GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME
+env GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL
+
+exec git init
+
+env GIT_COMMITTER_DATE=2022-07-19T11:07:00-04:00
+env GIT_AUTHOR_DATE=2022-07-19T11:07:00-04:00
+exec git add go.mod issue53955.go
+exec git commit -m 'initial commit'
+exec git branch -m main
+exec git tag v1.0.9
+
+env GIT_COMMITTER_DATE=2022-07-19T11:07:01-04:00
+env GIT_AUTHOR_DATE=2022-07-19T11:07:01-04:00
+exec git add extra.go
+exec git commit -m 'next commit'
+exec git show-ref --tags --heads
+cmp stdout $WORK/.git-refs-1
+
+cd $WORK/m
+go get -x github.com/golang/issue53955@2cb3d49f
+stderr '^go: added github.com/golang/issue53955 v1.0.10-0.20220719150701-2cb3d49f8874$'
+
+cd $WORK/repo
+exec git tag v1.0.10
+
+cd $WORK/m
+go get -x github.com/golang/issue53955@v1.0.10
+! stderr 'v1\.0\.10 is not a tag'
+stderr '^go: upgraded github.com/golang/issue53955 v.* => v1\.0\.10$'
+
+-- $WORK/repo/go.mod --
+module github.com/golang/issue53955
+
+go 1.18
+-- $WORK/repo/issue53955.go --
+package issue53955
+-- $WORK/repo/extra.go --
+package issue53955
+-- $WORK/.git-refs-1 --
+2cb3d49f8874b9362ed0ddd2a6512e4108bbf6b1 refs/heads/main
+050526ebf5883191e990529eb3cc9345abaf838c refs/tags/v1.0.9
+-- $WORK/m/go.mod --
+module m
+
+go 1.18
+-- $WORK/home/gopher/.gitconfig --
+[user]
+ name = Go Gopher
+ email = gopher@golang.org
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/go/testdata/script/mod_download_git_bareRepository.txt b/src/cmd/go/testdata/script/mod_download_git_bareRepository.txt
index 8050461..a61283c 100644
--- a/src/cmd/go/testdata/script/mod_download_git_bareRepository.txt
+++ b/src/cmd/go/testdata/script/mod_download_git_bareRepository.txt
@@ -1,8 +1,14 @@
[short] skip
[!git] skip
-[!GOOS:linux] skip # Uses XDG_CONFIG_HOME
-env GIT_CONFIG_GLOBAL=$WORK/.gitconfig
+# Redirect git to a test-specific .gitconfig.
+# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer.
+# For older git versions we also set $HOME.
+env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig
+env HOME=$WORK${/}home${/}gopher
+exec git config --global --show-origin user.name
+stdout 'Go Gopher'
+
env GOPRIVATE=vcs-test.golang.org
go mod download -x
@@ -14,6 +20,9 @@ go 1.18
require vcs-test.golang.org/git/gitrepo1.git v1.2.3
--- $WORK/.gitconfig --
+-- $WORK/home/gopher/.gitconfig --
+[user]
+ name = Go Gopher
+ email = gopher@golang.org
[safe]
-bareRepository = explicit
+ bareRepository = explicit
diff --git a/src/cmd/go/testdata/script/mod_download_git_decorate_full.txt b/src/cmd/go/testdata/script/mod_download_git_decorate_full.txt
index 080ccf0..9afd347 100644
--- a/src/cmd/go/testdata/script/mod_download_git_decorate_full.txt
+++ b/src/cmd/go/testdata/script/mod_download_git_decorate_full.txt
@@ -3,12 +3,15 @@ env GO111MODULE=on
[short] skip
[!git] skip
-env GOPROXY=direct
-env HOME=$WORK/home/gopher
-
+# Redirect git to a test-specific .gitconfig.
+# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer.
+# For older git versions we also set $HOME.
+env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig
+env HOME=$WORK${/}home${/}gopher
+exec git config --global --show-origin user.name
+stdout 'Go Gopher'
-go env GOPROXY
-stdout 'direct'
+env GOPROXY=direct
exec git config --get log.decorate
stdout 'full'
@@ -24,5 +27,8 @@ go list -m vcs-test.golang.org/git/gitrepo1.git@v1.2.3
stdout 'vcs-test.golang.org/git/gitrepo1.git v1.2.3'
-- $WORK/home/gopher/.gitconfig --
+[user]
+ name = Go Gopher
+ email = gopher@golang.org
[log]
decorate = full
diff --git a/src/cmd/go/testdata/script/mod_download_issue51114.txt b/src/cmd/go/testdata/script/mod_download_issue51114.txt
index 4d274d6..a28d467 100644
--- a/src/cmd/go/testdata/script/mod_download_issue51114.txt
+++ b/src/cmd/go/testdata/script/mod_download_issue51114.txt
@@ -1,8 +1,14 @@
[!net:github.com] skip
[!git] skip
-[!GOOS:linux] skip # Uses XDG_CONFIG_HOME
-env GIT_CONFIG_GLOBAL=$WORK/.gitconfig
+# Redirect git to a test-specific .gitconfig.
+# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer.
+# For older git versions we also set $HOME.
+env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig
+env HOME=$WORK${/}home${/}gopher
+exec git config --global --show-origin user.name
+stdout 'Go Gopher'
+
env GOPROXY=direct
! go mod download
@@ -15,6 +21,9 @@ go 1.18
require github.com/golang/notexist/subdir v0.1.0
--- $WORK/.gitconfig --
+-- $WORK/home/gopher/.gitconfig --
+[user]
+ name = Go Gopher
+ email = gopher@golang.org
[url "git@github.com:"]
insteadOf = https://github.com/
diff --git a/src/cmd/go/testdata/script/mod_download_private_vcs.txt b/src/cmd/go/testdata/script/mod_download_private_vcs.txt
index 2f72a42..5c8d93a 100644
--- a/src/cmd/go/testdata/script/mod_download_private_vcs.txt
+++ b/src/cmd/go/testdata/script/mod_download_private_vcs.txt
@@ -5,6 +5,14 @@ env GO111MODULE=on
[!git] skip
env GOPROXY=direct
+# Redirect git to a test-specific .gitconfig.
+# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer.
+# For older git versions we also set $HOME.
+env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig
+env HOME=$WORK${/}home${/}gopher
+exec git config --global --show-origin user.name
+stdout 'Go Gopher'
+
! go mod download github.com/golang/nonexist@latest
stderr 'Confirm the import path was entered correctly.'
stderr 'If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.'
@@ -27,7 +35,7 @@ stderr '^If this is a private repository, see https://golang.org/doc/faq#git_htt
# Test that Git clone errors will be shown to the user instead of a generic
# "unknown revision" error. To do this we want to force git ls-remote to return
# an error we don't already have special handling for. See golang/go#42751.
-env HOME=$WORK${/}home${/}gopher
+exec git config --global url.git@github.com.insteadOf https://github.com/
env GIT_SSH_COMMAND=false
! go install github.com/golang/nonexist@master
stderr 'fatal: Could not read from remote repository.'
@@ -35,5 +43,6 @@ stderr 'fatal: Could not read from remote repository.'
! stdout .
-- $WORK/home/gopher/.gitconfig --
-[url "git@github.com:"]
- insteadOf = https://github.com/
+[user]
+ name = Go Gopher
+ email = gopher@golang.org
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 a44b094..9e4d41f 100644
--- a/src/net/netip/netip.go
+++ b/src/net/netip/netip.go
@@ -507,6 +507,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() {
@@ -522,6 +526,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() {
@@ -537,6 +545,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() {
@@ -555,7 +567,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
@@ -563,6 +575,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() {
@@ -591,6 +607,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})) {
@@ -608,6 +628,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 0f80bb0..5c7ad14 100644
--- a/src/net/netip/netip_test.go
+++ b/src/net/netip/netip_test.go
@@ -589,10 +589,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 {
@@ -617,6 +620,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,
@@ -638,6 +646,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,
@@ -655,6 +669,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,
@@ -680,6 +699,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,
@@ -716,6 +740,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 533a484..f4709a4 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/metrics_test.go b/src/runtime/metrics_test.go
index cfb09a3..55d7dc4 100644
--- a/src/runtime/metrics_test.go
+++ b/src/runtime/metrics_test.go
@@ -761,3 +761,38 @@ func TestCPUMetricsSleep(t *testing.T) {
}
t.Errorf(`time.Sleep did not contribute enough to "idle" class: minimum idle time = %.5fs`, minIdleCPUSeconds)
}
+
+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 68f1aae..ce0e8df 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -771,6 +771,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
@@ -791,16 +804,6 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
} else {
mheap_.freeSpan(s)
}
-
- // 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/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)
+}