api/go1.23.txt | 2 +-
doc/next/1-intro.md | 14 --------------
doc/next/2-language.md | 18 ------------------
doc/next/3-tools.md | 84 -----------------------------------------------------
doc/next/4-runtime.md | 7 -------
doc/next/5-toolchain.md | 38 --------------------------------------
doc/next/6-stdlib/0-heading.md | 2 --
doc/next/6-stdlib/1-time.md | 32 --------------------------------
doc/next/6-stdlib/2-unique.md | 13 -------------
doc/next/6-stdlib/3-iter.md | 29 -----------------------------
doc/next/6-stdlib/4-structs.md | 11 -----------
doc/next/6-stdlib/99-minor/0-heading.md | 3 ---
doc/next/6-stdlib/99-minor/README | 1 -
doc/next/6-stdlib/99-minor/archive/tar/50102.md | 4 ----
doc/next/6-stdlib/99-minor/crypto/tls/63369.md | 3 ---
doc/next/6-stdlib/99-minor/crypto/tls/63691.md | 3 ---
doc/next/6-stdlib/99-minor/crypto/tls/66214.md | 3 ---
doc/next/6-stdlib/99-minor/crypto/tls/67061.md | 3 ---
doc/next/6-stdlib/99-minor/crypto/tls/67065.md | 3 ---
doc/next/6-stdlib/99-minor/crypto/x509/45990.md | 3 ---
doc/next/6-stdlib/99-minor/crypto/x509/62048.md | 4 ----
doc/next/6-stdlib/99-minor/crypto/x509/66249.md | 3 ---
doc/next/6-stdlib/99-minor/database/sql/64707.md | 3 ---
doc/next/6-stdlib/99-minor/debug/elf/66054.md | 3 ---
doc/next/6-stdlib/99-minor/debug/elf/66836.md | 2 --
doc/next/6-stdlib/99-minor/encoding/binary/60023.md | 3 ---
doc/next/6-stdlib/99-minor/go/ast/66339.md | 2 --
doc/next/6-stdlib/99-minor/go/types/46477.md | 1 -
doc/next/6-stdlib/99-minor/go/types/65772.md | 3 ---
doc/next/6-stdlib/99-minor/go/types/66559.md | 3 ---
doc/next/6-stdlib/99-minor/go/types/67143.md | 2 --
doc/next/6-stdlib/99-minor/go/types/cl-577715.md | 4 ----
doc/next/6-stdlib/99-minor/iter/61897.md | 1 -
doc/next/6-stdlib/99-minor/maps/61900.md | 1 -
doc/next/6-stdlib/99-minor/math/rand/v2/61716.md | 2 --
doc/next/6-stdlib/99-minor/math/rand/v2/67059.md | 1 -
doc/next/6-stdlib/99-minor/net/62254.md | 3 ---
doc/next/6-stdlib/99-minor/net/63116.md | 3 ---
doc/next/6-stdlib/99-minor/net/67925.md | 3 ---
doc/next/6-stdlib/99-minor/net/http/46443.md | 3 ---
doc/next/6-stdlib/99-minor/net/http/61472.md | 1 -
doc/next/6-stdlib/99-minor/net/http/62490.md | 1 -
doc/next/6-stdlib/99-minor/net/http/64910.md | 2 --
doc/next/6-stdlib/99-minor/net/http/66008.md | 7 -------
doc/next/6-stdlib/99-minor/net/http/66343.md | 16 ----------------
doc/next/6-stdlib/99-minor/net/http/66405.md | 3 ---
doc/next/6-stdlib/99-minor/net/http/httptest/59473.md | 2 --
doc/next/6-stdlib/99-minor/os/33357.md | 3 ---
doc/next/6-stdlib/99-minor/os/61893.md | 7 -------
doc/next/6-stdlib/99-minor/os/62484.md | 1 -
doc/next/6-stdlib/99-minor/os/63703.md | 5 -----
doc/next/6-stdlib/99-minor/path/filepath/57151.md | 2 --
doc/next/6-stdlib/99-minor/path/filepath/63703.md | 11 -----------
doc/next/6-stdlib/99-minor/reflect/60427.md | 6 ------
doc/next/6-stdlib/99-minor/reflect/61308.md | 3 ---
doc/next/6-stdlib/99-minor/reflect/66056.md | 4 ----
doc/next/6-stdlib/99-minor/runtime/debug/42888.md | 5 -----
doc/next/6-stdlib/99-minor/runtime/debug/67182.md | 1 -
doc/next/6-stdlib/99-minor/runtime/pprof/43669.md | 2 --
doc/next/6-stdlib/99-minor/runtime/trace/65319.md | 4 ----
doc/next/6-stdlib/99-minor/slices/53987.md | 1 -
doc/next/6-stdlib/99-minor/slices/61899.md | 1 -
doc/next/6-stdlib/99-minor/slices/65238.md | 2 --
doc/next/6-stdlib/99-minor/structs/66408.md | 1 -
doc/next/6-stdlib/99-minor/sync/61696.md | 2 --
doc/next/6-stdlib/99-minor/sync/atomic/61395.md | 3 ---
doc/next/6-stdlib/99-minor/syscall/62254.md | 1 -
doc/next/6-stdlib/99-minor/syscall/65817.md | 1 -
doc/next/6-stdlib/99-minor/testing/fstest/63675.md | 3 ---
doc/next/6-stdlib/99-minor/text/template/57646.md | 1 -
doc/next/6-stdlib/99-minor/time/67470.md | 2 --
doc/next/6-stdlib/99-minor/unicode/utf16/44940.md | 3 ---
doc/next/6-stdlib/99-minor/unique/62483.md | 1 -
doc/next/7-ports.md | 38 --------------------------------------
doc/next/9-todo.md | 51 ---------------------------------------------------
src/cmd/addr2line/main.go | 8 ++++----
src/cmd/asm/internal/asm/testdata/arm64.s | 6 +++++-
src/cmd/asm/main.go | 8 ++++----
src/cmd/buildid/buildid.go | 8 ++++----
src/cmd/cgo/gcc.go | 4 ++--
src/cmd/cgo/internal/testerrors/errors_test.go | 1 +
src/cmd/cgo/internal/testerrors/testdata/issue67707.go | 15 +++++++++++++++
src/cmd/cgo/internal/testplugin/plugin_test.go | 8 ++++++++
src/cmd/cgo/internal/testplugin/testdata/issue67976/plugin.go | 16 ++++++++++++++++
src/cmd/cgo/main.go | 23 +++++++++++++++++++----
src/cmd/compile/README.md | 3 ++-
src/cmd/compile/internal/base/flag.go | 4 ++--
src/cmd/compile/internal/base/print.go | 4 ++--
src/cmd/compile/internal/dwarfgen/dwarf.go | 6 ++++++
src/cmd/compile/internal/gc/main.go | 6 +++---
src/cmd/compile/internal/noder/unified.go | 6 +++++-
src/cmd/compile/internal/noder/writer.go | 26 +++++++++++++++++++-------
src/cmd/compile/internal/rangefunc/rewrite.go | 2 +-
src/cmd/compile/internal/ssa/debug.go | 30 ++++++++++++++++++++++++++----
src/cmd/compile/internal/ssa/rewrite.go | 17 ++++++++++++++---
src/cmd/compile/internal/staticinit/sched.go | 14 ++++++++++++++
src/cmd/compile/internal/typecheck/typecheck.go | 4 ++--
src/cmd/compile/internal/types2/issues_test.go | 29 +++++++++++++++++++++++++++++
src/cmd/compile/internal/types2/stmt.go | 9 +++++----
src/cmd/compile/internal/types2/typeparam.go | 4 ++--
src/cmd/covdata/covdata.go | 8 ++++----
src/cmd/cover/cover.go | 8 ++++----
src/cmd/dist/buildtool.go | 1 +
src/cmd/dist/test.go | 13 -------------
src/cmd/distpack/pack.go | 8 ++++----
src/cmd/doc/main.go | 8 ++++----
src/cmd/fix/main.go | 8 ++++----
src/cmd/go.mod | 6 +++---
src/cmd/go.sum | 12 ++++++------
src/cmd/go/alldocs.go | 12 +++++++++---
src/cmd/go/internal/clean/clean.go | 2 +-
src/cmd/go/internal/help/help.go | 4 ++--
src/cmd/go/internal/help/helpdoc.go | 7 +++++++
src/cmd/go/internal/modfetch/cache.go | 4 ++--
src/cmd/go/internal/telemetrystats/telemetrystats.go | 28 ++++++++++++++--------------
src/cmd/go/internal/telemetrystats/version_other.go | 4 ++--
src/cmd/go/internal/telemetrystats/version_unix.go | 10 +++++-----
src/cmd/go/internal/telemetrystats/version_windows.go | 8 ++++----
src/cmd/go/internal/tool/tool.go | 10 +++++-----
src/cmd/go/internal/toolchain/select.go | 6 +++---
src/cmd/go/internal/toolchain/switch.go | 4 ++--
src/cmd/go/internal/work/buildid.go | 8 ++++----
src/cmd/go/internal/workcmd/use.go | 3 +--
src/cmd/go/main.go | 37 +++++++++++++++++++------------------
src/cmd/gofmt/gofmt.go | 8 ++++----
src/cmd/internal/obj/arm64/asm_arm64_test.go | 297 +----------------------------------------------------
src/cmd/internal/obj/arm64/asm_test.go | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/cmd/internal/obj/arm64/obj7.go | 12 +++++++-----
src/cmd/internal/telemetry/counter/counter.go | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/cmd/internal/telemetry/counter/counter_bootstrap.go | 20 ++++++++++++++++++++
src/cmd/internal/telemetry/telemetry.go | 52 +++-------------------------------------------------
src/cmd/internal/telemetry/telemetry_bootstrap.go | 22 +++++-----------------
src/cmd/link/doc.go | 4 ++++
src/cmd/link/internal/amd64/asm.go | 7 +++++++
src/cmd/link/internal/ld/ld_test.go | 29 ++++++++++++++++++++++++++++-
src/cmd/link/internal/ld/lib.go | 29 ++++++++++++++++++-----------
src/cmd/link/internal/ld/main.go | 8 ++++----
src/cmd/link/internal/ld/pe.go | 13 +++++++++++++
src/cmd/nm/nm.go | 8 ++++----
src/cmd/objdump/main.go | 8 ++++----
src/cmd/pack/pack.go | 8 ++++----
src/cmd/pprof/pprof.go | 8 ++++----
src/cmd/preprofile/main.go | 8 ++++----
src/cmd/test2json/main.go | 8 ++++----
src/cmd/trace/gstate.go | 2 +-
src/cmd/trace/main.go | 8 ++++----
src/cmd/vendor/golang.org/x/mod/module/module.go | 2 --
src/cmd/vendor/golang.org/x/mod/sumdb/client.go | 8 ++++++++
src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go | 12 ++++++++++--
src/cmd/vendor/golang.org/x/sys/unix/mremap.go | 5 +++++
src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.go | 12 ++++++++++++
src/cmd/vendor/golang.org/x/sys/unix/syscall_unix.go | 9 +++++++++
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go | 33 +++++++++++++++++++++++++++++++++
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s | 10 ++++++++++
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go | 33 +++++++++++++++++++++++++++++++++
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s | 10 ++++++++++
src/cmd/vendor/golang.org/x/sys/windows/security_windows.go | 24 +++++++++++++++++++++++-
src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go | 9 +++++++++
src/cmd/vendor/golang.org/x/telemetry/counter/counter.go | 16 ++++++++++++++--
src/cmd/vendor/golang.org/x/telemetry/counter/doc.go | 7 +++++++
src/cmd/vendor/golang.org/x/telemetry/internal/counter/counter.go | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
src/cmd/vendor/golang.org/x/telemetry/internal/counter/file.go | 199 ++++++++++++++++++++++++++++++++++++++++-------------
src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap.go | 7 +++----
src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_other.go | 8 ++++----
src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_unix.go | 14 +++++++-------
src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_windows.go | 22 +++++++++++-----------
src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/proginfo.go | 11 +++++++----
src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/types.go | 4 ++--
src/cmd/vendor/golang.org/x/telemetry/internal/upload/findwork.go | 2 +-
src/cmd/vendor/golang.org/x/telemetry/internal/upload/reports.go | 7 +++++--
src/cmd/vendor/golang.org/x/telemetry/internal/upload/upload.go | 14 ++++++++------
src/cmd/vendor/modules.txt | 6 +++---
src/cmd/vet/main.go | 8 ++++----
src/context/context.go | 2 ++
src/context/x_test.go | 4 ++++
src/crypto/hmac/hmac_test.go | 41 ++++++++---------------------------------
src/crypto/internal/cryptotest/hash.go | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/crypto/md5/md5_test.go | 5 +++++
src/crypto/sha1/sha1_test.go | 5 +++++
src/crypto/sha256/sha256_test.go | 10 ++++++++++
src/crypto/sha512/sha512_test.go | 16 ++++++++++++++++
src/crypto/tls/bogo_shim_test.go | 27 ++++++++++++++++++++++++---
src/crypto/tls/handshake_client.go | 4 +++-
src/crypto/tls/handshake_client_test.go | 232 ++++++++++++++++++++++-------------------------------
src/crypto/tls/handshake_client_tls13.go | 2 +-
src/crypto/tls/handshake_server_test.go | 95 ++++++++++++-----------------------------------------
src/crypto/tls/handshake_server_tls13.go | 2 +-
src/crypto/tls/handshake_test.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/crypto/tls/quic.go | 16 ++++++++--------
src/crypto/tls/quic_test.go | 156 +++++++++++++++++++++++++++++------------------------
src/database/sql/driver/driver.go | 2 +-
src/encoding/json/decode.go | 3 +--
src/encoding/json/encode.go | 2 +-
src/go.mod | 2 +-
src/go.sum | 4 ++--
src/go/build/deps_test.go | 3 +++
src/go/types/issues_test.go | 29 +++++++++++++++++++++++++++++
src/go/types/stmt.go | 9 +++++----
src/go/types/typeparam.go | 4 ++--
src/internal/coverage/defs.go | 2 +-
src/internal/godebugs/table.go | 2 +-
src/io/pipe_test.go | 18 ++++++++++++++++++
src/iter/iter.go | 26 ++++++++++++++++----------
src/log/slog/internal/buffer/buffer.go | 5 ++++-
src/math/floor_asm.go | 2 +-
src/math/floor_noasm.go | 2 +-
src/math/floor_riscv64.s | 41 -----------------------------------------
src/net/http/filetransport.go | 2 +-
src/net/http/fs.go | 2 ++
src/net/http/request.go | 2 ++
src/net/http/routing_tree_test.go | 5 ++---
src/net/http/serve_test.go | 16 ++++++++++++++++
src/net/http/server.go | 16 ++++------------
src/net/netip/export_test.go | 4 ++++
src/net/netip/netip.go | 10 +++++-----
src/net/netip/netip_test.go | 23 +++++++++++++++++++----
src/os/error.go | 8 ++++----
src/os/exec/exec.go | 65 +++++++++++++++++++++++++++++-------------------------
src/os/exec/exec_test.go | 22 +++++++++++++++++++++-
src/os/os_test.go | 297 ++++++++++++++++++++++-------------------------------
src/os/os_unix_test.go | 34 +++++++---------------------------
src/runtime/arena.go | 2 +-
src/runtime/metrics/doc.go | 4 ++++
src/runtime/mprof.go | 115 +++++++++++++++++++++++++++++++++++++++++++++++------
src/runtime/pprof/pprof.go | 26 +++++++++++++++++++++++---
src/runtime/pprof/pprof_test.go | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/runtime/proc_test.go | 2 +-
src/slices/iter.go | 9 ++++-----
src/strings/builder.go | 14 +++++++++++++-
src/strings/compare.go | 2 +-
src/strings/replace.go | 2 +-
src/strings/strings.go | 8 ++++----
src/sync/atomic/type.go | 4 ++--
src/sync/export_test.go | 2 +-
src/sync/rwmutex.go | 2 +-
src/testing/testing.go | 2 +-
src/text/template/parse/node.go | 6 +++++-
src/text/template/parse/parse_test.go | 3 +++
src/time/format.go | 6 ++++--
src/time/format_test.go | 17 +++++++++++++++++
src/time/sleep.go | 1 +
src/unsafe/unsafe.go | 4 ++--
src/vendor/modules.txt | 2 +-
test/fixedbugs/issue54542.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++
test/fixedbugs/issue67190.go | 24 ++++++++++++++++++++++++
test/fixedbugs/issue68227.go | 43 +++++++++++++++++++++++++++++++++++++++++++
test/fixedbugs/issue68264.go | 15 +++++++++++++++
test/fixedbugs/issue68322.go | 17 +++++++++++++++++
test/fixedbugs/issue68415.go | 15 +++++++++++++++
diff --git a/api/go1.23.txt b/api/go1.23.txt
index dc92d3fe56b137b8547fa7047b33715948cb8ce7..9363bd41f3ce4681020fa83c0f54a19ec792377b 100644
--- a/api/go1.23.txt
+++ b/api/go1.23.txt
@@ -18,7 +18,7 @@ pkg crypto/tls, type Config struct, EncryptedClientHelloRejectionVerify func(ConnectionState) error #63369
pkg crypto/tls, type ConnectionState struct, ECHAccepted bool #63369
pkg crypto/tls, type ECHRejectionError struct #63369
pkg crypto/tls, type ECHRejectionError struct, RetryConfigList []uint8 #63369
-pkg crypto/tls, type QUICConfig struct, EnableStoreSessionEvent bool #63691
+pkg crypto/tls, type QUICConfig struct, EnableSessionEvents bool #63691
pkg crypto/tls, type QUICEvent struct, SessionState *SessionState #63691
pkg crypto/tls, type QUICSessionTicketOptions struct, Extra [][]uint8 #63691
pkg crypto/x509, func ParseOID(string) (OID, error) #66249
diff --git a/doc/next/1-intro.md b/doc/next/1-intro.md
deleted file mode 100644
index 585c6c8e52c32e3fb032972574bf2a596e3239d3..0000000000000000000000000000000000000000
--- a/doc/next/1-intro.md
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-## DRAFT RELEASE NOTES — Introduction to Go 1.23 {#introduction}
-
-**Go 1.23 is not yet released. These are work-in-progress release notes.
-Go 1.23 is expected to be released in August 2024.**
diff --git a/doc/next/2-language.md b/doc/next/2-language.md
deleted file mode 100644
index 83e3a51437e547eb90698b88876a5e52151069d7..0000000000000000000000000000000000000000
--- a/doc/next/2-language.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## Changes to the language {#language}
-
-
-Go 1.23 makes the (Go 1.22) ["range-over-func" experiment](/wiki/RangefuncExperiment) a part of the language.
-The "range" clause in a "for-range" loop now accepts iterator functions of the following types
-
- func(func() bool)
- func(func(K) bool)
- func(func(K, V) bool)
-
-as range expressions.
-Calls of the iterator argument function produce the iteration values for the "for-range" loop.
-For details see the [iter] package documentation and the [language spec](/ref/spec#For_range).
-For motivation see the 2022 ["range-over-func" discussion](/issue/56413).
-
-
-Go 1.23 includes preview support for [generic type aliases](/issue/46477).
-Building the toolchain with `GOEXPERIMENT=aliastypeparams` enables this feature.
diff --git a/doc/next/3-tools.md b/doc/next/3-tools.md
deleted file mode 100644
index 7ae651e0b4e61f119f28d1f1462a72684745f169..0000000000000000000000000000000000000000
--- a/doc/next/3-tools.md
+++ /dev/null
@@ -1,84 +0,0 @@
-## Tools {#tools}
-
-### Telemetry
-
-
-Starting in Go 1.23, the Go toolchain can collect usage and breakage
-statistics that help the Go team understand how the Go toolchain is
-used and how well it is working. We refer to these statistics as
-[Go telemetry](/doc/telemetry).
-
-Go telemetry is an _opt-in system_, controlled by the
-[`go` `telemetry` command](/cmd/go/#hdr-Manage_telemetry_data_and_settings).
-By default, the toolchain programs
-collect statistics in counter files that can be inspected locally
-but are otherwise unused (`go` `telemetry` `local`).
-
-To help us keep Go working well and understand Go usage,
-please consider opting in to Go telemetry by running
-`go` `telemetry` `on`.
-In that mode,
-anonymous counter reports are uploaded to
-[telemetry.go.dev](https://telemetry.go.dev) weekly,
-where they are aggregated into graphs and also made
-available for download by any Go contributors or users
-wanting to analyze the data.
-See “[Go Telemetry](/doc/telemetry)” for more details
-about the Go Telemetry system.
-
-### Go command {#go-command}
-
-Setting the `GOROOT_FINAL` environment variable no longer has an effect
-([#62047](/issue/62047)).
-Distributions that install the `go` command to a location other than
-`$GOROOT/bin/go` should install a symlink instead of relocating
-or copying the `go` binary.
-
-
-The new `go` `env` `-changed` flag causes the command to print only
-those settings whose effective value differs from the default value
-that would be obtained in an empty environment with no prior uses of the `-w` flag.
-
-
-The new `go` `mod` `tidy` `-diff` flag causes the command not to modify
-the files but instead print the necessary changes as a unified diff.
-It exits with a non-zero code if updates are needed.
-
-
-The `go` `list` `-m` `-json` command now includes new `Sum` and `GoModSum` fields.
-This is similar to the existing behavior of the `go` `mod` `download` `-json` command.
-
-
-The new `godebug` directive in `go.mod` and `go.work` declares a
-[GODEBUG setting](/doc/godebug) to apply for the work module or workspace in use.
-
-### Vet {#vet}
-
-
-The `go vet` subcommand now includes the
-[stdversion](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdversion)
-analyzer, which flags references to symbols that are too new for the version
-of Go in effect in the referring file. (The effective version is determined
-by the `go` directive in the file's enclosing `go.mod` file, and
-by any [`//go:build` constraints](/cmd/go#hdr-Build_constraints)
-in the file.)
-
-For example, it will report a diagnostic for a reference to the
-`reflect.TypeFor` function (introduced in go1.22) from a file in a
-module whose go.mod file specifies `go 1.21`.
-
-### Cgo {#cgo}
-
-
-[cmd/cgo] supports the new `-ldflags` flag for passing flags to the C linker.
-The `go` command uses it automatically, avoiding "argument list too long"
-errors with a very large `CGO_LDFLAGS`.
-
-### Trace {#trace}
-
-
-The `trace` tool now better tolerates partially broken traces by attempting to
-recover what trace data it can. This functionality is particularly helpful when
-viewing a trace that was collected during a program crash, since the trace data
-leading up to the crash will now [be recoverable](/issue/65319) under most
-circumstances.
diff --git a/doc/next/4-runtime.md b/doc/next/4-runtime.md
deleted file mode 100644
index 7553154a162b0792c3dc91b917bd51ade14e1948..0000000000000000000000000000000000000000
--- a/doc/next/4-runtime.md
+++ /dev/null
@@ -1,7 +0,0 @@
-## Runtime {#runtime}
-
-The traceback printed by the runtime after an unhandled panic or other
-fatal error now indents the second and subsequent lines of the error
-message (for example, the argument to panic) by a single tab, so that
-it can be unambiguously distinguished from the stack trace of the
-first goroutine. See [#64590](/issue/64590) for discussion.
diff --git a/doc/next/5-toolchain.md b/doc/next/5-toolchain.md
deleted file mode 100644
index 51a1dbfbdf3f8f340208181309dc4ec3bec00067..0000000000000000000000000000000000000000
--- a/doc/next/5-toolchain.md
+++ /dev/null
@@ -1,38 +0,0 @@
-## Compiler {#compiler}
-
-The build time overhead to building with [Profile Guided Optimization](/doc/pgo) has been reduced significantly.
-Previously, large builds could see 100%+ build time increase from enabling PGO.
-In Go 1.23, overhead should be in the single digit percentages.
-
-
-The compiler in Go 1.23 can now overlap the stack frame slots of local variables
-accessed in disjoint regions of a function, which reduces stack usage
-for Go applications.
-
-
-For 386 and amd64, the compiler will use information from PGO to align certain
-hot blocks in loops. This improves performance an additional 1-1.5% at
-a cost of an additional 0.1% text and binary size. This is currently only implemented
-on 386 and amd64 because it has not shown an improvement on other platforms.
-Hot block alignment can be disabled with `-gcflags=[=]-d=alignhot=0`
-
-## Assembler {#assembler}
-
-## Linker {#linker}
-
-
-The linker now disallows using a `//go:linkname` directive to refer to
-internal symbols in the standard library (including the runtime) that
-are not marked with `//go:linkname` on their definitions.
-Similarly, the linker disallows references to such symbols from assembly
-code.
-For backward compatibility, existing usages of `//go:linkname` found in
-a large open-source code corpus remain supported.
-Any new references to standard library internal symbols will be disallowed.
-
-A linker command line flag `-checklinkname=0` can be used to disable
-this check, for debugging and experimenting purposes.
-
-
-When building a dynamically linked ELF binary (including PIE binary), the
-new `-bindnow` flag enables immediate function binding.
diff --git a/doc/next/6-stdlib/0-heading.md b/doc/next/6-stdlib/0-heading.md
deleted file mode 100644
index 02351ce1c091ad9c87b3eafe30fd8b17938ac26a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/0-heading.md
+++ /dev/null
@@ -1,2 +0,0 @@
-## Core library {#library}
-
diff --git a/doc/next/6-stdlib/1-time.md b/doc/next/6-stdlib/1-time.md
deleted file mode 100644
index 6046ac53501dc45ef7f8437494a8c86c0501f564..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/1-time.md
+++ /dev/null
@@ -1,32 +0,0 @@
-### Timer changes
-
-Go 1.23 makes two significant changes to the implementation of
-[time.Timer] and [time.Ticker].
-
-
-First, `Timer`s and `Ticker`s that are no longer referred to by the program
-become eligible for garbage collection immediately, even if their
-`Stop` methods have not been called.
-Earlier versions of Go did not collect unstopped `Timer`s until after
-they had fired and never collected unstopped `Ticker`s.
-
-
-Second, the timer channel associated with a `Timer` or `Ticker` is
-now unbuffered, with capacity 0.
-The main effect of this change is that Go now guarantees
-that for any call to a `Reset` or `Stop` method, no stale values
-prepared before that call will be sent or received after the call.
-Earlier versions of Go used channels with a one-element buffer,
-making it difficult to use `Reset` and `Stop` correctly.
-A visible effect of this change is that `len` and `cap` of timer channels
-now returns 0 instead of 1, which may affect programs that
-poll the length to decide whether a receive on the timer channel
-will succeed.
-Such code should use a non-blocking receive instead.
-
-These new behaviors are only enabled when the main Go program
-is in a module with a `go.mod` `go` line using Go 1.23.0 or later.
-When Go 1.23 builds older programs, the old behaviors remain in effect.
-The new [GODEBUG setting](/doc/godebug) [`asynctimerchan=1`](/pkg/time/#NewTimer)
-can be used to revert back to asynchronous channel behaviors
-even when a program names Go 1.23.0 or later in its `go.mod` file.
diff --git a/doc/next/6-stdlib/2-unique.md b/doc/next/6-stdlib/2-unique.md
deleted file mode 100644
index 42737a52fa3618bc3da65ab82daf757998587c89..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/2-unique.md
+++ /dev/null
@@ -1,13 +0,0 @@
-### New unique package
-
-The new [unique] package provides facilities for
-canonicalizing values (like "interning" or "hash-consing").
-
-Any value of comparable type may be canonicalized with the new
-`Make[T]` function, which produces a reference to a canonical copy of
-the value in the form of a `Handle[T]`.
-Two `Handle[T]` are equal if and only if the values used to produce the
-handles are equal, allowing programs to deduplicate values and reduce
-their memory footprint.
-Comparing two `Handle[T]` values is efficient, reducing down to a simple
-pointer comparison.
diff --git a/doc/next/6-stdlib/3-iter.md b/doc/next/6-stdlib/3-iter.md
deleted file mode 100644
index bbb3bbbd8f23e8b993d8e841703d0799ea464325..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/3-iter.md
+++ /dev/null
@@ -1,29 +0,0 @@
-### Iterators
-
-The new [iter] package provides the basic definitions for working with
-user-defined iterators.
-
-The [slices] package adds several functions that work with iterators:
-- [All](/pkg/slices#All) returns an iterator over slice indexes and values.
-- [Values](/pkg/slices#Values) returns an iterator over slice elements.
-- [Backward](/pkg/slices#Backward) returns an iterator that loops over
- a slice backward.
-- [Collect](/pkg/slices#Collect) collects values from an iterator into
- a new slice.
-- [AppendSeq](/pkg/slices#AppendSeq) appends values from an iterator to
- an existing slice.
-- [Sorted](/pkg/slices#Sorted) collects values from an iterator into a
- new slice, and then sorts the slice.
-- [SortedFunc](/pkg/slices#SortedFunc) is like `Sorted` but with a
- comparison function.
-- [SortedStableFunc](/pkg/slices#SortedStableFunc) is like `SortFunc`
- but uses a stable sort algorithm.
-- [Chunk](/pkg/slices#Chunk) returns an iterator over consecutive
- sub-slices of up to n elements of a slice.
-
-The [maps] package adds several functions that work with iterators:
-- [All](/pkg/maps#All) returns an iterator over key-value pairs from a map.
-- [Keys](/pkg/maps#Keys) returns an iterator over keys in a map.
-- [Values](/pkg/maps#Values) returns an iterator over values in a map.
-- [Insert](/pkg/maps#Insert) adds the key-value pairs from an iterator to an existing map.
-- [Collect](/pkg/maps#Collect) collects key-value pairs from an iterator into a new map and returns it.
diff --git a/doc/next/6-stdlib/4-structs.md b/doc/next/6-stdlib/4-structs.md
deleted file mode 100644
index adf42f1b375cf77c90aeeb6a9af5025e4fffd09d..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/4-structs.md
+++ /dev/null
@@ -1,11 +0,0 @@
-### New structs package
-
-The new [structs] package provides
-types for struct fields that modify properties of
-the containing struct type such as memory layout.
-
-In this release, the only such type is
-[`HostLayout`](/pkg/structs#HostLayout)
-which indicates that a structure with a field of that
-type has a layout that conforms to host platform
-expectations.
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/0-heading.md b/doc/next/6-stdlib/99-minor/0-heading.md
deleted file mode 100644
index a98105e8ccba7f64a0fd77d1b85cf46545ba2d2b..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/0-heading.md
+++ /dev/null
@@ -1,3 +0,0 @@
-### Minor changes to the library {#minor_library_changes}
-
-
diff --git a/doc/next/6-stdlib/99-minor/README b/doc/next/6-stdlib/99-minor/README
deleted file mode 100644
index fac778de050642927b0f83650ee34b8db1fb97f5..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/README
+++ /dev/null
@@ -1 +0,0 @@
-API changes and other small changes to the standard library go here.
diff --git a/doc/next/6-stdlib/99-minor/archive/tar/50102.md b/doc/next/6-stdlib/99-minor/archive/tar/50102.md
deleted file mode 100644
index ed8675f6933ffc4ca57ea9d06f0bc92c18109b05..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/archive/tar/50102.md
+++ /dev/null
@@ -1,4 +0,0 @@
-If the argument to [FileInfoHeader] implements the new [FileInfoNames]
-interface, then the interface methods will be used to set the Uname/Gname
-of the file header. This allows applications to override the system-dependent
-Uname/Gname lookup.
diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/63369.md b/doc/next/6-stdlib/99-minor/crypto/tls/63369.md
deleted file mode 100644
index 6ec5b5bdf62d3e48c10335e8833f739dd93e234f..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/crypto/tls/63369.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The TLS client now supports the Encrypted Client Hello [draft specification](https://www.ietf.org/archive/id/draft-ietf-tls-esni-18.html).
-This feature can be enabled by setting the [Config.EncryptedClientHelloConfigList]
-field to an encoded ECHConfigList for the host that is being connected to.
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/63691.md b/doc/next/6-stdlib/99-minor/crypto/tls/63691.md
deleted file mode 100644
index 67ed04cf00d84f79b4231421e8cd33fc5fabb5a8..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/crypto/tls/63691.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The [QUICConn] type used by QUIC implementations includes new events
-reporting on the state of session resumption, and provides a way for
-the QUIC layer to add data to session tickets and session cache entries.
diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/66214.md b/doc/next/6-stdlib/99-minor/crypto/tls/66214.md
deleted file mode 100644
index ebe1b490f57851d0d841d663adeae11a1d1e4bac..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/crypto/tls/66214.md
+++ /dev/null
@@ -1,3 +0,0 @@
-3DES cipher suites were removed from the default list used when
-[Config.CipherSuites] is nil. The default can be reverted by adding `tls3des=1` to
-the GODEBUG environment variable.
diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/67061.md b/doc/next/6-stdlib/99-minor/crypto/tls/67061.md
deleted file mode 100644
index fe3620ed6d25b5b608a8af55fd3da1643caaae35..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/crypto/tls/67061.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The experimental post-quantum key exchange mechanism X25519Kyber768Draft00
-is now enabled by default when [Config.CurvePreferences] is nil.
-The default can be reverted by adding `tlskyber=0` to the GODEBUG environment variable.
diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/67065.md b/doc/next/6-stdlib/99-minor/crypto/tls/67065.md
deleted file mode 100644
index 3fcc8d5309368394b43b0b020b0c50d7eefa2b4c..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/crypto/tls/67065.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Go 1.23 changed the behavior of [X509KeyPair] and [LoadX509KeyPair]
-to populate the [Certificate.Leaf] field of the returned [Certificate].
-The new `x509keypairleaf` [GODEBUG setting](/doc/godebug) is added for this behavior.
diff --git a/doc/next/6-stdlib/99-minor/crypto/x509/45990.md b/doc/next/6-stdlib/99-minor/crypto/x509/45990.md
deleted file mode 100644
index 2eda8476a9a6877475a4942422b93f610194acbe..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/crypto/x509/45990.md
+++ /dev/null
@@ -1,3 +0,0 @@
-[CreateCertificateRequest] now correct supports RSA-PSS signature algorithms.
-
-[CreateCertificateRequest] and [CreateRevocationList] now verify the generated signature using the signer’s public key. If the signature is invalid, an error is returned. This has been the behavior of [CreateCertificate] since Go 1.16.
diff --git a/doc/next/6-stdlib/99-minor/crypto/x509/62048.md b/doc/next/6-stdlib/99-minor/crypto/x509/62048.md
deleted file mode 100644
index aaa8c5e3506fb0c7e06e2ac5b9f791051e7a84d9..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/crypto/x509/62048.md
+++ /dev/null
@@ -1,4 +0,0 @@
-The [`x509sha1` GODEBUG setting](/pkg/crypto/x509#InsecureAlgorithmError) will
-be removed in the next Go major release (Go 1.24). This will mean that crypto/x509
-will no longer support verifying signatures on certificates that use SHA-1 based
-signature algorithms.
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/crypto/x509/66249.md b/doc/next/6-stdlib/99-minor/crypto/x509/66249.md
deleted file mode 100644
index d449e74d66364bdc3be12c94933bcf02fc1e01ae..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/crypto/x509/66249.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The new [ParseOID] function parses a dot-encoded ASN.1 Object Identifier string.
-The [OID] type now implements the [encoding.BinaryMarshaler],
-[encoding.BinaryUnmarshaler], [encoding.TextMarshaler], [encoding.TextUnmarshaler] interfaces.
diff --git a/doc/next/6-stdlib/99-minor/database/sql/64707.md b/doc/next/6-stdlib/99-minor/database/sql/64707.md
deleted file mode 100644
index 17d4516ba8a0b3febf2c0d44a9efa0772390c945..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/database/sql/64707.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Errors returned by [driver.Valuer] implementations are now wrapped for
-improved error handling during operations like [DB.Query], [DB.Exec],
-and [DB.QueryRow].
diff --git a/doc/next/6-stdlib/99-minor/debug/elf/66054.md b/doc/next/6-stdlib/99-minor/debug/elf/66054.md
deleted file mode 100644
index 0b3443f7d4034b108b473dea7c4244efe3a18c4a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/debug/elf/66054.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The `debug/elf` package now defines [PT_OPENBSD_NOBTCFI]. This [ProgType] is
-used to disable Branch Tracking Control Flow Integrity (BTCFI) enforcement
-on OpenBSD binaries.
diff --git a/doc/next/6-stdlib/99-minor/debug/elf/66836.md b/doc/next/6-stdlib/99-minor/debug/elf/66836.md
deleted file mode 100644
index 4aad5798dd46873b837d9303c4f07cbdb9336d33..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/debug/elf/66836.md
+++ /dev/null
@@ -1,2 +0,0 @@
-Now defines the symbol type constants [STT_RELC], [STT_SRELC], and
-[STT_GNU_IFUNC].
diff --git a/doc/next/6-stdlib/99-minor/encoding/binary/60023.md b/doc/next/6-stdlib/99-minor/encoding/binary/60023.md
deleted file mode 100644
index 015bfc380314a1fc9a3d0708fabd25b364e8ffb5..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/encoding/binary/60023.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The new [Encode] and [Decode] functions are byte slice equivalents
-to [Read] and [Write].
-[Append] allows marshaling multiple data into the same byte slice.
diff --git a/doc/next/6-stdlib/99-minor/go/ast/66339.md b/doc/next/6-stdlib/99-minor/go/ast/66339.md
deleted file mode 100644
index 0eec51ecd69390e3f3386da889d6f4ab6d653a9a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/go/ast/66339.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The new [Preorder] function returns a convenient iterator over all the
-nodes of a syntax tree.
diff --git a/doc/next/6-stdlib/99-minor/go/types/46477.md b/doc/next/6-stdlib/99-minor/go/types/46477.md
deleted file mode 100644
index 7f744dc6ae4eee8142be6b88190f8f01ce676b70..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/go/types/46477.md
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/go/types/65772.md b/doc/next/6-stdlib/99-minor/go/types/65772.md
deleted file mode 100644
index ec7f0b0e59bc0e270cb284069e9a2966f524a21d..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/go/types/65772.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The [Func] type, which represents a function or method symbol, now
-has a [Func.Signature] method that returns the function's type, which
-is always a `Signature`.
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/go/types/66559.md b/doc/next/6-stdlib/99-minor/go/types/66559.md
deleted file mode 100644
index e3884594fa204d29ac93d3eb6ffb6eb8e57cc035..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/go/types/66559.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The [Alias] type now has an [Rhs] method that returns the type on the
-right-hand side of its declaration: given `type A = B`, the `Rhs` of A
-is B. ([#66559](/issue/66559))
diff --git a/doc/next/6-stdlib/99-minor/go/types/67143.md b/doc/next/6-stdlib/99-minor/go/types/67143.md
deleted file mode 100644
index 405c679378e8d705f6d9f50df0996a43f86361f6..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/go/types/67143.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The methods [Alias.Origin], [Alias.SetTypeParams], [Alias.TypeParams],
-and [Alias.TypeArgs] have been added. They are needed for generic alias types.
diff --git a/doc/next/6-stdlib/99-minor/go/types/cl-577715.md b/doc/next/6-stdlib/99-minor/go/types/cl-577715.md
deleted file mode 100644
index 939d5ac46c657847f960ab06745ed1e73fd3d25a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/go/types/cl-577715.md
+++ /dev/null
@@ -1,4 +0,0 @@
-
-By default, go/types now produces [Alias] type nodes for type aliases.
-This behavior can be controlled by the `GODEBUG` `gotypesalias` flag.
-Its default has changed from 0 in Go 1.22 to 1 in Go 1.23.
diff --git a/doc/next/6-stdlib/99-minor/iter/61897.md b/doc/next/6-stdlib/99-minor/iter/61897.md
deleted file mode 100644
index 02d77cd11df35e9280c68e8b52aac4b398b3893a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/iter/61897.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/doc/next/6-stdlib/99-minor/maps/61900.md b/doc/next/6-stdlib/99-minor/maps/61900.md
deleted file mode 100644
index 02d77cd11df35e9280c68e8b52aac4b398b3893a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/maps/61900.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/doc/next/6-stdlib/99-minor/math/rand/v2/61716.md b/doc/next/6-stdlib/99-minor/math/rand/v2/61716.md
deleted file mode 100644
index 68ff614ee5c0d6d57f0e29708a604114c3c7673e..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/math/rand/v2/61716.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The [Uint] function and [Rand.Uint] method have been added.
-They were inadvertently left out of Go 1.22.
diff --git a/doc/next/6-stdlib/99-minor/math/rand/v2/67059.md b/doc/next/6-stdlib/99-minor/math/rand/v2/67059.md
deleted file mode 100644
index c66110c7a4453b8f46f8dc9fcf084a78f6a99b9e..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/math/rand/v2/67059.md
+++ /dev/null
@@ -1 +0,0 @@
-The new [ChaCha8.Read] method implements the [io.Reader] interface.
diff --git a/doc/next/6-stdlib/99-minor/net/62254.md b/doc/next/6-stdlib/99-minor/net/62254.md
deleted file mode 100644
index 639140bbec1f2d7646d36895a9edd30b9ec4fa5e..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/62254.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The new type [KeepAliveConfig] permits fine-tuning the keep-alive
-options for TCP connections, via a new [TCPConn.SetKeepAliveConfig]
-method and new KeepAliveConfig fields for [Dialer] and [ListenConfig].
diff --git a/doc/next/6-stdlib/99-minor/net/63116.md b/doc/next/6-stdlib/99-minor/net/63116.md
deleted file mode 100644
index 87a098374927b375cd3a8a9f7b34025df4ebfafe..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/63116.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The [DNSError] type now wraps errors caused by timeouts or cancellation.
-For example, `errors.Is(someDNSErr, context.DeadlineExceedeed)`
-will now report whether a DNS error was caused by a timeout.
diff --git a/doc/next/6-stdlib/99-minor/net/67925.md b/doc/next/6-stdlib/99-minor/net/67925.md
deleted file mode 100644
index e43f0cd644e243e984d1878567827e0485fb2074..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/67925.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The new `GODEBUG` setting `netedns0=0` disables sending EDNS0
-additional headers on DNS requests, as they reportedly break the DNS
-server on some modems.
diff --git a/doc/next/6-stdlib/99-minor/net/http/46443.md b/doc/next/6-stdlib/99-minor/net/http/46443.md
deleted file mode 100644
index 37ceae9eddd33b42307b62d3cf8f41d7a6b4447f..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/http/46443.md
+++ /dev/null
@@ -1,3 +0,0 @@
-[Cookie] now preserves double quotes surrounding a cookie value.
-The new [Cookie.Quoted] field indicates whether the [Cookie.Value]
-was originally quoted.
diff --git a/doc/next/6-stdlib/99-minor/net/http/61472.md b/doc/next/6-stdlib/99-minor/net/http/61472.md
deleted file mode 100644
index b3c2fd54094652f8a59791c146b0675b471dc7f0..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/http/61472.md
+++ /dev/null
@@ -1 +0,0 @@
-The new [Request.CookiesNamed] method retrieves all cookies that match the given name.
diff --git a/doc/next/6-stdlib/99-minor/net/http/62490.md b/doc/next/6-stdlib/99-minor/net/http/62490.md
deleted file mode 100644
index 891eb45daea33741d35cefc9801f8ec7ebea51b7..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/http/62490.md
+++ /dev/null
@@ -1 +0,0 @@
-The new [Cookie.Partitioned] field identifies cookies with the Partitioned attribute.
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/net/http/64910.md b/doc/next/6-stdlib/99-minor/net/http/64910.md
deleted file mode 100644
index 28452ee9327a386b986fa6b38732cdc7c0edb78c..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/http/64910.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The patterns used by [ServeMux] now allow one or more spaces or tabs after the method name.
-Previously, only a single space was permitted.
diff --git a/doc/next/6-stdlib/99-minor/net/http/66008.md b/doc/next/6-stdlib/99-minor/net/http/66008.md
deleted file mode 100644
index e8603707ef315066f16856dd6e4ca1a57b5eba6c..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/http/66008.md
+++ /dev/null
@@ -1,7 +0,0 @@
-The new [ParseCookie] function parses a Cookie header value and
-returns all the cookies which were set in it. Since the same cookie
-name can appear multiple times the returned Values can contain
-more than one value for a given key.
-
-The new [ParseSetCookie] function parses a Set-Cookie header value and
-returns a cookie. It returns an error on syntax error.
diff --git a/doc/next/6-stdlib/99-minor/net/http/66343.md b/doc/next/6-stdlib/99-minor/net/http/66343.md
deleted file mode 100644
index b39e8624e7def10396ab034cbff3c620eca5b1ef..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/http/66343.md
+++ /dev/null
@@ -1,16 +0,0 @@
-[ServeContent], [ServeFile], and [ServeFileFS] now remove
-the `Cache-Control`, `Content-Encoding`, `Etag`, and `Last-Modified`
-headers when serving an error. These headers usually apply to the
-non-error content, but not to the text of errors.
-
-Middleware which wraps a [ResponseWriter] and applies on-the-fly
-encoding, such as `Content-Encoding: gzip`, will not function after
-this change. The previous behavior of [ServeContent], [ServeFile],
-and [ServeFileFS] may be restored by setting
-`GODEBUG=httpservecontentkeepheaders=1`.
-
-Note that middleware which changes the size of the served content
-(such as by compressing it) already does not function properly when
-[ServeContent] handles a Range request. On-the-fly compression
-should use the `Transfer-Encoding` header instead of `Content-Encoding`.
-
diff --git a/doc/next/6-stdlib/99-minor/net/http/66405.md b/doc/next/6-stdlib/99-minor/net/http/66405.md
deleted file mode 100644
index c827b4b2192b875de645b7280e4a75330fab5d03..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/http/66405.md
+++ /dev/null
@@ -1,3 +0,0 @@
-For inbound requests, the new [Request.Pattern] field contains the [ServeMux]
-pattern (if any) that matched the request. This field is not set when
-`GODEBUG=httpmuxgo121=1` is set.
diff --git a/doc/next/6-stdlib/99-minor/net/http/httptest/59473.md b/doc/next/6-stdlib/99-minor/net/http/httptest/59473.md
deleted file mode 100644
index a640bbd0e4b08f9ac4e7a20c0c27ed8205d5a886..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/net/http/httptest/59473.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The new [NewRequestWithContext] method creates an incoming request with
-a [context.Context].
diff --git a/doc/next/6-stdlib/99-minor/os/33357.md b/doc/next/6-stdlib/99-minor/os/33357.md
deleted file mode 100644
index bd542d9d77ac0e3aa5331421e015dba1a6310554..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/os/33357.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The [Stat] function now sets the [ModeSocket] bit for
-files that are Unix sockets on Windows. These files are identified
-by having a reparse tag set to `IO_REPARSE_TAG_AF_UNIX`.
diff --git a/doc/next/6-stdlib/99-minor/os/61893.md b/doc/next/6-stdlib/99-minor/os/61893.md
deleted file mode 100644
index d22060c8698017f273015da417308018eb0689c0..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/os/61893.md
+++ /dev/null
@@ -1,7 +0,0 @@
-On Windows, the mode bits reported by [Lstat] and [Stat] for
-reparse points changed. Mount points no longer have [ModeSymlink] set,
-and reparse points that are not symlinks, Unix sockets, or dedup files
-now always have [ModeIrregular] set.
-This behavior is controlled by the `winsymlink` setting.
-For Go 1.23, it defaults to `winsymlink=1`.
-Previous versions default to `winsymlink=0`.
diff --git a/doc/next/6-stdlib/99-minor/os/62484.md b/doc/next/6-stdlib/99-minor/os/62484.md
deleted file mode 100644
index c99801bb6c7d9b81698dd5f0abc973f87a96ee29..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/os/62484.md
+++ /dev/null
@@ -1 +0,0 @@
-The [CopyFS] function copies an [io/fs.FS] into the local filesystem.
diff --git a/doc/next/6-stdlib/99-minor/os/63703.md b/doc/next/6-stdlib/99-minor/os/63703.md
deleted file mode 100644
index 3fbb2594cf795399055acad57e82efa04f0e7147..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/os/63703.md
+++ /dev/null
@@ -1,5 +0,0 @@
-On Windows, [Readlink] no longer tries to normalize volumes
-to drive letters, which was not always even possible.
-This behavior is controlled by the `winreadlinkvolume` setting.
-For Go 1.23, it defaults to `winreadlinkvolume=1`.
-Previous versions default to `winreadlinkvolume=0`.
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/path/filepath/57151.md b/doc/next/6-stdlib/99-minor/path/filepath/57151.md
deleted file mode 100644
index 5a99e3a4f2cffaacaf51f4cf62d04952cc81c10a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/path/filepath/57151.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The new [Localize] function safely converts a slash-separated
-path into an operating system path.
diff --git a/doc/next/6-stdlib/99-minor/path/filepath/63703.md b/doc/next/6-stdlib/99-minor/path/filepath/63703.md
deleted file mode 100644
index da2b132d8b3a7dc15807011296830ba328e5a108..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/path/filepath/63703.md
+++ /dev/null
@@ -1,11 +0,0 @@
-On Windows, [EvalSymlinks] no longer evaluates mount points,
-which was a source of many inconsistencies and bugs.
-This behavior is controlled by the `winsymlink` setting.
-For Go 1.23, it defaults to `winsymlink=1`.
-Previous versions default to `winsymlink=0`.
-
-On Windows, [EvalSymlinks] no longer tries to normalize
-volumes to drive letters, which was not always even possible.
-This behavior is controlled by the `winreadlinkvolume` setting.
-For Go 1.23, it defaults to `winreadlinkvolume=1`.
-Previous versions default to `winreadlinkvolume=0`.
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/reflect/60427.md b/doc/next/6-stdlib/99-minor/reflect/60427.md
deleted file mode 100644
index bca13607346e5629d35e070b854fa1db6ae12a1e..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/reflect/60427.md
+++ /dev/null
@@ -1,6 +0,0 @@
-The new methods synonymous with the method of the same name
-in [Value] are added to [Type]:
-1. [Type.OverflowComplex]
-2. [Type.OverflowFloat]
-3. [Type.OverflowInt]
-4. [Type.OverflowUint]
diff --git a/doc/next/6-stdlib/99-minor/reflect/61308.md b/doc/next/6-stdlib/99-minor/reflect/61308.md
deleted file mode 100644
index ec24655dce2c655096db1df63fc61b6ed50b272c..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/reflect/61308.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The new [SliceAt] function is analogous to [NewAt], but for slices.
-
-The [Value.Pointer] and [Value.UnsafePointer] methods now support values of kind [String].
diff --git a/doc/next/6-stdlib/99-minor/reflect/66056.md b/doc/next/6-stdlib/99-minor/reflect/66056.md
deleted file mode 100644
index b5f39349df1aa54f60b1f6dc54569599abbecf1d..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/reflect/66056.md
+++ /dev/null
@@ -1,4 +0,0 @@
-The new methods [Value.Seq] and [Value.Seq2] return sequences that iterate over the value
-as though it were used in a for/range loop.
-The new methods [Type.CanSeq] and [Type.CanSeq2] report whether calling
-[Value.Seq] and [Value.Seq2], respectively, will succeed without panicking.
diff --git a/doc/next/6-stdlib/99-minor/runtime/debug/42888.md b/doc/next/6-stdlib/99-minor/runtime/debug/42888.md
deleted file mode 100644
index f10753d25c20a9a5f2aa7794959761fbd3e67f8b..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/runtime/debug/42888.md
+++ /dev/null
@@ -1,5 +0,0 @@
-The [SetCrashOutput] function allows the user to specify an alternate
-file to which the runtime should write its fatal crash report.
-It may be used to construct an automated reporting mechanism for all
-unexpected crashes, not just those in goroutines that explicitly use
-`recover`.
diff --git a/doc/next/6-stdlib/99-minor/runtime/debug/67182.md b/doc/next/6-stdlib/99-minor/runtime/debug/67182.md
deleted file mode 100644
index d83864a3dbbcb8258f22420a65bcd703371df6f6..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/runtime/debug/67182.md
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/doc/next/6-stdlib/99-minor/runtime/pprof/43669.md b/doc/next/6-stdlib/99-minor/runtime/pprof/43669.md
deleted file mode 100644
index 119308b46a2d6bb817b2f610379953a3f68d615f..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/runtime/pprof/43669.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The maximum stack depth for alloc, mutex, block, threadcreate and goroutine
-profiles has been raised from 32 to 128 frames.
diff --git a/doc/next/6-stdlib/99-minor/runtime/trace/65319.md b/doc/next/6-stdlib/99-minor/runtime/trace/65319.md
deleted file mode 100644
index b180368e00b0a89fc8c65700a6b277dbe7ff1515..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/runtime/trace/65319.md
+++ /dev/null
@@ -1,4 +0,0 @@
-
-The runtime now explicitly flushes trace data when a program crashes due to an
-uncaught panic. This means that more complete trace data will be available in a
-trace if the program crashes while tracing is active.
diff --git a/doc/next/6-stdlib/99-minor/slices/53987.md b/doc/next/6-stdlib/99-minor/slices/53987.md
deleted file mode 100644
index 02d77cd11df35e9280c68e8b52aac4b398b3893a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/slices/53987.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/doc/next/6-stdlib/99-minor/slices/61899.md b/doc/next/6-stdlib/99-minor/slices/61899.md
deleted file mode 100644
index 02d77cd11df35e9280c68e8b52aac4b398b3893a..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/slices/61899.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/doc/next/6-stdlib/99-minor/slices/65238.md b/doc/next/6-stdlib/99-minor/slices/65238.md
deleted file mode 100644
index 34ef66a2dd1d7ada72f2b1ff7dd542e745b10381..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/slices/65238.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The [Repeat] function returns a new slice that repeats the
-provided slice the given number of times.
diff --git a/doc/next/6-stdlib/99-minor/structs/66408.md b/doc/next/6-stdlib/99-minor/structs/66408.md
deleted file mode 100644
index 810a09e3ca825cd8fa21c5954cbe9f4354a86142..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/structs/66408.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/doc/next/6-stdlib/99-minor/sync/61696.md b/doc/next/6-stdlib/99-minor/sync/61696.md
deleted file mode 100644
index 59584301f3dd94fe7465f9d786386253b839a40d..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/sync/61696.md
+++ /dev/null
@@ -1,2 +0,0 @@
-The [Map.Clear] method deletes all the entries, resulting in
-an empty [Map]. It is analogous to `clear`.
diff --git a/doc/next/6-stdlib/99-minor/sync/atomic/61395.md b/doc/next/6-stdlib/99-minor/sync/atomic/61395.md
deleted file mode 100644
index 8aea9d6bf3a77a5c9a3090f7d9afc457a0f205ff..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/sync/atomic/61395.md
+++ /dev/null
@@ -1,3 +0,0 @@
-
-The new [And] and [Or] operators apply a bitwise `AND` or `OR` to
-the given input, returning the old value.
diff --git a/doc/next/6-stdlib/99-minor/syscall/62254.md b/doc/next/6-stdlib/99-minor/syscall/62254.md
deleted file mode 100644
index 1d463e5ea8127fe3c81fb06ab517c1012fbe1a90..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/syscall/62254.md
+++ /dev/null
@@ -1 +0,0 @@
-The syscall package now defines [WSAENOPROTOOPT] on Windows.
diff --git a/doc/next/6-stdlib/99-minor/syscall/65817.md b/doc/next/6-stdlib/99-minor/syscall/65817.md
deleted file mode 100644
index 9a2d12c0741e49db343ef01265f6bca1755f21d6..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/syscall/65817.md
+++ /dev/null
@@ -1 +0,0 @@
-The [GetsockoptInt] function is now supported on Windows.
diff --git a/doc/next/6-stdlib/99-minor/testing/fstest/63675.md b/doc/next/6-stdlib/99-minor/testing/fstest/63675.md
deleted file mode 100644
index cea9ae3dc2e1a03688c00399f7e0e8142c07feaa..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/testing/fstest/63675.md
+++ /dev/null
@@ -1,3 +0,0 @@
-[TestFS] now returns a structured error that can be unwrapped
-(via method `Unwrap() []error`). This allows inspecting errors
-using [errors.Is] or [errors.As].
diff --git a/doc/next/6-stdlib/99-minor/text/template/57646.md b/doc/next/6-stdlib/99-minor/text/template/57646.md
deleted file mode 100644
index 5b8f031432d1a6316630057f2ddf9b0d539bd7e5..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/text/template/57646.md
+++ /dev/null
@@ -1 +0,0 @@
-Templates now support the new "else with" action, which reduces template complexity in some use cases.
diff --git a/doc/next/6-stdlib/99-minor/time/67470.md b/doc/next/6-stdlib/99-minor/time/67470.md
deleted file mode 100644
index 8cfcc0aa9da31b668c901ea1e362f54f3b6f2669..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/time/67470.md
+++ /dev/null
@@ -1,2 +0,0 @@
-[Parse] and [ParseInLocation] now return an error if the time zone
-offset is out of range.
diff --git a/doc/next/6-stdlib/99-minor/unicode/utf16/44940.md b/doc/next/6-stdlib/99-minor/unicode/utf16/44940.md
deleted file mode 100644
index e0667845883d3ea3eda4b1e59f6a18975d8e15ac..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/unicode/utf16/44940.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The [RuneLen] function returns the number of 16-bit words in
-the UTF-16 encoding of the rune. It returns -1 if the rune
-is not a valid value to encode in UTF-16.
diff --git a/doc/next/6-stdlib/99-minor/unique/62483.md b/doc/next/6-stdlib/99-minor/unique/62483.md
deleted file mode 100644
index d281ab290e361d954b2c65a0721729e5ab02b3bc..0000000000000000000000000000000000000000
--- a/doc/next/6-stdlib/99-minor/unique/62483.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/doc/next/7-ports.md b/doc/next/7-ports.md
deleted file mode 100644
index 51e0ac7441ad4e6d7c9441fece1e10e183045a09..0000000000000000000000000000000000000000
--- a/doc/next/7-ports.md
+++ /dev/null
@@ -1,38 +0,0 @@
-## Ports {#ports}
-
-### Darwin {#darwin}
-
-
-As [announced](go1.22#darwin) in the Go 1.22 release notes,
-Go 1.23 requires macOS 11 Big Sur or later;
-support for previous versions has been discontinued.
-
-### Linux {#linux}
-
-
-Go 1.23 is the last release that requires Linux kernel version 2.6.32 or later. Go 1.24 will require Linux kernel version 3.17 or later, with an exception that systems running 3.10 or later will continue to be supported if the kernel has been patched to support the getrandom system call.
-
-### OpenBSD {#openbsd}
-
-
-Go 1.23 adds experimental support for OpenBSD on 64-bit RISC-V (`GOOS=openbsd`, `GOARCH=riscv64`).
-
-### ARM64 {#arm64}
-
-
-Go 1.23 introduces a new `GOARM64` environment variable, which specifies the minimum target version of the ARM64 architecture at compile time. Allowed values are `v8.{0-9}` and `v9.{0-5}`. This may be followed by an option specifying extensions implemented by target hardware. Valid options are `,lse` and `,crypto`.
-
-The `GOARM64` environment variable defaults to `v8.0`.
-
-### RISC-V {#riscv}
-
-
-Go 1.23 introduces a new `GORISCV64` environment variable, which selects the [RISC-V user-mode application profile](https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc) for which to compile. Allowed values are `rva20u64` and `rva22u64`.
-
-The `GORISCV64` environment variable defaults to `rva20u64`.
-
-### Wasm {#wasm}
-
-
-The `go_wasip1_wasm_exec` script in `GOROOT/misc/wasm` has dropped support
-for versions of `wasmtime` < 14.0.0.
diff --git a/doc/next/9-todo.md b/doc/next/9-todo.md
deleted file mode 100644
index 424780cd7d85cf0eb26f914430e5da7016d4ba8d..0000000000000000000000000000000000000000
--- a/doc/next/9-todo.md
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/cmd/addr2line/main.go b/src/cmd/addr2line/main.go
index b1ec4e02785d7338a387455c1a6836e5545461c4..500da717ff3f2d84c4d76aaa2b323123651d1df0 100644
--- a/src/cmd/addr2line/main.go
+++ b/src/cmd/addr2line/main.go
@@ -28,7 +28,7 @@ "strconv"
"strings"
"cmd/internal/objfile"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
func printUsage(w *os.File) {
@@ -46,7 +46,7 @@
func main() {
log.SetFlags(0)
log.SetPrefix("addr2line: ")
- telemetry.OpenCounters()
+ counter.Open()
// pprof expects this behavior when checking for addr2line
if len(os.Args) > 1 && os.Args[1] == "--help" {
@@ -56,8 +56,8 @@ }
flag.Usage = usage
flag.Parse()
- telemetry.Inc("addr2line/invocations")
- telemetry.CountFlags("addr2line/flag:", *flag.CommandLine)
+ counter.Inc("addr2line/invocations")
+ counter.CountFlags("addr2line/flag:", *flag.CommandLine)
if flag.NArg() != 1 {
usage()
}
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index ecad08b37aa021ee87f83e77def30e590a496809..f12cdaf921fc44fef1d766ea5f4f4c62ba488546 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -961,7 +961,11 @@ CASPW (R6, R7), (R8), (R4, R5) // 047d2608
CASPD (R2, R3), (R2), (R8, R9) // 487c2248
// RET
- RET
+ RET // c0035fd6
+ RET R0 // 00005fd6
+ RET R6 // c0005fd6
+ RET R27 // 60035fd6
+ RET R30 // c0035fd6
RET foo(SB)
// B/BL/B.cond cases, and canonical names JMP, CALL.
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index ca4e25d047c4a9706960991f6ba12dfc67002881..9fdb7c49a2bb5631e5fe4309cd70b67de35a00e5 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -20,20 +20,20 @@
"cmd/internal/bio"
"cmd/internal/obj"
"cmd/internal/objabi"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
func main() {
log.SetFlags(0)
log.SetPrefix("asm: ")
- telemetry.OpenCounters()
+ counter.Open()
buildcfg.Check()
GOARCH := buildcfg.GOARCH
flags.Parse()
- telemetry.Inc("asm/invocations")
- telemetry.CountFlags("asm/flag:", *flag.CommandLine)
+ counter.Inc("asm/invocations")
+ counter.CountFlags("asm/flag:", *flag.CommandLine)
architecture := arch.Set(GOARCH, *flags.Shared || *flags.Dynlink)
if architecture == nil {
diff --git a/src/cmd/buildid/buildid.go b/src/cmd/buildid/buildid.go
index a008122a0aa743380071b2c23fc25a1f5cf4708a..a16b96f677a676ef7dcd902f332cd7391ce06c4d 100644
--- a/src/cmd/buildid/buildid.go
+++ b/src/cmd/buildid/buildid.go
@@ -12,7 +12,7 @@ "os"
"strings"
"cmd/internal/buildid"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
func usage() {
@@ -26,11 +26,11 @@
func main() {
log.SetPrefix("buildid: ")
log.SetFlags(0)
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = usage
flag.Parse()
- telemetry.Inc("buildid/invocations")
- telemetry.CountFlags("buildid/flag:", *flag.CommandLine)
+ counter.Inc("buildid/invocations")
+ counter.CountFlags("buildid/flag:", *flag.CommandLine)
if flag.NArg() != 1 {
usage()
}
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index b596477b0a65f1054d31dc4beb81ca8a5ebe53fe..6c23e59adf19eb6e49d789de6b6ef722747187f7 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1601,8 +1601,8 @@ error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
break
}
if r.Context == ctxCall2 {
- if r.Name.Go == "_CMalloc" {
- error_(r.Pos(), "no two-result form for C.malloc")
+ if builtinDefs[r.Name.Go] != "" {
+ error_(r.Pos(), "no two-result form for C.%s", r.Name.Go)
break
}
// Invent new Name for the two-result function.
diff --git a/src/cmd/cgo/internal/testerrors/errors_test.go b/src/cmd/cgo/internal/testerrors/errors_test.go
index 07556007a84fe88b101bc84f7edd546db5f1ecb2..eddfb6583b9e7715fb4a236af587b4f4b0a4f60d 100644
--- a/src/cmd/cgo/internal/testerrors/errors_test.go
+++ b/src/cmd/cgo/internal/testerrors/errors_test.go
@@ -127,6 +127,7 @@ "issue28721.go",
"issue33061.go",
"issue50710.go",
"issue67517.go",
+ "issue67707.go",
} {
check(t, file)
}
diff --git a/src/cmd/cgo/internal/testerrors/testdata/issue67707.go b/src/cmd/cgo/internal/testerrors/testdata/issue67707.go
new file mode 100644
index 0000000000000000000000000000000000000000..4f80de165e3b19dc01512a1f14551fdb7533e42b
--- /dev/null
+++ b/src/cmd/cgo/internal/testerrors/testdata/issue67707.go
@@ -0,0 +1,15 @@
+// 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 p
+
+import "C"
+
+func F() *C.char {
+ s, err := C.CString("hi") // ERROR HERE: no two-result form
+ if err != nil {
+ println(err)
+ }
+ return s
+}
diff --git a/src/cmd/cgo/internal/testplugin/plugin_test.go b/src/cmd/cgo/internal/testplugin/plugin_test.go
index 4900ada18201567de89e86615f08ce2c2c816618..85dfd31123b5dedd27aa83544caf692bc3805395 100644
--- a/src/cmd/cgo/internal/testplugin/plugin_test.go
+++ b/src/cmd/cgo/internal/testplugin/plugin_test.go
@@ -414,3 +414,11 @@ if !strings.Contains(syms, "runtime.text.1") {
t.Errorf("runtime.text.1 not found, text section not split?")
}
}
+
+func TestIssue67976(t *testing.T) {
+ // Issue 67976: build failure with loading a dynimport variable (the runtime/pprof
+ // package does this on darwin) in a plugin on darwin/amd64.
+ // The test program uses runtime/pprof in a plugin.
+ globalSkip(t)
+ goCmd(t, "build", "-buildmode=plugin", "-o", "issue67976.so", "./issue67976/plugin.go")
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue67976/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue67976/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..502ecc5c4750f4920759768a408eb197f3afc022
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue67976/plugin.go
@@ -0,0 +1,16 @@
+// 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
+
+import (
+ "io"
+ "runtime/pprof"
+)
+
+func main() {}
+
+func Start() {
+ pprof.StartCPUProfile(io.Discard)
+}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index bf879be814fe997798204edb10b2e01f3e9b907b..5699cc55be0e66ea38fa108b2904293d167bd88e 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -28,7 +28,7 @@
"cmd/internal/edit"
"cmd/internal/notsha256"
"cmd/internal/objabi"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
// A Package collects information about the package we're going to write.
@@ -258,11 +258,11 @@ var goarch, goos, gomips, gomips64 string
var gccBaseCmd []string
func main() {
- telemetry.OpenCounters()
+ counter.Open()
objabi.AddVersionFlag() // -V
objabi.Flagparse(usage)
- telemetry.Inc("cgo/invocations")
- telemetry.CountFlags("cgo/flag:", *flag.CommandLine)
+ counter.Inc("cgo/invocations")
+ counter.CountFlags("cgo/flag:", *flag.CommandLine)
if *gccgoDefineCgoIncomplete {
if !*gccgo {
@@ -339,6 +339,21 @@ if *ldflags != "" {
args, err := splitQuoted(*ldflags)
if err != nil {
fatalf("bad -ldflags option: %q (%s)", *ldflags, err)
+ }
+ p.addToFlag("LDFLAGS", args)
+ }
+
+ // For backward compatibility for Bazel, record CGO_LDFLAGS
+ // from the environment for external linking.
+ // This should not happen with cmd/go, which removes CGO_LDFLAGS
+ // from the environment when invoking cgo.
+ // This can be removed when we no longer need to support
+ // older versions of Bazel. See issue #66456 and
+ // https://github.com/bazelbuild/rules_go/issues/3979.
+ if envFlags := os.Getenv("CGO_LDFLAGS"); envFlags != "" {
+ args, err := splitQuoted(envFlags)
+ if err != nil {
+ fatalf("bad CGO_LDFLAGS: %q (%s)", envFlags, err)
}
p.addToFlag("LDFLAGS", args)
}
diff --git a/src/cmd/compile/README.md b/src/cmd/compile/README.md
index 3fc7ca6ec6699baf7a3d470a208484011896f37d..cffb4e7a80fa933872d25c432349676a411ae037 100644
--- a/src/cmd/compile/README.md
+++ b/src/cmd/compile/README.md
@@ -63,7 +63,6 @@ Unified IR is also involved in import/export of packages and inlining.
### 4. Middle end
-* `cmd/compile/internal/deadcode` (dead code elimination)
* `cmd/compile/internal/inline` (function call inlining)
* `cmd/compile/internal/devirtualize` (devirtualization of known interface method calls)
* `cmd/compile/internal/escape` (escape analysis)
@@ -71,6 +70,8 @@
Several optimization passes are performed on the IR representation:
dead code elimination, (early) devirtualization, function call
inlining, and escape analysis.
+
+The early dead code elimination pass is integrated into the unified IR writer phase.
### 5. Walk
diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go
index 8c17c5f27d8802f645f8f3340cea0650f7cdeda4..b296f3666cf4752c06466dba4da787e69201f6ed 100644
--- a/src/cmd/compile/internal/base/flag.go
+++ b/src/cmd/compile/internal/base/flag.go
@@ -6,7 +6,7 @@ package base
import (
"cmd/internal/cov/covcmd"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"encoding/json"
"flag"
"fmt"
@@ -195,7 +195,7 @@
objabi.AddVersionFlag() // -V
registerFlags()
objabi.Flagparse(usage)
- telemetry.CountFlags("compile/flag:", *flag.CommandLine)
+ counter.CountFlags("compile/flag:", *flag.CommandLine)
if gcd := os.Getenv("GOCOMPILEDEBUG"); gcd != "" {
// This will only override the flags set in gcd;
diff --git a/src/cmd/compile/internal/base/print.go b/src/cmd/compile/internal/base/print.go
index 15256186afe4dcad1d9e5c487a6e2c8ba2b9c57b..119f06fbc033518e5942ef64710ec1e965ec15d7 100644
--- a/src/cmd/compile/internal/base/print.go
+++ b/src/cmd/compile/internal/base/print.go
@@ -14,7 +14,7 @@ "sort"
"strings"
"cmd/internal/src"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
// An errorMsg is a queued error message, waiting to be printed.
@@ -195,7 +195,7 @@ func Fatalf(format string, args ...interface{}) {
FatalfAt(Pos, format, args...)
}
-var bugStack = telemetry.NewStackCounter("compile/bug", 16) // 16 is arbitrary; used by gopls and crashmonitor
+var bugStack = counter.NewStack("compile/bug", 16) // 16 is arbitrary; used by gopls and crashmonitor
// FatalfAt reports a fatal error - an internal problem - at pos and exits.
// If other errors have already been printed, then FatalfAt just quietly exits.
diff --git a/src/cmd/compile/internal/dwarfgen/dwarf.go b/src/cmd/compile/internal/dwarfgen/dwarf.go
index 512d8d22e757b6198d496b67df1bbd949be529ed..36cc253e827de5856f72dce4fcacd6b0061e0ca1 100644
--- a/src/cmd/compile/internal/dwarfgen/dwarf.go
+++ b/src/cmd/compile/internal/dwarfgen/dwarf.go
@@ -91,6 +91,9 @@ case ir.PPARAM, ir.PPARAMOUT:
default:
continue
}
+ if !ssa.IsVarWantedForDebug(n) {
+ continue
+ }
apdecls = append(apdecls, n)
if n.Type().Kind() == types.TSSA {
// Can happen for TypeInt128 types. This only happens for
@@ -194,6 +197,9 @@ // entries here so that we can process them properly during
// DWARF-gen. See issue 48573 for more details.
debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
for _, n := range debugInfo.RegOutputParams {
+ if !ssa.IsVarWantedForDebug(n) {
+ continue
+ }
if n.Class != ir.PPARAMOUT || !n.IsOutputParamInRegisters() {
panic("invalid ir.Name on debugInfo.RegOutputParams list")
}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 3887d4156d6e3f4988c3888c3b6261e42cf226c5..f68cf4deaf041a92d34ba3ac610adb519e2bf2a6 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -30,7 +30,7 @@ "cmd/internal/dwarf"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/src"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"flag"
"fmt"
"internal/buildcfg"
@@ -59,8 +59,8 @@ // arguments, type-checks the parsed Go package, compiles functions to machine
// code, and finally writes the compiled package definition to disk.
func Main(archInit func(*ssagen.ArchInfo)) {
base.Timer.Start("fe", "init")
- telemetry.OpenCounters()
- telemetry.Inc("compile/invocations")
+ counter.Open()
+ counter.Inc("compile/invocations")
defer handlePanic()
diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go
index 22d6f71329c3754f3fa2ce486f34833e518c62a0..6bc23cc5f922742b684455350749074df0ce20df 100644
--- a/src/cmd/compile/internal/noder/unified.go
+++ b/src/cmd/compile/internal/noder/unified.go
@@ -7,6 +7,7 @@
import (
"fmt"
"internal/pkgbits"
+ "internal/types/errors"
"io"
"runtime"
"sort"
@@ -403,7 +404,10 @@ {
r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic)
pkg := r.pkg()
- base.Assertf(pkg == importpkg, "have package %q (%p), want package %q (%p)", pkg.Path, pkg, importpkg.Path, importpkg)
+ if pkg != importpkg {
+ base.ErrorfAt(base.AutogeneratedPos, errors.BadImportPath, "mismatched import path, have %q (%p), want %q (%p)", pkg.Path, pkg, importpkg.Path, importpkg)
+ base.ErrorExit()
+ }
r.Bool() // TODO(mdempsky): Remove; was "has init"
diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index fe8f8f2a351394b93f3085fb8f8198066f3bb901..8fed138a4a120290daee3525ce9905f98fb75f02 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -1582,6 +1582,7 @@ w.pos(stmt)
w.stmt(stmt.Init)
var iface, tagType types2.Type
+ var tagTypeIsChan bool
if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.Bool(ok) {
iface = w.p.typeOf(guard.X)
@@ -1603,6 +1604,7 @@ if tag != nil {
tv := w.p.typeAndValue(tag)
tagType = tv.Type
tagValue = tv.Value
+ _, tagTypeIsChan = tagType.Underlying().(*types2.Chan)
} else {
tagType = types2.Typ[types2.Bool]
tagValue = constant.MakeBool(true)
@@ -1655,12 +1657,18 @@ // each case expression, and we want these comparisons to always
// have the same type. If there are any case values that can't be
// converted to the tag value's type, then convert everything to
// `any` instead.
- Outer:
- for _, clause := range stmt.Body {
- for _, cas := range syntax.UnpackListExpr(clause.Cases) {
- if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) {
- tagType = types2.NewInterfaceType(nil, nil)
- break Outer
+ //
+ // Except that we need to keep comparisons of channel values from
+ // being wrapped in any(). See issue #67190.
+
+ if !tagTypeIsChan {
+ Outer:
+ for _, clause := range stmt.Body {
+ for _, cas := range syntax.UnpackListExpr(clause.Cases) {
+ if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) {
+ tagType = types2.NewInterfaceType(nil, nil)
+ break Outer
+ }
}
}
}
@@ -1696,7 +1704,11 @@ w.Sync(pkgbits.SyncExprList)
w.Sync(pkgbits.SyncExprs)
w.Len(len(cases))
for _, cas := range cases {
- w.implicitConvExpr(tagType, cas)
+ typ := tagType
+ if tagTypeIsChan {
+ typ = nil
+ }
+ w.implicitConvExpr(typ, cas)
}
}
diff --git a/src/cmd/compile/internal/rangefunc/rewrite.go b/src/cmd/compile/internal/rangefunc/rewrite.go
index e5a0b9f8af141780bed94fd39b6c7ec8971c4201..ba2eb8d0fdcf757f7d169437f0d63db64a3bec94 100644
--- a/src/cmd/compile/internal/rangefunc/rewrite.go
+++ b/src/cmd/compile/internal/rangefunc/rewrite.go
@@ -1137,7 +1137,7 @@ // that should be at the start or end of the loop.
func (r *rewriter) bodyFunc(body []syntax.Stmt, lhs []syntax.Expr, def bool, ftyp *types2.Signature, start, end syntax.Pos) *syntax.FuncLit {
// Starting X(bodyFunc); build up bodyFunc first.
var params, results []*types2.Var
- results = append(results, types2.NewVar(start, nil, "", r.bool.Type()))
+ results = append(results, types2.NewVar(start, nil, "#r", r.bool.Type()))
bodyFunc := &syntax.FuncLit{
// Note: Type is ignored but needs to be non-nil to avoid panic in syntax.Inspect.
Type: &syntax.FuncType{},
diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go
index 4abe5a98924f49e1067a47a12dbc0face3a83e78..04025f78829a50cd01745a41e647da8968844013 100644
--- a/src/cmd/compile/internal/ssa/debug.go
+++ b/src/cmd/compile/internal/ssa/debug.go
@@ -600,7 +600,7 @@ state.slots = state.slots[:0]
state.vars = state.vars[:0]
for i, slot := range f.Names {
state.slots = append(state.slots, *slot)
- if ir.IsSynthetic(slot.N) {
+ if ir.IsSynthetic(slot.N) || !IsVarWantedForDebug(slot.N) {
continue
}
@@ -620,7 +620,7 @@ for _, b := range f.Blocks {
for _, v := range b.Values {
if v.Op == OpVarDef {
n := v.Aux.(*ir.Name)
- if ir.IsSynthetic(n) {
+ if ir.IsSynthetic(n) || !IsVarWantedForDebug(n) {
continue
}
@@ -665,7 +665,7 @@
state.initializeCache(f, len(state.varParts), len(state.slots))
for i, slot := range f.Names {
- if ir.IsSynthetic(slot.N) {
+ if ir.IsSynthetic(slot.N) || !IsVarWantedForDebug(slot.N) {
continue
}
for _, value := range f.NamedValues[*slot] {
@@ -1087,7 +1087,7 @@
switch {
case v.Op == OpVarDef:
n := v.Aux.(*ir.Name)
- if ir.IsSynthetic(n) {
+ if ir.IsSynthetic(n) || !IsVarWantedForDebug(n) {
break
}
@@ -1835,6 +1835,9 @@ if !isNamedRegParam(inp) {
// will be sorted out elsewhere
continue
}
+ if !IsVarWantedForDebug(inp.Name) {
+ continue
+ }
addVarSlot(inp.Name, inp.Type)
params = append(params, inp)
}
@@ -1853,6 +1856,9 @@ pidx := 0
for _, inp := range params {
if !isNamedRegParam(inp) {
// will be sorted out elsewhere
+ continue
+ }
+ if !IsVarWantedForDebug(inp.Name) {
continue
}
@@ -1948,3 +1954,19 @@ rval.LocationLists[pidx] = list
pidx++
}
}
+
+// IsVarWantedForDebug returns true if the debug info for the node should
+// be generated.
+// For example, internal variables for range-over-func loops have little
+// value to users, so we don't generate debug info for them.
+func IsVarWantedForDebug(n ir.Node) bool {
+ name := n.Sym().Name
+ if len(name) > 0 && name[0] == '&' {
+ name = name[1:]
+ }
+ if len(name) > 0 && name[0] == '#' {
+ // #yield is used by delve.
+ return strings.HasPrefix(name, "#yield")
+ }
+ return true
+}
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index aeec2b3768c0b366baacd81106f384c6f93581be..5bc03083628117d388128f6a4488575c517f3cc3 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -1287,6 +1287,11 @@ // check if value zeroes out upper 32-bit of 64-bit register.
// depth limits recursion depth. In AMD64.rules 3 is used as limit,
// because it catches same amount of cases as 4.
func zeroUpper32Bits(x *Value, depth int) bool {
+ if x.Type.IsSigned() && x.Type.Size() < 8 {
+ // If the value is signed, it might get re-sign-extended
+ // during spill and restore. See issue 68227.
+ return false
+ }
switch x.Op {
case OpAMD64MOVLconst, OpAMD64MOVLload, OpAMD64MOVLQZX, OpAMD64MOVLloadidx1,
OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVBload, OpAMD64MOVBloadidx1,
@@ -1305,7 +1310,7 @@ return true
case OpArg: // note: but not ArgIntReg
// amd64 always loads args from the stack unsigned.
// most other architectures load them sign/zero extended based on the type.
- return x.Type.Size() == 4 && (x.Type.IsUnsigned() || x.Block.Func.Config.arch == "amd64")
+ return x.Type.Size() == 4 && x.Block.Func.Config.arch == "amd64"
case OpPhi, OpSelect0, OpSelect1:
// Phis can use each-other as an arguments, instead of tracking visited values,
// just limit recursion depth.
@@ -1325,11 +1330,14 @@ }
// zeroUpper48Bits is similar to zeroUpper32Bits, but for upper 48 bits.
func zeroUpper48Bits(x *Value, depth int) bool {
+ if x.Type.IsSigned() && x.Type.Size() < 8 {
+ return false
+ }
switch x.Op {
case OpAMD64MOVWQZX, OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2:
return true
case OpArg: // note: but not ArgIntReg
- return x.Type.Size() == 2 && (x.Type.IsUnsigned() || x.Block.Func.Config.arch == "amd64")
+ return x.Type.Size() == 2 && x.Block.Func.Config.arch == "amd64"
case OpPhi, OpSelect0, OpSelect1:
// Phis can use each-other as an arguments, instead of tracking visited values,
// just limit recursion depth.
@@ -1349,11 +1357,14 @@ }
// zeroUpper56Bits is similar to zeroUpper32Bits, but for upper 56 bits.
func zeroUpper56Bits(x *Value, depth int) bool {
+ if x.Type.IsSigned() && x.Type.Size() < 8 {
+ return false
+ }
switch x.Op {
case OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1:
return true
case OpArg: // note: but not ArgIntReg
- return x.Type.Size() == 1 && (x.Type.IsUnsigned() || x.Block.Func.Config.arch == "amd64")
+ return x.Type.Size() == 1 && x.Block.Func.Config.arch == "amd64"
case OpPhi, OpSelect0, OpSelect1:
// Phis can use each-other as an arguments, instead of tracking visited values,
// just limit recursion depth.
diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go
index 7317ed1fec4249d5e55b5ecd09986f64b2aaa5f9..91c0a27faf02955ee1b79ff1e03d36a6828a7e7e 100644
--- a/src/cmd/compile/internal/staticinit/sched.go
+++ b/src/cmd/compile/internal/staticinit/sched.go
@@ -107,6 +107,20 @@ base.FatalfAt(n.Pos(), "unexpected initialization statement: %v", n)
case ir.OAS:
n := n.(*ir.AssignStmt)
lhs, rhs = []ir.Node{n.X}, n.Y
+ case ir.OAS2:
+ // Usually OAS2 has been rewritten to separate OASes by types2.
+ // What's left here is "var a, b = tmp1, tmp2" as a result from rewriting
+ // "var a, b = f()" that needs type conversion, which is not static.
+ n := n.(*ir.AssignListStmt)
+ for _, rhs := range n.Rhs {
+ for rhs.Op() == ir.OCONVNOP {
+ rhs = rhs.(*ir.ConvExpr).X
+ }
+ if name, ok := rhs.(*ir.Name); !ok || !name.AutoTemp() {
+ base.FatalfAt(n.Pos(), "unexpected rhs, not an autotmp: %+v", rhs)
+ }
+ }
+ return false
case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
n := n.(*ir.AssignListStmt)
if len(n.Lhs) < 2 || len(n.Rhs) != 1 {
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index b4b9ecd8368b99c96208856e4e6aed435ab59b2b..ec849e315400c38f0420c08f9e6dd3ac3e63f611 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -663,14 +663,14 @@ n.PtrInit().Append(Stmt(as))
switch n := n.(type) {
default:
- base.Fatalf("rewriteMultiValueCall %+v", n.Op())
+ base.Fatalf("RewriteMultiValueCall %+v", n.Op())
case *ir.CallExpr:
n.Args = list
case *ir.ReturnStmt:
n.Results = list
case *ir.AssignListStmt:
if n.Op() != ir.OAS2FUNC {
- base.Fatalf("rewriteMultiValueCall: invalid op %v", n.Op())
+ base.Fatalf("RewriteMultiValueCall: invalid op %v", n.Op())
}
as.SetOp(ir.OAS2FUNC)
n.SetOp(ir.OAS2)
diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go
index b4da3c0b915befae020440c5250d9cb23c9d859e..20e3f52facd9deb4f3f38ca8aec21cf6fd53f728 100644
--- a/src/cmd/compile/internal/types2/issues_test.go
+++ b/src/cmd/compile/internal/types2/issues_test.go
@@ -1092,3 +1092,32 @@ // even though the (module) Go version is set to go1.17.
conf := Config{GoVersion: "go1.17"}
mustTypecheck(src, &conf, nil)
}
+
+func TestIssue68334(t *testing.T) {
+ const src = `
+package p
+
+func f(x int) {
+ for i, j := range x {
+ _, _ = i, j
+ }
+ var a, b int
+ for a, b = range x {
+ _, _ = a, b
+ }
+}
+`
+
+ got := ""
+ conf := Config{
+ GoVersion: "go1.21", // #68334 requires GoVersion <= 1.21
+ Error: func(err error) { got += err.Error() + "\n" }, // #68334 requires Error != nil
+ }
+ typecheck(src, &conf, nil) // do not crash
+
+ want := "p:5:20: cannot range over x (variable of type int): requires go1.22 or later\n" +
+ "p:9:19: cannot range over x (variable of type int): requires go1.22 or later\n"
+ if got != want {
+ t.Errorf("got: %s want: %s", got, want)
+ }
+}
diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go
index 58783f47c3cec5b2d6cec83e74089ab303ba45da..b598a4f068621db562f920dfbf37455db5e912df 100644
--- a/src/cmd/compile/internal/types2/stmt.go
+++ b/src/cmd/compile/internal/types2/stmt.go
@@ -920,14 +920,15 @@ assert(obj.typ == nil)
// initialize lhs iteration variable, if any
typ := rhs[i]
- if typ == nil {
+ if typ == nil || typ == Typ[Invalid] {
+ // typ == Typ[Invalid] can happen if allowVersion fails.
obj.typ = Typ[Invalid]
obj.used = true // don't complain about unused variable
continue
}
if rangeOverInt {
- assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
+ assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
check.initVar(obj, &x, "range clause")
} else {
var y operand
@@ -957,12 +958,12 @@ }
// assign to lhs iteration variable, if any
typ := rhs[i]
- if typ == nil {
+ if typ == nil || typ == Typ[Invalid] {
continue
}
if rangeOverInt {
- assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
+ assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
check.assignVar(lhs, nil, &x, "range clause")
// If the assignment succeeded, if x was untyped before, it now
// has a type inferred via the assignment. It must be an integer.
diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go
index 9ad064906fb25bbae5767a7b3169221cd6cd555a..e22981e1ad0c00d958240c80acc13bcd91323e94 100644
--- a/src/cmd/compile/internal/types2/typeparam.go
+++ b/src/cmd/compile/internal/types2/typeparam.go
@@ -25,8 +25,8 @@ bound Type // any type, but underlying is eventually *Interface for correct programs (see TypeParam.iface)
}
// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
-// or Signature type by calling SetTypeParams. Setting a type parameter on more
-// than one type will result in a panic.
+// type by calling SetTypeParams. Setting a type parameter on more than one type
+// will result in a panic.
//
// The constraint argument can be nil, and set later via SetConstraint. If the
// constraint is non-nil, it must be fully defined.
diff --git a/src/cmd/covdata/covdata.go b/src/cmd/covdata/covdata.go
index 48d7b9ed08915a786b15bd5d648a5cb2055edf8b..122ad28b5cafce6e2753e71f8ebf0afa440d0e32 100644
--- a/src/cmd/covdata/covdata.go
+++ b/src/cmd/covdata/covdata.go
@@ -7,7 +7,7 @@
import (
"cmd/internal/cov"
"cmd/internal/pkgpattern"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"flag"
"fmt"
"os"
@@ -109,7 +109,7 @@ debugDumpMode = "debugdump"
)
func main() {
- telemetry.OpenCounters()
+ counter.Open()
// First argument should be mode/subcommand.
if len(os.Args) < 2 {
@@ -146,8 +146,8 @@ flag.Usage = func() {
op.Usage("")
}
flag.Parse()
- telemetry.Inc("covdata/invocations")
- telemetry.CountFlags("covdata/flag:", *flag.CommandLine)
+ counter.Inc("covdata/invocations")
+ counter.CountFlags("covdata/flag:", *flag.CommandLine)
// Mode-independent flag setup
dbgtrace(1, "starting mode-independent setup")
diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go
index 47eebaadd3a1ce4e3dc4c0f147edc8a6c5b37817..d8bb989bcce2444baf75405cbc25f9c25aeff665 100644
--- a/src/cmd/cover/cover.go
+++ b/src/cmd/cover/cover.go
@@ -26,7 +26,7 @@ "strings"
"cmd/internal/edit"
"cmd/internal/objabi"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
const usageMessage = "" +
@@ -87,13 +87,13 @@ atomicPackageName = "_cover_atomic_"
)
func main() {
- telemetry.OpenCounters()
+ counter.Open()
objabi.AddVersionFlag()
flag.Usage = usage
objabi.Flagparse(usage)
- telemetry.Inc("cover/invocations")
- telemetry.CountFlags("cover/flag:", *flag.CommandLine)
+ counter.Inc("cover/invocations")
+ counter.CountFlags("cover/flag:", *flag.CommandLine)
// Usage information when no arguments.
if flag.NFlag() == 0 && flag.NArg() == 0 {
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index 62f9693210230ad46a22cc277b1fcbc23e0ebc9e..9ca8fc539c43d448893e31f24f63a5e8bf45b67d 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -53,6 +53,7 @@ "cmd/internal/quoted",
"cmd/internal/src",
"cmd/internal/sys",
"cmd/internal/telemetry",
+ "cmd/internal/telemetry/counter",
"cmd/link",
"cmd/link/internal/...",
"compress/flate",
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index d7cbadf7b17aef6a15e6564e2287c618166462d5..0ffcabe4164af6ec05bbe701f5b49d16d6e77a8c 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -711,19 +711,6 @@ pkg: "crypto/x509",
})
}
- // GOEXPERIMENT=rangefunc tests
- if !t.compileOnly {
- for _, pkg := range []string{"iter", "slices", "maps"} {
- t.registerTest("GOEXPERIMENT=rangefunc",
- &goTest{
- variant: pkg,
- short: t.short,
- env: []string{"GOEXPERIMENT=rangefunc"},
- pkg: pkg,
- })
- }
- }
-
// GODEBUG=gcstoptheworld=2 tests. We only run these in long-test
// mode (with GO_TEST_SHORT=0) because this is just testing a
// non-critical debug setting.
diff --git a/src/cmd/distpack/pack.go b/src/cmd/distpack/pack.go
index 9ad33ee589cc8b45e20a96beaf03de4a6d50d7d2..552524936699f7b3ae34796e9b6ee49aa9563450 100644
--- a/src/cmd/distpack/pack.go
+++ b/src/cmd/distpack/pack.go
@@ -45,7 +45,7 @@ "runtime"
"strings"
"time"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
func usage() {
@@ -69,11 +69,11 @@
func main() {
log.SetPrefix("distpack: ")
log.SetFlags(0)
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = usage
flag.Parse()
- telemetry.Inc("distpack/invocations")
- telemetry.CountFlags("distpack/flag:", *flag.CommandLine)
+ counter.Inc("distpack/invocations")
+ counter.CountFlags("distpack/flag:", *flag.CommandLine)
if flag.NArg() != 0 {
usage()
}
diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go
index 4dbddcb79fcd217c65ccd1ab2253ae88a50998c2..502de097f50688e2326b35c0660327334c4fb4de 100644
--- a/src/cmd/doc/main.go
+++ b/src/cmd/doc/main.go
@@ -55,7 +55,7 @@ "path"
"path/filepath"
"strings"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
var (
@@ -87,7 +87,7 @@
func main() {
log.SetFlags(0)
log.SetPrefix("doc: ")
- telemetry.OpenCounters()
+ counter.Open()
dirsInit()
err := do(os.Stdout, flag.CommandLine, os.Args[1:])
if err != nil {
@@ -108,8 +108,8 @@ flagSet.BoolVar(&showCmd, "cmd", false, "show symbols with package docs even if package is a command")
flagSet.BoolVar(&showSrc, "src", false, "show source code for symbol")
flagSet.BoolVar(&short, "short", false, "one-line representation for each symbol")
flagSet.Parse(args)
- telemetry.Inc("doc/invocations")
- telemetry.CountFlags("doc/flag:", *flag.CommandLine)
+ counter.Inc("doc/invocations")
+ counter.CountFlags("doc/flag:", *flag.CommandLine)
if chdir != "" {
if err := os.Chdir(chdir); err != nil {
return err
diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go
index d915ece4ceb839e1570fac527e220ab26c8c95ed..6f1ff120da1057c8bfe59c5ee33e7f3c4721701a 100644
--- a/src/cmd/fix/main.go
+++ b/src/cmd/fix/main.go
@@ -22,7 +22,7 @@ "path/filepath"
"sort"
"strings"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
var (
@@ -65,11 +65,11 @@ os.Exit(2)
}
func main() {
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = usage
flag.Parse()
- telemetry.Inc("fix/invocations")
- telemetry.CountFlags("fix/flag:", *flag.CommandLine)
+ counter.Inc("fix/invocations")
+ counter.CountFlags("fix/flag:", *flag.CommandLine)
if !version.IsValid(*goVersion) {
report(fmt.Errorf("invalid -go=%s", *goVersion))
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index 559ffd1ccdc5b5d78f95cf78c1ab70a1a0f5a8ce..f568996fd0bb27e3d5d56f237afe5ddd0bbc6caa 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -6,10 +6,10 @@ require (
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba
golang.org/x/arch v0.8.0
golang.org/x/build v0.0.0-20240603162849-5dfbda438323
- golang.org/x/mod v0.18.0
+ golang.org/x/mod v0.19.0
golang.org/x/sync v0.7.0
- golang.org/x/sys v0.21.0
- golang.org/x/telemetry v0.0.0-20240612191826-8cad58b3fcbb
+ golang.org/x/sys v0.22.0
+ golang.org/x/telemetry v0.0.0-20240712210958-268b4a8ec2d7
golang.org/x/term v0.20.0
golang.org/x/tools v0.22.1-0.20240618181713-f2d2ebe43e72
)
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index 8f9517bc624754d183b8a1293a92940dada732c1..f822fa372ad2711d92e0f49a663437338e87e5c9 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -10,14 +10,14 @@ golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/build v0.0.0-20240603162849-5dfbda438323 h1:XHj9DzsjpryRW9MnyZq85mQ1dRpSxVC+2TLcMzVZNMo=
golang.org/x/build v0.0.0-20240603162849-5dfbda438323/go.mod h1:yz9anu0Z63yrVrqnoOxoJuyBRDwtGUoOFJwtfvs+D+U=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
+golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/telemetry v0.0.0-20240612191826-8cad58b3fcbb h1:0Ge50tvTqbHEyuQDgCYypgL2afqNjRNdl4GHPJuN9QY=
-golang.org/x/telemetry v0.0.0-20240612191826-8cad58b3fcbb/go.mod h1:n38mvGdgc4dA684EC4NwQwoPKSw4jyKw8/DgZHDA1Dk=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240712210958-268b4a8ec2d7 h1:nU8/tAV/21mkPrCjACUeSibjhynTovgRMXc32+Y1Aec=
+golang.org/x/telemetry v0.0.0-20240712210958-268b4a8ec2d7/go.mod h1:amNmu/SBSm2GAF3X+9U2C0epLocdh+r5Z+7oMYO5cLM=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 972f9e111f6db1e83e352bc289e5d084456361f5..75e6d65d0c98908696156cc607a44fc3d7a9077c 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -276,7 +276,7 @@ // # Remove object files and cached files
//
// Usage:
//
-// go clean [clean flags] [build flags] [packages]
+// go clean [-i] [-r] [-cache] [-testcache] [-modcache] [-fuzzcache] [build flags] [packages]
//
// Clean removes object files from package source directories.
// The go command builds most objects in a temporary directory,
@@ -1689,8 +1689,7 @@ // thing that go work use does.
//
// The -r flag searches recursively for modules in the argument
// directories, and the use command operates as if each of the directories
-// were specified as arguments: namely, use directives will be added for
-// directories that exist, and removed for directories that do not exist.
+// were specified as arguments.
//
// See the workspaces reference at https://go.dev/ref/mod#workspaces
// for more information.
@@ -1994,6 +1993,9 @@ // line comment that begins
//
// //go:build
//
+// Build constraints can also be used to downgrade the language version
+// used to compile a file.
+//
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
// only by blank lines and other comments. These rules mean that in Go
@@ -2115,6 +2117,10 @@ //
// Go versions 1.16 and earlier used a different syntax for build constraints,
// with a "// +build" prefix. The gofmt command will add an equivalent //go:build
// constraint when encountering the older syntax.
+//
+// In modules with a Go version of 1.21 or later, if a file's build constraint
+// has a term for a Go major release, the language version used when compiling
+// the file will be the minimum version implied by the build constraint.
//
// # Build modes
//
diff --git a/src/cmd/go/internal/clean/clean.go b/src/cmd/go/internal/clean/clean.go
index de2ef9dcb957bb8bf55cde1269c908c373d57abd..3b5924fe13d147d5073ea99763e08e9ebdced892 100644
--- a/src/cmd/go/internal/clean/clean.go
+++ b/src/cmd/go/internal/clean/clean.go
@@ -28,7 +28,7 @@ "cmd/go/internal/work"
)
var CmdClean = &base.Command{
- UsageLine: "go clean [clean flags] [build flags] [packages]",
+ UsageLine: "go clean [-i] [-r] [-cache] [-testcache] [-modcache] [-fuzzcache] [build flags] [packages]",
Short: "remove object files and cached files",
Long: `
Clean removes object files from package source directories.
diff --git a/src/cmd/go/internal/help/help.go b/src/cmd/go/internal/help/help.go
index 98382f2423ad15434b8c20b60fc67ec21a3b97c8..4f2607fef2b89f082f96f22b01346226d48ceb3c 100644
--- a/src/cmd/go/internal/help/help.go
+++ b/src/cmd/go/internal/help/help.go
@@ -16,10 +16,10 @@ "unicode"
"unicode/utf8"
"cmd/go/internal/base"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
-var counterErrorsHelpUnknownTopic = telemetry.NewCounter("go/errors:help-unknown-topic")
+var counterErrorsHelpUnknownTopic = counter.New("go/errors:help-unknown-topic")
// Help implements the 'help' command.
func Help(w io.Writer, args []string) {
diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
index 791013dbfeaa381c4a81071ddcd44373a4a32b87..29c0a56321a602dca7ce44bf077a26aadc15724c 100644
--- a/src/cmd/go/internal/help/helpdoc.go
+++ b/src/cmd/go/internal/help/helpdoc.go
@@ -835,6 +835,9 @@ line comment that begins
//go:build
+Build constraints can also be used to downgrade the language version
+used to compile a file.
+
Constraints may appear in any kind of source file (not just Go), but
they must appear near the top of the file, preceded
only by blank lines and other comments. These rules mean that in Go
@@ -954,5 +957,9 @@
Go versions 1.16 and earlier used a different syntax for build constraints,
with a "// +build" prefix. The gofmt command will add an equivalent //go:build
constraint when encountering the older syntax.
+
+In modules with a Go version of 1.21 or later, if a file's build constraint
+has a term for a Go major release, the language version used when compiling
+the file will be the minimum version implied by the build constraint.
`,
}
diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go
index 75b28b9bbc7f5d653eccd3ae0ba301e3197cc8db..02c4833a1b80100ecad6a8abc427bc3cb4fef235 100644
--- a/src/cmd/go/internal/modfetch/cache.go
+++ b/src/cmd/go/internal/modfetch/cache.go
@@ -26,7 +26,7 @@ "cmd/go/internal/lockedfile"
"cmd/go/internal/modfetch/codehost"
"cmd/go/internal/par"
"cmd/go/internal/robustio"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
@@ -779,7 +779,7 @@ var (
statCacheOnce sync.Once
statCacheErr error
- counterErrorsGOMODCACHEEntryRelative = telemetry.NewCounter("go/errors:gomodcache-entry-relative")
+ counterErrorsGOMODCACHEEntryRelative = counter.New("go/errors:gomodcache-entry-relative")
)
// checkCacheDir checks if the directory specified by GOMODCACHE exists. An
diff --git a/src/cmd/go/internal/telemetrystats/telemetrystats.go b/src/cmd/go/internal/telemetrystats/telemetrystats.go
index 610c4a22e85a73a56e7be4916b1d8ce6a871ba2d..950453fa9513746324d4bde210e8a29bc0426d06 100644
--- a/src/cmd/go/internal/telemetrystats/telemetrystats.go
+++ b/src/cmd/go/internal/telemetrystats/telemetrystats.go
@@ -10,7 +10,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/modload"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
func Increment() {
@@ -22,30 +22,30 @@ // incrementConfig increments counters for the configuration
// the command is running in.
func incrementConfig() {
if !modload.WillBeEnabled() {
- telemetry.Inc("go/mode:gopath")
+ counter.Inc("go/mode:gopath")
} else if workfile := modload.FindGoWork(base.Cwd()); workfile != "" {
- telemetry.Inc("go/mode:workspace")
+ counter.Inc("go/mode:workspace")
} else {
- telemetry.Inc("go/mode:module")
+ counter.Inc("go/mode:module")
}
- telemetry.Inc("go/platform/target/goos:" + cfg.Goos)
- telemetry.Inc("go/platform/target/goarch:" + cfg.Goarch)
+ counter.Inc("go/platform/target/goos:" + cfg.Goos)
+ counter.Inc("go/platform/target/goarch:" + cfg.Goarch)
switch cfg.Goarch {
case "386":
- telemetry.Inc("go/platform/target/go386:" + cfg.GO386)
+ counter.Inc("go/platform/target/go386:" + cfg.GO386)
case "amd64":
- telemetry.Inc("go/platform/target/goamd64:" + cfg.GOAMD64)
+ counter.Inc("go/platform/target/goamd64:" + cfg.GOAMD64)
case "arm":
- telemetry.Inc("go/platform/target/goarm:" + cfg.GOARM)
+ counter.Inc("go/platform/target/goarm:" + cfg.GOARM)
case "arm64":
- telemetry.Inc("go/platform/target/goarm64:" + cfg.GOARM64)
+ counter.Inc("go/platform/target/goarm64:" + cfg.GOARM64)
case "mips":
- telemetry.Inc("go/platform/target/gomips:" + cfg.GOMIPS)
+ counter.Inc("go/platform/target/gomips:" + cfg.GOMIPS)
case "ppc64":
- telemetry.Inc("go/platform/target/goppc64:" + cfg.GOPPC64)
+ counter.Inc("go/platform/target/goppc64:" + cfg.GOPPC64)
case "riscv64":
- telemetry.Inc("go/platform/target/goriscv64:" + cfg.GORISCV64)
+ counter.Inc("go/platform/target/goriscv64:" + cfg.GORISCV64)
case "wasm":
- telemetry.Inc("go/platform/target/gowasm:" + cfg.GOWASM)
+ counter.Inc("go/platform/target/gowasm:" + cfg.GOWASM)
}
}
diff --git a/src/cmd/go/internal/telemetrystats/version_other.go b/src/cmd/go/internal/telemetrystats/version_other.go
index b20294e2237f32fad5c1fb64601a6ed7120152ac..efce5fcf362985b2cd1863f53e6d497a882d5628 100644
--- a/src/cmd/go/internal/telemetrystats/version_other.go
+++ b/src/cmd/go/internal/telemetrystats/version_other.go
@@ -6,8 +6,8 @@ //go:build !cmd_go_bootstrap && !unix && !windows
package telemetrystats
-import "cmd/internal/telemetry"
+import "cmd/internal/telemetry/counter"
func incrementVersionCounters() {
- telemetry.Inc("go/platform:version-not-supported")
+ counter.Inc("go/platform:version-not-supported")
}
diff --git a/src/cmd/go/internal/telemetrystats/version_unix.go b/src/cmd/go/internal/telemetrystats/version_unix.go
index 08259b7c89655e8bbc8356311d2055d60b86bff1..517e7829b68ef4768d2dfaaafb4322cf36478437 100644
--- a/src/cmd/go/internal/telemetrystats/version_unix.go
+++ b/src/cmd/go/internal/telemetrystats/version_unix.go
@@ -12,7 +12,7 @@ "fmt"
"runtime"
"strings"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"golang.org/x/sys/unix"
)
@@ -29,7 +29,7 @@
var v unix.Utsname
err := unix.Uname(&v)
if err != nil {
- telemetry.Inc(fmt.Sprintf("go/platform/host/%s/version:unknown-uname-error", runtime.GOOS))
+ counter.Inc(fmt.Sprintf("go/platform/host/%s/version:unknown-uname-error", runtime.GOOS))
return
}
major, minor, ok := majorMinor(convert(v.Release[:]))
@@ -37,11 +37,11 @@ if runtime.GOOS == "aix" {
major, minor, ok = convert(v.Version[:]), convert(v.Release[:]), true
}
if !ok {
- telemetry.Inc(fmt.Sprintf("go/platform/host/%s/version:unknown-bad-format", runtime.GOOS))
+ counter.Inc(fmt.Sprintf("go/platform/host/%s/version:unknown-bad-format", runtime.GOOS))
return
}
- telemetry.Inc(fmt.Sprintf("go/platform/host/%s/major-version:%s", runtime.GOOS, major))
- telemetry.Inc(fmt.Sprintf("go/platform/host/%s/version:%s-%s", runtime.GOOS, major, minor))
+ counter.Inc(fmt.Sprintf("go/platform/host/%s/major-version:%s", runtime.GOOS, major))
+ counter.Inc(fmt.Sprintf("go/platform/host/%s/version:%s-%s", runtime.GOOS, major, minor))
}
func majorMinor(v string) (string, string, bool) {
diff --git a/src/cmd/go/internal/telemetrystats/version_windows.go b/src/cmd/go/internal/telemetrystats/version_windows.go
index e6a33e00cdc5685ae80121ce0016166f7c2ad8af..7de87193c67236223638240db64925370ce9fdcb 100644
--- a/src/cmd/go/internal/telemetrystats/version_windows.go
+++ b/src/cmd/go/internal/telemetrystats/version_windows.go
@@ -9,14 +9,14 @@
import (
"fmt"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"golang.org/x/sys/windows"
)
func incrementVersionCounters() {
v := windows.RtlGetVersion()
- telemetry.Inc(fmt.Sprintf("go/platform/host/windows/major-version:%d", v.MajorVersion))
- telemetry.Inc(fmt.Sprintf("go/platform/host/windows/version:%d-%d", v.MajorVersion, v.MinorVersion))
- telemetry.Inc(fmt.Sprintf("go/platform/host/windows/build:%d", v.BuildNumber))
+ counter.Inc(fmt.Sprintf("go/platform/host/windows/major-version:%d", v.MajorVersion))
+ counter.Inc(fmt.Sprintf("go/platform/host/windows/version:%d-%d", v.MajorVersion, v.MinorVersion))
+ counter.Inc(fmt.Sprintf("go/platform/host/windows/build:%d", v.BuildNumber))
}
diff --git a/src/cmd/go/internal/tool/tool.go b/src/cmd/go/internal/tool/tool.go
index da219f041cf548afe7aa105265a1a261eee29db3..77cee564b3d557f95907a5cb8ba1740b163ef1c7 100644
--- a/src/cmd/go/internal/tool/tool.go
+++ b/src/cmd/go/internal/tool/tool.go
@@ -6,7 +6,7 @@ // Package tool implements the “go tool” command.
package tool
import (
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"context"
"encoding/json"
"flag"
@@ -58,7 +58,7 @@ }
func runTool(ctx context.Context, cmd *base.Command, args []string) {
if len(args) == 0 {
- telemetry.Inc("go/subcommand:tool")
+ counter.Inc("go/subcommand:tool")
listTools()
return
}
@@ -86,17 +86,17 @@ // If the dist tool does not exist, impersonate this command.
if impersonateDistList(args[2:]) {
// If it becomes necessary, we could increment an additional counter to indicate
// that we're impersonating dist list if knowing that becomes important?
- telemetry.Inc("go/subcommand:tool-dist")
+ counter.Inc("go/subcommand:tool-dist")
return
}
}
- telemetry.Inc("go/subcommand:tool-unknown")
+ counter.Inc("go/subcommand:tool-unknown")
// Emit the usual error for the missing tool.
_ = base.Tool(toolName)
} else {
// Increment a counter for the tool subcommand with the tool name.
- telemetry.Inc("go/subcommand:tool-" + toolName)
+ counter.Inc("go/subcommand:tool-" + toolName)
}
if toolN {
diff --git a/src/cmd/go/internal/toolchain/select.go b/src/cmd/go/internal/toolchain/select.go
index d4787a844f07306a91a6f47842b6e6fd46a6e8aa..8e93e6c903308736fe5de01998da50936d8a1bbb 100644
--- a/src/cmd/go/internal/toolchain/select.go
+++ b/src/cmd/go/internal/toolchain/select.go
@@ -26,7 +26,7 @@ "cmd/go/internal/modfetch"
"cmd/go/internal/modload"
"cmd/go/internal/run"
"cmd/go/internal/work"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"golang.org/x/mod/module"
)
@@ -82,7 +82,7 @@ }
return out
}
-var counterErrorsInvalidToolchainInFile = telemetry.NewCounter("go/errors:invalid-toolchain-in-file")
+var counterErrorsInvalidToolchainInFile = counter.New("go/errors:invalid-toolchain-in-file")
// Select invokes a different Go toolchain if directed by
// the GOTOOLCHAIN environment variable or the user's configuration
@@ -253,7 +253,7 @@ counterSelectExec.Inc()
Exec(gotoolchain)
}
-var counterSelectExec = telemetry.NewCounter("go/toolchain/select-exec")
+var counterSelectExec = counter.New("go/toolchain/select-exec")
// TestVersionSwitch is set in the test go binary to the value in $TESTGO_VERSION_SWITCH.
// Valid settings are:
diff --git a/src/cmd/go/internal/toolchain/switch.go b/src/cmd/go/internal/toolchain/switch.go
index ba1e6973cf4186b542d53bfd7614bc49472d0c03..37c1bcdcbec6567734a033622ebe5589d93e54ac 100644
--- a/src/cmd/go/internal/toolchain/switch.go
+++ b/src/cmd/go/internal/toolchain/switch.go
@@ -16,7 +16,7 @@ "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/gover"
"cmd/go/internal/modfetch"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
// A Switcher collects errors to be reported and then decides
@@ -104,7 +104,7 @@ Exec(tv)
panic("unreachable")
}
-var counterSwitchExec = telemetry.NewCounter("go/toolchain/switch-exec")
+var counterSwitchExec = counter.New("go/toolchain/switch-exec")
// SwitchOrFatal attempts a toolchain switch based on the information in err
// and otherwise falls back to base.Fatal(err).
diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go
index 889cc6ca508ef706a9b1bec375562a2146af4bd6..4ee43e24369286264ef69f9a373f25edb1140ca2 100644
--- a/src/cmd/go/internal/work/buildid.go
+++ b/src/cmd/go/internal/work/buildid.go
@@ -19,7 +19,7 @@ "cmd/go/internal/fsys"
"cmd/go/internal/str"
"cmd/internal/buildid"
"cmd/internal/quoted"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
// Build IDs
@@ -406,11 +406,11 @@ return buildid.HashToString(sum)
}
var (
- counterCacheHit = telemetry.NewCounter("go/buildcache/hit")
- counterCacheMiss = telemetry.NewCounter("go/buildcache/miss")
+ counterCacheHit = counter.New("go/buildcache/hit")
+ counterCacheMiss = counter.New("go/buildcache/miss")
onceIncStdlibRecompiled sync.Once
- stdlibRecompiled = telemetry.NewCounter("go/buildcache/stdlib-recompiled")
+ stdlibRecompiled = counter.New("go/buildcache/stdlib-recompiled")
)
// useCache tries to satisfy the action a, which has action ID actionHash,
diff --git a/src/cmd/go/internal/workcmd/use.go b/src/cmd/go/internal/workcmd/use.go
index 55477119d4605cb2e1f99a52f0d0ae96e78089c9..0cdbed6b18b05d6f310f17637049296079733eb7 100644
--- a/src/cmd/go/internal/workcmd/use.go
+++ b/src/cmd/go/internal/workcmd/use.go
@@ -42,8 +42,7 @@ thing that go work use does.
The -r flag searches recursively for modules in the argument
directories, and the use command operates as if each of the directories
-were specified as arguments: namely, use directives will be added for
-directories that exist, and removed for directories that do not exist.
+were specified as arguments.
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index eb33df1ad4c9296534eb893486195fefcea2bb51..1c58232a6621b98564627751c9b6b8ec514bbd77 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -45,6 +45,7 @@ "cmd/go/internal/vet"
"cmd/go/internal/work"
"cmd/go/internal/workcmd"
"cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
func init() {
@@ -91,20 +92,20 @@ }
var _ = go11tag
-var counterErrorsGOPATHEntryRelative = telemetry.NewCounter("go/errors:gopath-entry-relative")
+var counterErrorsGOPATHEntryRelative = counter.New("go/errors:gopath-entry-relative")
func main() {
log.SetFlags(0)
- telemetry.MaybeChild() // Run in child mode if this is the telemetry sidecar child process.
- telemetry.OpenCounters() // Open the telemetry counter file so counters can be written to it.
+ telemetry.MaybeChild() // Run in child mode if this is the telemetry sidecar child process.
+ counter.Open() // Open the telemetry counter file so counters can be written to it.
handleChdirFlag()
toolchain.Select()
telemetry.MaybeParent() // Run the upload process. Opening the counter file is idempotent.
flag.Usage = base.Usage
flag.Parse()
- telemetry.Inc("go/invocations")
- telemetry.CountFlags("go/flag:", *flag.CommandLine)
+ counter.Inc("go/invocations")
+ counter.CountFlags("go/flag:", *flag.CommandLine)
args := flag.Args()
if len(args) < 1 {
@@ -113,7 +114,7 @@ }
cfg.CmdName = args[0] // for error messages
if args[0] == "help" {
- telemetry.Inc("go/subcommand:" + strings.Join(append([]string{"help"}, args[1:]...), "-"))
+ counter.Inc("go/subcommand:" + strings.Join(append([]string{"help"}, args[1:]...), "-"))
help.Help(os.Stdout, args[1:])
return
}
@@ -128,17 +129,17 @@ os.Exit(2)
}
switch strings.ToLower(cfg.GOROOT) {
case "/usr/local/go": // Location recommended for installation on Linux and Darwin and used by Mac installer.
- telemetry.Inc("go/goroot:usr-local-go")
+ counter.Inc("go/goroot:usr-local-go")
case "/usr/lib/go": // A typical location used by Linux package managers.
- telemetry.Inc("go/goroot:usr-lib-go")
+ counter.Inc("go/goroot:usr-lib-go")
case "/usr/lib/golang": // Another typical location used by Linux package managers.
- telemetry.Inc("go/goroot:usr-lib-golang")
+ counter.Inc("go/goroot:usr-lib-golang")
case `c:\program files\go`: // Location used by Windows installer.
- telemetry.Inc("go/goroot:program-files-go")
+ counter.Inc("go/goroot:program-files-go")
case `c:\program files (x86)\go`: // Location used by 386 Windows installer on amd64 platform.
- telemetry.Inc("go/goroot:program-files-x86-go")
+ counter.Inc("go/goroot:program-files-x86-go")
default:
- telemetry.Inc("go/goroot:other")
+ counter.Inc("go/goroot:other")
}
// Diagnose common mistake: GOPATH==GOROOT.
@@ -184,7 +185,7 @@ base.Exit()
}
if args[used] == "help" {
// Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'.
- telemetry.Inc("go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-") + "-" + strings.Join(args[used:], "-"))
+ counter.Inc("go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-") + "-" + strings.Join(args[used:], "-"))
help.Help(os.Stdout, append(slices.Clip(args[:used]), args[used+1:]...))
base.Exit()
}
@@ -196,7 +197,7 @@ cmdName := cfg.CmdName
if cmdName == "" {
cmdName = args[0]
}
- telemetry.Inc("go/subcommand:unknown")
+ counter.Inc("go/subcommand:unknown")
fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cmdName, helpArg)
base.SetExitStatus(2)
base.Exit()
@@ -206,7 +207,7 @@ // Don't increment the counter for the tool subcommand here: we'll
// increment in the tool subcommand's Run function because we need
// to do the flag processing in invoke first.
if cfg.CmdName != "tool" {
- telemetry.Inc("go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-"))
+ counter.Inc("go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-"))
}
telemetrystats.Increment()
invoke(cmd, args[used-1:])
@@ -274,8 +275,8 @@ } else {
base.SetFromGOFLAGS(&cmd.Flag)
cmd.Flag.Parse(args[1:])
flagCounterPrefix := "go/" + strings.ReplaceAll(cfg.CmdName, " ", "-") + "/flag"
- telemetry.CountFlags(flagCounterPrefix+":", cmd.Flag)
- telemetry.CountFlagValue(flagCounterPrefix+"/", cmd.Flag, "buildmode")
+ counter.CountFlags(flagCounterPrefix+":", cmd.Flag)
+ counter.CountFlagValue(flagCounterPrefix+"/", cmd.Flag, "buildmode")
args = cmd.Flag.Args()
}
@@ -361,7 +362,7 @@ case strings.HasPrefix(a, "-C="), strings.HasPrefix(a, "--C="):
_, dir, _ = strings.Cut(a, "=")
os.Args = slices.Delete(os.Args, used, used+1)
}
- telemetry.Inc("go/flag:C")
+ counter.Inc("go/flag:C")
if err := os.Chdir(dir); err != nil {
base.Fatalf("go: %v", err)
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index d6721f9327316d33aac605feea93451c235669db..d91a75b1050e2090e92bfbfec92e72edc61c7c99 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -25,7 +25,7 @@ "runtime/pprof"
"strconv"
"strings"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"golang.org/x/sync/semaphore"
)
@@ -374,11 +374,11 @@ os.Exit(s.GetExitCode())
}
func gofmtMain(s *sequencer) {
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = usage
flag.Parse()
- telemetry.Inc("gofmt/invocations")
- telemetry.CountFlags("gofmt/flag:", *flag.CommandLine)
+ counter.Inc("gofmt/invocations")
+ counter.CountFlags("gofmt/flag:", *flag.CommandLine)
if *cpuprofile != "" {
fdSem <- true
diff --git a/src/cmd/internal/obj/arm64/asm_arm64_test.go b/src/cmd/internal/obj/arm64/asm_arm64_test.go
index 068039496a23f6451d0a8306f5f8c03bee503601..83d137a08466bd2f66b0dd751b93bf5d7bc2f616 100644
--- a/src/cmd/internal/obj/arm64/asm_arm64_test.go
+++ b/src/cmd/internal/obj/arm64/asm_arm64_test.go
@@ -4,302 +4,7 @@ // license that can be found in the LICENSE file.
package arm64
-import (
- "bytes"
- "fmt"
- "internal/testenv"
- "os"
- "path/filepath"
- "regexp"
- "testing"
-)
-
-func TestSplitImm24uScaled(t *testing.T) {
- tests := []struct {
- v int32
- shift int
- wantErr bool
- wantHi int32
- wantLo int32
- }{
- {
- v: 0,
- shift: 0,
- wantHi: 0,
- wantLo: 0,
- },
- {
- v: 0x1001,
- shift: 0,
- wantHi: 0x1000,
- wantLo: 0x1,
- },
- {
- v: 0xffffff,
- shift: 0,
- wantHi: 0xfff000,
- wantLo: 0xfff,
- },
- {
- v: 0xffffff,
- shift: 1,
- wantErr: true,
- },
- {
- v: 0xfe,
- shift: 1,
- wantHi: 0x0,
- wantLo: 0x7f,
- },
- {
- v: 0x10fe,
- shift: 1,
- wantHi: 0x0,
- wantLo: 0x87f,
- },
- {
- v: 0x2002,
- shift: 1,
- wantHi: 0x2000,
- wantLo: 0x1,
- },
- {
- v: 0xfffffe,
- shift: 1,
- wantHi: 0xffe000,
- wantLo: 0xfff,
- },
- {
- v: 0x1000ffe,
- shift: 1,
- wantHi: 0xfff000,
- wantLo: 0xfff,
- },
- {
- v: 0x1001000,
- shift: 1,
- wantErr: true,
- },
- {
- v: 0xfffffe,
- shift: 2,
- wantErr: true,
- },
- {
- v: 0x4004,
- shift: 2,
- wantHi: 0x4000,
- wantLo: 0x1,
- },
- {
- v: 0xfffffc,
- shift: 2,
- wantHi: 0xffc000,
- wantLo: 0xfff,
- },
- {
- v: 0x1002ffc,
- shift: 2,
- wantHi: 0xfff000,
- wantLo: 0xfff,
- },
- {
- v: 0x1003000,
- shift: 2,
- wantErr: true,
- },
- {
- v: 0xfffffe,
- shift: 3,
- wantErr: true,
- },
- {
- v: 0x8008,
- shift: 3,
- wantHi: 0x8000,
- wantLo: 0x1,
- },
- {
- v: 0xfffff8,
- shift: 3,
- wantHi: 0xff8000,
- wantLo: 0xfff,
- },
- {
- v: 0x1006ff8,
- shift: 3,
- wantHi: 0xfff000,
- wantLo: 0xfff,
- },
- {
- v: 0x1007000,
- shift: 3,
- wantErr: true,
- },
- }
- for _, test := range tests {
- hi, lo, err := splitImm24uScaled(test.v, test.shift)
- switch {
- case err == nil && test.wantErr:
- t.Errorf("splitImm24uScaled(%v, %v) succeeded, want error", test.v, test.shift)
- case err != nil && !test.wantErr:
- t.Errorf("splitImm24uScaled(%v, %v) failed: %v", test.v, test.shift, err)
- case !test.wantErr:
- if got, want := hi, test.wantHi; got != want {
- t.Errorf("splitImm24uScaled(%x, %x) - got hi %x, want %x", test.v, test.shift, got, want)
- }
- if got, want := lo, test.wantLo; got != want {
- t.Errorf("splitImm24uScaled(%x, %x) - got lo %x, want %x", test.v, test.shift, got, want)
- }
- }
- }
- for shift := 0; shift <= 3; shift++ {
- for v := int32(0); v < 0xfff000+0xfff< 0 {
// dump symbol info on crash
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 8cfecafe84ab6c576a3cdc9470f0fabfcdbdf5b7..14f04855305a401e6c6e2f1a88533d7d57de961c 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -1548,8 +1548,21 @@
// sort the pages array
sort.Sort(rt.pages)
+ // .reloc section must be 32-bit aligned
+ if out.Offset()&3 != 0 {
+ Errorf(nil, "internal error, start of .reloc not 32-bit aligned")
+ }
+
for _, p := range rt.pages {
b := rt.blocks[p]
+
+ // Add a dummy entry at the end of the list if we have an
+ // odd number of entries, so as to ensure that the next
+ // block starts on a 32-bit boundary (see issue 68260).
+ if len(b.entries)&1 != 0 {
+ b.entries = append(b.entries, peBaseRelocEntry{})
+ }
+
const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32)
blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
out.Write32(p)
diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go
index e0d98d5f6c67d015e331e9df9ce830675abeb46a..752870654d5ccd1c57a3ab178e921904fc4b14cb 100644
--- a/src/cmd/nm/nm.go
+++ b/src/cmd/nm/nm.go
@@ -13,7 +13,7 @@ "os"
"sort"
"cmd/internal/objfile"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
const helpText = `usage: go tool nm [options] file...
@@ -68,11 +68,11 @@ }
func main() {
log.SetFlags(0)
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = usage
flag.Parse()
- telemetry.Inc("nm/invocations")
- telemetry.CountFlags("nm/flag:", *flag.CommandLine)
+ counter.Inc("nm/invocations")
+ counter.CountFlags("nm/flag:", *flag.CommandLine)
switch *sortOrder {
case "address", "name", "none", "size":
diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go
index 7554b5500c1216604e6402c05200b6074aa5fa9a..b5b0d7f5178d5bf4aa13ba81c7a29ae25a222640 100644
--- a/src/cmd/objdump/main.go
+++ b/src/cmd/objdump/main.go
@@ -41,7 +41,7 @@ "strconv"
"strings"
"cmd/internal/objfile"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
)
var printCode = flag.Bool("S", false, "print Go code alongside assembly")
@@ -58,12 +58,12 @@
func main() {
log.SetFlags(0)
log.SetPrefix("objdump: ")
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = usage
flag.Parse()
- telemetry.Inc("objdump/invocations")
- telemetry.CountFlags("objdump/flag:", *flag.CommandLine)
+ counter.Inc("objdump/invocations")
+ counter.CountFlags("objdump/flag:", *flag.CommandLine)
if flag.NArg() != 1 && flag.NArg() != 3 {
usage()
}
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
index 28f217ace1b57ee0006a1299077619f45a8c4546..4ac6ce995fe9185ff8b20065e28e34bfe6ca2237 100644
--- a/src/cmd/pack/pack.go
+++ b/src/cmd/pack/pack.go
@@ -6,7 +6,7 @@ package main
import (
"cmd/internal/archive"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"fmt"
"io"
"io/fs"
@@ -31,7 +31,7 @@
func main() {
log.SetFlags(0)
log.SetPrefix("pack: ")
- telemetry.OpenCounters()
+ counter.Open()
// need "pack op archive" at least.
if len(os.Args) < 3 {
log.Print("not enough arguments")
@@ -39,8 +39,8 @@ fmt.Fprintln(os.Stderr)
usage()
}
setOp(os.Args[1])
- telemetry.Inc("pack/invocations")
- telemetry.Inc("pack/op:" + string(op))
+ counter.Inc("pack/invocations")
+ counter.Inc("pack/op:" + string(op))
var ar *Archive
switch op {
case 'p':
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 722b745287eec1ffe1560ef3acd93c4fd61f5e31..a1c2cd210f8dbaf2c3d4d49739af962e6793120f 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -25,22 +25,22 @@ "sync"
"time"
"cmd/internal/objfile"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"github.com/google/pprof/driver"
"github.com/google/pprof/profile"
)
func main() {
- telemetry.OpenCounters()
- telemetry.Inc("pprof/invocations")
+ counter.Open()
+ counter.Inc("pprof/invocations")
options := &driver.Options{
Fetch: new(fetcher),
Obj: new(objTool),
UI: newUI(),
}
err := driver.PProf(options)
- telemetry.CountFlags("pprof/flag:", *flag.CommandLine) // pprof will use the flag package as its default
+ counter.CountFlags("pprof/flag:", *flag.CommandLine) // pprof will use the flag package as its default
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(2)
diff --git a/src/cmd/preprofile/main.go b/src/cmd/preprofile/main.go
index 1260eed10471ee8044c2420ce42f3730650eb2c7..60aa1f7cc6cdd66ea11816bc4439e5018c220c84 100644
--- a/src/cmd/preprofile/main.go
+++ b/src/cmd/preprofile/main.go
@@ -18,7 +18,7 @@ import (
"bufio"
"cmd/internal/objabi"
"cmd/internal/pgo"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"flag"
"fmt"
"log"
@@ -73,12 +73,12 @@ objabi.AddVersionFlag()
log.SetFlags(0)
log.SetPrefix("preprofile: ")
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = usage
flag.Parse()
- telemetry.Inc("preprofile/invocations")
- telemetry.CountFlags("preprofile/flag:", *flag.CommandLine)
+ counter.Inc("preprofile/invocations")
+ counter.CountFlags("preprofile/flag:", *flag.CommandLine)
if *input == "" {
log.Print("Input pprof path required (-i)")
usage()
diff --git a/src/cmd/test2json/main.go b/src/cmd/test2json/main.go
index 844ee5aa6c6cc13c47600c9f758e37e06f9627bc..b704dd4d31a5e537821e9a956963e5473de7a08f 100644
--- a/src/cmd/test2json/main.go
+++ b/src/cmd/test2json/main.go
@@ -96,7 +96,7 @@ "os"
"os/exec"
"os/signal"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"cmd/internal/test2json"
)
@@ -116,12 +116,12 @@ signal.Ignore(signalsToIgnore...)
}
func main() {
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = usage
flag.Parse()
- telemetry.Inc("test2json/invocations")
- telemetry.CountFlags("test2json/flag:", *flag.CommandLine)
+ counter.Inc("test2json/invocations")
+ counter.CountFlags("test2json/flag:", *flag.CommandLine)
var mode test2json.Mode
if *flagT {
diff --git a/src/cmd/trace/gstate.go b/src/cmd/trace/gstate.go
index bcbe3b6c7faff1b38772a74bfed9f7b63bdc8e78..638d492670a6e74cfe3945db9b77eb002bd49caa 100644
--- a/src/cmd/trace/gstate.go
+++ b/src/cmd/trace/gstate.go
@@ -46,7 +46,7 @@ // completedRanges is a list of ranges that completed since before the
// goroutine stopped executing. These are flushed on every stop or block.
completedRanges []completedRange
- // startRunning is the most recent event that caused a goroutine to
+ // startRunningTime is the most recent event that caused a goroutine to
// transition to GoRunning.
startRunningTime trace.Time
diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go
index e48048b9f257caa3cc39ff48850be9ab55192efc..d51ee5816456bf9a1e120e653b987b17e9f9bda8 100644
--- a/src/cmd/trace/main.go
+++ b/src/cmd/trace/main.go
@@ -6,7 +6,7 @@ package main
import (
"cmd/internal/browser"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"flag"
"fmt"
"internal/trace"
@@ -64,14 +64,14 @@ traceFile string
)
func main() {
- telemetry.OpenCounters()
+ counter.Open()
flag.Usage = func() {
fmt.Fprint(os.Stderr, usageMessage)
os.Exit(2)
}
flag.Parse()
- telemetry.Inc("trace/invocations")
- telemetry.CountFlags("trace/flag:", *flag.CommandLine)
+ counter.Inc("trace/invocations")
+ counter.CountFlags("trace/flag:", *flag.CommandLine)
// Go 1.7 traces embed symbol info and does not require the binary.
// But we optionally accept binary as first arg for Go 1.5 traces.
diff --git a/src/cmd/vendor/golang.org/x/mod/module/module.go b/src/cmd/vendor/golang.org/x/mod/module/module.go
index cac1a899e9c3600db61dee3f497704d10ea6f86b..2a364b229b9f950d4f471f8748b05ca700d3ff50 100644
--- a/src/cmd/vendor/golang.org/x/mod/module/module.go
+++ b/src/cmd/vendor/golang.org/x/mod/module/module.go
@@ -506,7 +506,6 @@ "CON",
"PRN",
"AUX",
"NUL",
- "COM0",
"COM1",
"COM2",
"COM3",
@@ -516,7 +515,6 @@ "COM6",
"COM7",
"COM8",
"COM9",
- "LPT0",
"LPT1",
"LPT2",
"LPT3",
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/client.go b/src/cmd/vendor/golang.org/x/mod/sumdb/client.go
index 04c6e24d0e06ffc5b95f535acf6a2b5ebbbe7f64..04dbdfe46afdc48f77e40a4dd511666ebd82794e 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/client.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/client.go
@@ -142,6 +142,14 @@ }
c.verifiers = note.VerifierList(verifier)
c.name = verifier.Name()
+ if c.latest.N == 0 {
+ c.latest.Hash, err = tlog.TreeHash(0, nil)
+ if err != nil {
+ c.initErr = err
+ return
+ }
+ }
+
data, err := c.ops.ReadConfig(c.name + "/latest")
if err != nil {
c.initErr = err
diff --git a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go
index 6a11a752f909c79508d4abb628bd0e696874a792..f7ea75383208a0820e7b1922edc3f7a21d6c2270 100644
--- a/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go
+++ b/src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go
@@ -234,14 +234,22 @@ func (f HashReaderFunc) ReadHashes(indexes []int64) ([]Hash, error) {
return f(indexes)
}
+// emptyHash is the hash of the empty tree, per RFC 6962, Section 2.1.
+// It is the hash of the empty string.
+var emptyHash = Hash{
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
+ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
+ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+}
+
// TreeHash computes the hash for the root of the tree with n records,
// using the HashReader to obtain previously stored hashes
// (those returned by StoredHashes during the writes of those n records).
// TreeHash makes a single call to ReadHash requesting at most 1 + log₂ n hashes.
-// The tree of size zero is defined to have an all-zero Hash.
func TreeHash(n int64, r HashReader) (Hash, error) {
if n == 0 {
- return Hash{}, nil
+ return emptyHash, nil
}
indexes := subTreeIndex(0, n, nil)
hashes, err := r.ReadHashes(indexes)
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/mremap.go b/src/cmd/vendor/golang.org/x/sys/unix/mremap.go
index fd45fe529da517e2ebd898a823534034936687bb..3a5e776f895aae7aa0cf30d25e515705080090b6 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/mremap.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/mremap.go
@@ -50,3 +50,8 @@
func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) {
return mapper.Mremap(oldData, newLength, flags)
}
+
+func MremapPtr(oldAddr unsafe.Pointer, oldSize uintptr, newAddr unsafe.Pointer, newSize uintptr, flags int) (ret unsafe.Pointer, err error) {
+ xaddr, err := mapper.mremap(uintptr(oldAddr), oldSize, newSize, flags, uintptr(newAddr))
+ return unsafe.Pointer(xaddr), err
+}
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.go
index 59542a897d236606075760f33aa41563d692280b..4cc7b005967ebd06f8078ec3d196c042edef1f94 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.go
@@ -542,6 +542,18 @@ return buf[:n/SizeofKinfoProc], nil
}
}
+//sys pthread_chdir_np(path string) (err error)
+
+func PthreadChdir(path string) (err error) {
+ return pthread_chdir_np(path)
+}
+
+//sys pthread_fchdir_np(fd int) (err error)
+
+func PthreadFchdir(fd int) (err error) {
+ return pthread_fchdir_np(fd)
+}
+
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error)
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_unix.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_unix.go
index 77081de8c7de75ac729814dff15aee9a64760c3a..4e92e5aa40628b3a913cbf6f55f9429ef9e7b08e 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_unix.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_unix.go
@@ -154,6 +154,15 @@ func Munmap(b []byte) (err error) {
return mapper.Munmap(b)
}
+func MmapPtr(fd int, offset int64, addr unsafe.Pointer, length uintptr, prot int, flags int) (ret unsafe.Pointer, err error) {
+ xaddr, err := mapper.mmap(uintptr(addr), length, prot, flags, fd, offset)
+ return unsafe.Pointer(xaddr), err
+}
+
+func MunmapPtr(addr unsafe.Pointer, length uintptr) (err error) {
+ return mapper.munmap(uintptr(addr), length)
+}
+
func Read(fd int, p []byte) (n int, err error) {
n, err = read(fd, p)
if raceenabled {
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
index ccb02f240a4f7346d18174d089654b1a556dd025..07642c308d3aa87af51068b91ab4f58c213d5cee 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
@@ -760,6 +760,39 @@ //go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func pthread_chdir_np(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall_syscall(libc_pthread_chdir_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_pthread_chdir_np_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_pthread_chdir_np pthread_chdir_np "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pthread_fchdir_np(fd int) (err error) {
+ _, _, e1 := syscall_syscall(libc_pthread_fchdir_np_trampoline_addr, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_pthread_fchdir_np_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_pthread_fchdir_np pthread_fchdir_np "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) {
_, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags))
if e1 != 0 {
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
index 8b8bb28402857d5abab344ba0e220238e0864630..923e08cb7924cf8aaca4d31a8ab3708e61510e6d 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
@@ -228,6 +228,16 @@ JMP libc_sysctl(SB)
GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8
DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB)
+TEXT libc_pthread_chdir_np_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_pthread_chdir_np(SB)
+GLOBL ·libc_pthread_chdir_np_trampoline_addr(SB), RODATA, $8
+DATA ·libc_pthread_chdir_np_trampoline_addr(SB)/8, $libc_pthread_chdir_np_trampoline<>(SB)
+
+TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_pthread_fchdir_np(SB)
+GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8
+DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB)
+
TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_sendfile(SB)
GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
index 1b40b997b5260f6f0a1e5082a227db34c9a58d91..7d73dda64733ccdfced79148a1c5d4db3037d877 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
@@ -760,6 +760,39 @@ //go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func pthread_chdir_np(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall_syscall(libc_pthread_chdir_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_pthread_chdir_np_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_pthread_chdir_np pthread_chdir_np "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pthread_fchdir_np(fd int) (err error) {
+ _, _, e1 := syscall_syscall(libc_pthread_fchdir_np_trampoline_addr, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_pthread_fchdir_np_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_pthread_fchdir_np pthread_fchdir_np "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) {
_, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags))
if e1 != 0 {
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
index 08362c1ab747252ee6de46091413b1815842f50c..057700111e74658d543c58c4d1aff1dbef6da5ac 100644
--- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
+++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
@@ -228,6 +228,16 @@ JMP libc_sysctl(SB)
GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8
DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB)
+TEXT libc_pthread_chdir_np_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_pthread_chdir_np(SB)
+GLOBL ·libc_pthread_chdir_np_trampoline_addr(SB), RODATA, $8
+DATA ·libc_pthread_chdir_np_trampoline_addr(SB)/8, $libc_pthread_chdir_np_trampoline<>(SB)
+
+TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_pthread_fchdir_np(SB)
+GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8
+DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB)
+
TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_sendfile(SB)
GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8
diff --git a/src/cmd/vendor/golang.org/x/sys/windows/security_windows.go b/src/cmd/vendor/golang.org/x/sys/windows/security_windows.go
index 6f7d2ac70a93dacf47181cbd2d1f61851bc79701..97651b5bd04bfa850b4df3cd670b643249d10e33 100644
--- a/src/cmd/vendor/golang.org/x/sys/windows/security_windows.go
+++ b/src/cmd/vendor/golang.org/x/sys/windows/security_windows.go
@@ -894,7 +894,7 @@ type ACL struct {
aclRevision byte
sbz1 byte
aclSize uint16
- aceCount uint16
+ AceCount uint16
sbz2 uint16
}
@@ -1087,6 +1087,27 @@ Inheritance uint32
Trustee TRUSTEE
}
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
+type ACE_HEADER struct {
+ AceType uint8
+ AceFlags uint8
+ AceSize uint16
+}
+
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-access_allowed_ace
+type ACCESS_ALLOWED_ACE struct {
+ Header ACE_HEADER
+ Mask ACCESS_MASK
+ SidStart uint32
+}
+
+const (
+ // Constants for AceType
+ // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
+ ACCESS_ALLOWED_ACE_TYPE = 0
+ ACCESS_DENIED_ACE_TYPE = 1
+)
+
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
type TrusteeValue uintptr
@@ -1158,6 +1179,7 @@ //sys makeAbsoluteSD(selfRelativeSD *SECURITY_DESCRIPTOR, absoluteSD *SECURITY_DESCRIPTOR, absoluteSDSize *uint32, dacl *ACL, daclSize *uint32, sacl *ACL, saclSize *uint32, owner *SID, ownerSize *uint32, group *SID, groupSize *uint32) (err error) = advapi32.MakeAbsoluteSD
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD
//sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW
+//sys GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (ret error) = advapi32.GetAce
// Control returns the security descriptor control bits.
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
diff --git a/src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index 9f73df75b5fe4e330fc35630a49f6473051903ec..eba761018aafe82957b5a91925c986aa8f39c72d 100644
--- a/src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -91,6 +91,7 @@ procEnumDependentServicesW = modadvapi32.NewProc("EnumDependentServicesW")
procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW")
procEqualSid = modadvapi32.NewProc("EqualSid")
procFreeSid = modadvapi32.NewProc("FreeSid")
+ procGetAce = modadvapi32.NewProc("GetAce")
procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
procGetNamedSecurityInfoW = modadvapi32.NewProc("GetNamedSecurityInfoW")
procGetSecurityDescriptorControl = modadvapi32.NewProc("GetSecurityDescriptorControl")
@@ -1220,6 +1221,14 @@ func setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) {
r0, _, _ := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(countExplicitEntries), uintptr(unsafe.Pointer(explicitEntries)), uintptr(unsafe.Pointer(oldACL)), uintptr(unsafe.Pointer(newACL)), 0, 0)
if r0 != 0 {
ret = syscall.Errno(r0)
+ }
+ return
+}
+
+func GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (ret error) {
+ r0, _, _ := syscall.Syscall(procGetAce.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(aceIndex), uintptr(unsafe.Pointer(pAce)))
+ if r0 == 0 {
+ ret = GetLastError()
}
return
}
diff --git a/src/cmd/vendor/golang.org/x/telemetry/counter/counter.go b/src/cmd/vendor/golang.org/x/telemetry/counter/counter.go
index ba1c68889e1ec0ea35e05f37f4235fb10aa863cf..ff727ad97ce5083d98d9a679a54c8623eb1049f7 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/counter/counter.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/counter/counter.go
@@ -15,6 +15,7 @@ "path"
"runtime/debug"
"golang.org/x/telemetry/internal/counter"
+ "golang.org/x/telemetry/internal/telemetry"
)
// Inc increments the counter with the given name.
@@ -82,9 +83,20 @@ //
// If the telemetry mode is "off", Open is a no-op. Otherwise, it opens the
// counter file on disk and starts to mmap telemetry counters to the file.
// Open also persists any counters already created in the current process.
+func Open() {
+ counter.Open()
+}
+
+// OpenDir prepares telemetry counters for recording to the file system, using
+// the specified telemetry directory, if it is not the empty string.
//
-// Programs using telemetry should call Open exactly once.
-func Open() {
+// If the telemetry mode is "off", Open is a no-op. Otherwise, it opens the
+// counter file on disk and starts to mmap telemetry counters to the file.
+// Open also persists any counters already created in the current process.
+func OpenDir(telemetryDir string) {
+ if telemetryDir != "" {
+ telemetry.Default = telemetry.NewDir(telemetryDir)
+ }
counter.Open()
}
diff --git a/src/cmd/vendor/golang.org/x/telemetry/counter/doc.go b/src/cmd/vendor/golang.org/x/telemetry/counter/doc.go
index 53695ac270109b9260fe22fed09c376fc9b331d4..639e9ea3568b65294703e0921e980761e2fbfcd3 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/counter/doc.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/counter/doc.go
@@ -48,4 +48,11 @@ // - Histograms should use bucket names identifying upper bounds with '<'.
// For example given two counters "gopls/completion/latency:<50ms" and
// "gopls/completion/latency:<100ms", the "<100ms" bucket counts events
// with latency in the half-open interval [50ms, 100ms).
+//
+// # Debugging
+//
+// The GODEBUG environment variable can enable printing of additional debug
+// information for counters. Adding GODEBUG=countertrace=1 to the environment
+// of a process using counters causes the x/telemetry/counter package to log
+// counter information to stderr.
package counter
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/counter/counter.go b/src/cmd/vendor/golang.org/x/telemetry/internal/counter/counter.go
index cc562bc74426030eadf68d572f329297d799e895..6fbcec3a926febe3bc19d9718452deeaf102f170 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/counter/counter.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/counter/counter.go
@@ -15,15 +15,31 @@ "strings"
"sync/atomic"
)
-// Note: not using internal/godebug, so that internal/godebug can use internal/counter.
-var debugCounter = strings.Contains(os.Getenv("GODEBUG"), "countertrace=1")
+var (
+ // Note: not using internal/godebug, so that internal/godebug can use
+ // internal/counter.
+ debugCounter = strings.Contains(os.Getenv("GODEBUG"), "countertrace=1")
+ CrashOnBugs = false // for testing; if set, exit on fatal log messages
+)
-func debugPrintf(format string, args ...interface{}) {
+// debugPrintf formats a debug message if GODEBUG=countertrace=1.
+func debugPrintf(format string, args ...any) {
if debugCounter {
if len(format) == 0 || format[len(format)-1] != '\n' {
format += "\n"
}
fmt.Fprintf(os.Stderr, "counter: "+format, args...)
+ }
+}
+
+// debugFatalf logs a fatal error if GODEBUG=countertrace=1.
+func debugFatalf(format string, args ...any) {
+ if debugCounter || CrashOnBugs {
+ if len(format) == 0 || format[len(format)-1] != '\n' {
+ format += "\n"
+ }
+ fmt.Fprintf(os.Stderr, "counter bug: "+format, args...)
+ os.Exit(1)
}
}
@@ -246,6 +262,7 @@ return
}
}
+// add wraps the atomic.Uint64.Add operation to handle integer overflow.
func (c *Counter) add(n uint64) uint64 {
count := c.ptr.count
for {
@@ -336,11 +353,11 @@ return pf, nil
}
// ReadFile reads the counters and stack counters from the given file.
-// This is the implementation of x/telemetry/counter/countertest.Read
+// This is the implementation of x/telemetry/counter/countertest.ReadFile.
func ReadFile(name string) (counters, stackCounters map[string]uint64, _ error) {
// TODO: Document the format of the stackCounters names.
- data, err := os.ReadFile(name)
+ data, err := ReadMapped(name)
if err != nil {
return nil, nil, fmt.Errorf("failed to read from file: %v", err)
}
@@ -359,3 +376,26 @@ }
}
return counters, stackCounters, nil
}
+
+// ReadMapped reads the contents of the given file by memory mapping.
+//
+// This avoids file synchronization issues.
+func ReadMapped(name string) ([]byte, error) {
+ f, err := os.OpenFile(name, os.O_RDWR, 0666)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ mapping, err := memmap(f)
+ if err != nil {
+ return nil, err
+ }
+ data := make([]byte, fi.Size())
+ copy(data, mapping.Data)
+ munmap(mapping)
+ return data, nil
+}
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/counter/file.go b/src/cmd/vendor/golang.org/x/telemetry/internal/counter/file.go
index 0cb6cc22de3095b8547800560864e9e1c2e5e939..4fe9e577b17d5f8b099ae80254ac7bfcd58ee191 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/counter/file.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/counter/file.go
@@ -36,7 +36,22 @@ mu sync.Mutex
buildInfo *debug.BuildInfo
timeBegin, timeEnd time.Time
err error
- current atomic.Pointer[mappedFile] // may be read without holding mu, but may be nil
+ // current holds the current file mapping, which may change when the file is
+ // rotated or extended.
+ //
+ // current may be read without holding mu, but may be nil.
+ //
+ // The cleanup logic for file mappings is complicated, because invalidating
+ // counter pointers is reentrant: [file.invalidateCounters] may call
+ // [file.lookup], which acquires mu. Therefore, writing current must be done
+ // as follows:
+ // 1. record the previous value of current
+ // 2. Store a new value in current
+ // 3. unlock mu
+ // 4. call invalidateCounters
+ // 5. close the previous mapped value from (1)
+ // TODO(rfindley): simplify
+ current atomic.Pointer[mappedFile]
}
var defaultFile file
@@ -292,7 +307,7 @@ return time.Time{}
}
name := filepath.Join(dir, baseName)
- m, err := openMapped(name, meta, nil)
+ m, err := openMapped(name, meta)
if err != nil {
// Mapping failed:
// If there used to be a mapped file, after cleanup
@@ -334,11 +349,15 @@
cleanup = nop
if newM != nil {
f.current.Store(newM)
- // TODO(rfindley): shouldn't this close f.current?
- cleanup = f.invalidateCounters
+ cleanup = func() {
+ f.invalidateCounters()
+ current.close()
+ }
}
return v, cleanup
}
+
+var openOnce sync.Once
// Open associates counting with the defaultFile.
// The returned function is for testing only, and should
@@ -349,25 +368,61 @@ func Open() func() {
if telemetry.DisabledOnPlatform {
return func() {}
}
- if mode, _ := telemetry.Default.Mode(); mode == "off" {
- // Don't open the file when telemetry is off.
- defaultFile.err = ErrDisabled
- return func() {} // No need to clean up.
- }
- debugPrintf("Open")
- defaultFile.rotate()
- return func() {
- // Once this has been called, the defaultFile is no longer usable.
- mf := defaultFile.current.Load()
- if mf == nil {
- // telemetry might have been off
+ close := func() {}
+ openOnce.Do(func() {
+ if mode, _ := telemetry.Default.Mode(); mode == "off" {
+ // Don't open the file when telemetry is off.
+ defaultFile.err = ErrDisabled
+ // No need to clean up.
return
}
- mf.close()
- }
+ debugPrintf("Open")
+ defaultFile.rotate()
+ close = func() {
+ // Once this has been called, the defaultFile is no longer usable.
+ mf := defaultFile.current.Load()
+ if mf == nil {
+ // telemetry might have been off
+ return
+ }
+ mf.close()
+ }
+ })
+ return close
}
+const (
+ FileVersion = "v1"
+ hdrPrefix = "# telemetry/counter file " + FileVersion + "\n"
+ recordUnit = 32
+ maxMetaLen = 512
+ numHash = 512 // 2kB for hash table
+ maxNameLen = 4 * 1024
+ limitOff = 0
+ hashOff = 4
+ pageSize = 16 * 1024
+ minFileLen = 16 * 1024
+)
+
// A mappedFile is a counter file mmapped into memory.
+//
+// The file layout for a mappedFile m is as follows:
+//
+// offset, byte size: description
+// ------------------ -----------
+// 0, hdrLen: header, containing metadata; see [mappedHeader]
+// hdrLen+limitOff, 4: uint32 allocation limit (byte offset of the end of counter records)
+// hdrLen+hashOff, 4*numHash: hash table, stores uint32 heads of a linked list of records, keyed by name hash
+// hdrLen+hashOff+4*numHash to limit: counter records: see record syntax below
+//
+// The record layout is as follows:
+//
+// offset, byte size: description
+// ------------------ -----------
+// 0, 8: uint64 counter value
+// 8, 12: uint32 name length
+// 12, 16: uint32 offset of next record in linked list
+// 16, name length: counter name
type mappedFile struct {
meta string
hdrLen uint32
@@ -377,9 +432,16 @@ f *os.File
mapping *mmap.Data
}
+// openMapped opens and memory maps a file.
+//
+// name is the path to the file.
+//
+// meta is the file metadata, which must match the metadata of the file on disk
+// exactly.
+//
// existing should be nil the first time this is called for a file,
// and when remapping, should be the previous mappedFile.
-func openMapped(name string, meta string, existing *mappedFile) (_ *mappedFile, err error) {
+func openMapped(name, meta string) (_ *mappedFile, err error) {
hdr, err := mappedHeader(meta)
if err != nil {
return nil, err
@@ -395,13 +457,13 @@ m := &mappedFile{
f: f,
meta: meta,
}
- // without this files cannot be cleanedup on Windows (affects tests)
- runtime.SetFinalizer(m, (*mappedFile).close)
+
defer func() {
if err != nil {
m.close()
}
}()
+
info, err := f.Stat()
if err != nil {
return nil, err
@@ -426,17 +488,14 @@ }
}
// Map into memory.
- var mapping mmap.Data
- if existing != nil {
- mapping, err = memmap(f, existing.mapping)
- } else {
- mapping, err = memmap(f, nil)
- }
+ mapping, err := memmap(f)
if err != nil {
return nil, err
}
- m.mapping = &mapping
+ m.mapping = mapping
if !bytes.HasPrefix(m.mapping.Data, hdr) {
+ // TODO(rfindley): we can and should do better here, reading the mapped
+ // header length and comparing headers exactly.
return nil, fmt.Errorf("counter: header mismatch")
}
m.hdrLen = uint32(len(hdr))
@@ -444,19 +503,6 @@
return m, nil
}
-const (
- FileVersion = "v1"
- hdrPrefix = "# telemetry/counter file " + FileVersion + "\n"
- recordUnit = 32
- maxMetaLen = 512
- numHash = 512 // 2kB for hash table
- maxNameLen = 4 * 1024
- limitOff = 0
- hashOff = 4
- pageSize = 16 * 1024
- minFileLen = 16 * 1024
-)
-
func mappedHeader(meta string) ([]byte, error) {
if len(meta) > maxMetaLen {
return nil, fmt.Errorf("counter: metadata too large")
@@ -477,6 +523,11 @@ limit = m.hdrLen + hashOff + 4*numHash
}
n := round(uint32(16+len(name)), recordUnit)
start = round(limit, recordUnit) // should already be rounded but just in case
+ // Note: Checking for crossing a page boundary would be
+ // start/pageSize != (start+n-1)/pageSize,
+ // but we are checking for reaching the page end, so no -1.
+ // The page end is reserved for use by extend.
+ // See the comment in m.extend.
if start/pageSize != (start+n)/pageSize {
// bump start to next page
start = round(limit, pageSize)
@@ -531,6 +582,9 @@ }
return (*atomic.Uint32)(unsafe.Pointer(&m.mapping.Data[off])).CompareAndSwap(old, new)
}
+// entryAt reads a counter record at the given byte offset.
+//
+// See the documentation for [mappedFile] for a description of the counter record layout.
func (m *mappedFile) entryAt(off uint32) (name []byte, next uint32, v *atomic.Uint64, ok bool) {
if off < m.hdrLen+hashOff || int64(off)+16 > int64(len(m.mapping.Data)) {
return nil, 0, nil, false
@@ -545,7 +599,14 @@ v = (*atomic.Uint64)(unsafe.Pointer(&m.mapping.Data[off]))
return name, next, v, true
}
+// writeEntryAt writes a new counter record at the given offset.
+//
+// See the documentation for [mappedFile] for a description of the counter record layout.
+//
+// writeEntryAt only returns false in the presence of some form of corruption:
+// an offset outside the bounds of the record region in the mapped file.
func (m *mappedFile) writeEntryAt(off uint32, name string) (next *atomic.Uint32, v *atomic.Uint64, ok bool) {
+ // TODO(rfindley): shouldn't this first condition be off < m.hdrLen+hashOff+4*numHash?
if off < m.hdrLen+hashOff || int64(off)+16+int64(len(name)) > int64(len(m.mapping.Data)) {
return nil, nil, false
}
@@ -556,6 +617,11 @@ v = (*atomic.Uint64)(unsafe.Pointer(&m.mapping.Data[off]))
return next, v, true
}
+// lookup searches the mapped file for a counter record with the given name, returning:
+// - v: the mapped counter value
+// - headOff: the offset of the head pointer (see [mappedFile])
+// - head: the value of the head pointer
+// - ok: whether lookup succeeded
func (m *mappedFile) lookup(name string) (v *atomic.Uint64, headOff, head uint32, ok bool) {
h := hash(name)
headOff = m.hdrLen + hashOff + h*4
@@ -574,6 +640,9 @@ }
return nil, headOff, head, true
}
+// newCounter allocates and writes a new counter record with the given name.
+//
+// If name is already recorded in the file, newCounter returns the existing counter.
func (m *mappedFile) newCounter(name string) (v *atomic.Uint64, m1 *mappedFile, err error) {
if len(name) > maxNameLen {
return nil, nil, fmt.Errorf("counter name too long")
@@ -590,19 +659,37 @@ }
}()
v, headOff, head, ok := m.lookup(name)
- for !ok {
+ for tries := 0; !ok; tries++ {
+ if tries >= 10 {
+ debugFatalf("corrupt: failed to remap after 10 tries")
+ return nil, nil, errCorrupt
+ }
// Lookup found an invalid pointer,
// perhaps because the file has grown larger than the mapping.
limit := m.load32(m.hdrLen + limitOff)
- if int64(limit) <= int64(len(m.mapping.Data)) {
- // Mapping doesn't need to grow, so lookup found actual corruption.
- debugPrintf("corrupt1\n")
+ if limit, datalen := int64(limit), int64(len(m.mapping.Data)); limit <= datalen {
+ // Mapping doesn't need to grow, so lookup found actual corruption,
+ // in the form of an entry pointer that exceeds the recorded allocation
+ // limit. This should never happen, unless the actual file contents are
+ // corrupt.
+ debugFatalf("corrupt: limit %d is within mapping length %d", limit, datalen)
return nil, nil, errCorrupt
}
- newM, err := openMapped(m.f.Name(), m.meta, m)
+ // That the recorded limit is greater than the mapped data indicates that
+ // an external process has extended the file. Re-map to pick up this extension.
+ newM, err := openMapped(m.f.Name(), m.meta)
if err != nil {
return nil, nil, err
}
+ if limit, datalen := int64(limit), int64(len(newM.mapping.Data)); limit > datalen {
+ // We've re-mapped, yet limit still exceeds the data length. This
+ // indicates that the underlying file was somehow truncated, or the
+ // recorded limit is corrupt.
+ debugFatalf("corrupt: limit %d exceeds file size %d", limit, datalen)
+ return nil, nil, errCorrupt
+ }
+ // If m != orig, this is at least the second time around the loop
+ // trying to open the mapping. Close the previous attempt.
if m != orig {
m.close()
}
@@ -643,7 +730,7 @@
// Write record.
next, v, ok := m.writeEntryAt(start, name)
if !ok {
- debugPrintf("corrupt2 %#x+%d vs %#x\n", start, len(name), len(m.mapping.Data))
+ debugFatalf("corrupt: failed to write entry: %#x+%d vs %#x\n", start, len(name), len(m.mapping.Data))
return nil, nil, errCorrupt // more likely our math is wrong
}
@@ -679,12 +766,26 @@ if err != nil {
return nil, err
}
if info.Size() < int64(end) {
+ // Note: multiple processes could be calling extend at the same time,
+ // but this write only writes the last 4 bytes of the page.
+ // The last 4 bytes of the page are reserved for this purpose and hold no data.
+ // (In m.place, if a new record would extend to the very end of the page,
+ // it is placed in the next page instead.)
+ // So it is fine if multiple processes extend at the same time.
if _, err := m.f.WriteAt(m.zero[:], int64(end)-int64(len(m.zero))); err != nil {
return nil, err
}
}
- newM, err := openMapped(m.f.Name(), m.meta, m)
- m.f.Close()
+ newM, err := openMapped(m.f.Name(), m.meta)
+ if err != nil {
+ return nil, err
+ }
+ if int64(len(newM.mapping.Data)) < int64(end) {
+ // File system or logic bug: new file is somehow not extended.
+ // See go.dev/issue/68311, where this appears to have been happening.
+ newM.close()
+ return nil, errCorrupt
+ }
return newM, err
}
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap.go b/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap.go
index fb3ca9650d9093f46f8621797728be060b55216f..2febe3ecb9ed99cf41ffbc41211eb4537765150a 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap.go
@@ -26,12 +26,11 @@ }
// Mmap maps the given file into memory.
// When remapping a file, pass the most recently returned Data.
-func Mmap(f *os.File, data *Data) (Data, error) {
- return mmapFile(f, data)
+func Mmap(f *os.File) (*Data, error) {
+ return mmapFile(f)
}
// Munmap unmaps the given file from memory.
func Munmap(d *Data) error {
- // d.f.Close() on Windows still gets an error
- return munmapFile(*d)
+ return munmapFile(d)
}
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_other.go b/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_other.go
index 361ca8b01aa7fe0511f24204d78900e60d348358..190afd8e9fb65d8c57c04972dbacb73ceddb1029 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_other.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_other.go
@@ -12,14 +12,14 @@ "os"
)
// mmapFile on other systems doesn't mmap the file. It just reads everything.
-func mmapFile(f *os.File, _ *Data) (Data, error) {
+func mmapFile(f *os.File) (*Data, error) {
b, err := io.ReadAll(f)
if err != nil {
- return Data{}, err
+ return nil, err
}
- return Data{f, b, nil}, nil
+ return &Data{f, b, nil}, nil
}
-func munmapFile(d Data) error {
+func munmapFile(_ *Data) error {
return nil
}
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_unix.go b/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_unix.go
index af462ff67646a14941c28d25679d7734a1580e7f..f15ac615b341f44bba640307b3658e94ca3d5f0a 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_unix.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_unix.go
@@ -13,29 +13,29 @@ "os"
"syscall"
)
-func mmapFile(f *os.File, _ *Data) (Data, error) {
+func mmapFile(f *os.File) (*Data, error) {
st, err := f.Stat()
if err != nil {
- return Data{}, err
+ return nil, err
}
size := st.Size()
pagesize := int64(os.Getpagesize())
if int64(int(size+(pagesize-1))) != size+(pagesize-1) {
- return Data{}, fmt.Errorf("%s: too large for mmap", f.Name())
+ return nil, fmt.Errorf("%s: too large for mmap", f.Name())
}
n := int(size)
if n == 0 {
- return Data{f, nil, nil}, nil
+ return &Data{f, nil, nil}, nil
}
mmapLength := int(((size + pagesize - 1) / pagesize) * pagesize) // round up to page size
data, err := syscall.Mmap(int(f.Fd()), 0, mmapLength, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
if err != nil {
- return Data{}, &fs.PathError{Op: "mmap", Path: f.Name(), Err: err}
+ return nil, &fs.PathError{Op: "mmap", Path: f.Name(), Err: err}
}
- return Data{f, data[:n], nil}, nil
+ return &Data{f, data[:n], nil}, nil
}
-func munmapFile(d Data) error {
+func munmapFile(d *Data) error {
if len(d.Data) == 0 {
return nil
}
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_windows.go b/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_windows.go
index e70e7c7b07454fc0c61d74149562ade7e896a819..2e8dfbea9c0cba89dbda84ab2c6e76f194b499d7 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_windows.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/mmap/mmap_windows.go
@@ -13,35 +13,35 @@
"golang.org/x/sys/windows"
)
-func mmapFile(f *os.File, previous *Data) (Data, error) {
- if previous != nil {
- munmapFile(*previous)
- }
+func mmapFile(f *os.File) (*Data, error) {
st, err := f.Stat()
if err != nil {
- return Data{}, err
+ return nil, err
}
size := st.Size()
if size == 0 {
- return Data{f, nil, nil}, nil
+ return &Data{f, nil, nil}, nil
}
// set the min and max sizes to zero to map the whole file, as described in
// https://learn.microsoft.com/en-us/windows/win32/memory/creating-a-file-mapping-object#file-mapping-size
h, err := windows.CreateFileMapping(windows.Handle(f.Fd()), nil, syscall.PAGE_READWRITE, 0, 0, nil)
if err != nil {
- return Data{}, fmt.Errorf("CreateFileMapping %s: %w", f.Name(), err)
+ return nil, fmt.Errorf("CreateFileMapping %s: %w", f.Name(), err)
}
// the mapping extends from zero to the end of the file mapping
// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile
addr, err := windows.MapViewOfFile(h, syscall.FILE_MAP_READ|syscall.FILE_MAP_WRITE, 0, 0, 0)
if err != nil {
- return Data{}, fmt.Errorf("MapViewOfFile %s: %w", f.Name(), err)
+ return nil, fmt.Errorf("MapViewOfFile %s: %w", f.Name(), err)
}
- // need to remember addr and h for unmapping
- return Data{f, unsafe.Slice((*byte)(unsafe.Pointer(addr)), size), h}, nil
+ // Note: previously, we called windows.VirtualQuery here to get the exact
+ // size of the memory mapped region, but VirtualQuery reported sizes smaller
+ // than the actual file size (hypothesis: VirtualQuery only reports pages in
+ // a certain state, and newly written pages may not be counted).
+ return &Data{f, unsafe.Slice((*byte)(unsafe.Pointer(addr)), size), h}, nil
}
-func munmapFile(d Data) error {
+func munmapFile(d *Data) error {
err := windows.UnmapViewOfFile(uintptr(unsafe.Pointer(&d.Data[0])))
x, ok := d.Windows.(windows.Handle)
if ok {
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/proginfo.go b/src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/proginfo.go
index 20be9664fc8cd1570abf342cf6df69a82146d96c..60cb0edc792a599ce6c74b9a699e352e4df0439b 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/proginfo.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/proginfo.go
@@ -9,8 +9,6 @@ "os"
"path/filepath"
"runtime/debug"
"strings"
-
- "golang.org/x/mod/module"
)
// IsToolchainProgram reports whether a program with the given path is a Go
@@ -43,8 +41,13 @@ if IsToolchainProgram(progPath) {
progVers = goVers
} else {
progVers = info.Main.Version
- if strings.Contains(progVers, "devel") || module.IsPseudoVersion(progVers) {
- // We don't want to track pseudo versions, but may want to track prereleases.
+ if strings.Contains(progVers, "devel") || strings.Count(progVers, "-") > 1 {
+ // Heuristically mark all pseudo-version-like version strings as "devel"
+ // to avoid creating too many counter files.
+ // We should not use regexp that pulls in large dependencies.
+ // Pseudo-versions have at least three parts (https://go.dev/ref/mod#pseudo-versions).
+ // This heuristic still allows use to track prerelease
+ // versions (e.g. gopls@v0.16.0-pre.1, vscgo@v0.42.0-rc.1).
progVers = "devel"
}
}
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/types.go b/src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/types.go
index bcd172d97f8e48148b141f7c9f651d36f4137ea7..7c788b34152ce2f809290749f9a25e6d3211f856 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/types.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/telemetry/types.go
@@ -31,9 +31,9 @@ Rate float64 // If X <= Rate, report this counter
Depth int `json:",omitempty"` // for stack counters
}
-// A Report is what's uploaded (or saved locally)
+// A Report is the weekly aggregate of counters.
type Report struct {
- Week string // first day this report covers (YYYY-MM-DD)
+ Week string // End day this report covers (YYYY-MM-DD)
LastWeek string // Week field from latest previous report uploaded
X float64 // A random probability used to determine which counters are uploaded
Programs []*ProgramReport
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/upload/findwork.go b/src/cmd/vendor/golang.org/x/telemetry/internal/upload/findwork.go
index f1490be3a57b8508ca634afd6384bb2d99dc6f64..2b165be3f9ff208dec86e16409f07f44e8a48597 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/upload/findwork.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/upload/findwork.go
@@ -32,7 +32,7 @@ return ans
}
mode, asof := u.dir.Mode()
- u.logger.Printf("Finding work: mode %s, asof %s", mode, asof)
+ u.logger.Printf("Finding work: mode %s asof %s", mode, asof)
// count files end in .v1.count
// reports end in .json. If they are not to be uploaded they
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/upload/reports.go b/src/cmd/vendor/golang.org/x/telemetry/internal/upload/reports.go
index d1091f40add84225b148613c76aa4e861c84db5b..31bda70676f32a31f726ad89b20e029be4a84331 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/upload/reports.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/upload/reports.go
@@ -115,8 +115,11 @@ }
}
}
-// createReport for all the count files for the same date.
-// returns the absolute path name of the file containing the report
+// createReport creates local and upload report files by
+// combining all the count files for the expiryDate, and
+// returns the upload report file's path.
+// It may delete the count files once local and upload report
+// files are successfully created.
func (u *uploader) createReport(start time.Time, expiryDate string, countFiles []string, lastWeek string) (string, error) {
uploadOK := true
mode, asof := u.dir.Mode()
diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/upload/upload.go b/src/cmd/vendor/golang.org/x/telemetry/internal/upload/upload.go
index 2a3bf70f9d5be3a30dd4f340a13a3f81834ebd80..aa0f4f0c87c97fe61a346db6ed9a54794894994a 100644
--- a/src/cmd/vendor/golang.org/x/telemetry/internal/upload/upload.go
+++ b/src/cmd/vendor/golang.org/x/telemetry/internal/upload/upload.go
@@ -65,12 +65,6 @@ fdate := strings.TrimSuffix(filepath.Base(fname), ".json")
fdate = fdate[len(fdate)-len("2006-01-02"):]
newname := filepath.Join(u.dir.UploadDir(), fdate+".json")
- if _, err := os.Stat(newname); err == nil {
- // Another process uploaded but failed to clean up (or hasn't yet cleaned
- // up). Ensure that cleanup occurs.
- _ = os.Remove(fname)
- return false
- }
// Lock the upload, to prevent duplicate uploads.
{
@@ -82,6 +76,14 @@ return false
}
_ = lockfile.Close()
defer os.Remove(lockname)
+ }
+
+ if _, err := os.Stat(newname); err == nil {
+ // Another process uploaded but failed to clean up (or hasn't yet cleaned
+ // up). Ensure that cleanup occurs.
+ u.logger.Printf("After acquire: report already uploaded")
+ _ = os.Remove(fname)
+ return false
}
endpoint := u.uploadServerURL + "/" + fdate
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
index 8ba7df290fa0c1b012ada0b6601570d6ef2d3958..8a3cc87dcb157924eb4898b0155f9bd97a836fa8 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -25,7 +25,7 @@ golang.org/x/arch/x86/x86asm
# golang.org/x/build v0.0.0-20240603162849-5dfbda438323
## explicit; go 1.21
golang.org/x/build/relnote
-# golang.org/x/mod v0.18.0
+# golang.org/x/mod v0.19.0
## explicit; go 1.18
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
@@ -40,12 +40,12 @@ # golang.org/x/sync v0.7.0
## explicit; go 1.18
golang.org/x/sync/errgroup
golang.org/x/sync/semaphore
-# golang.org/x/sys v0.21.0
+# golang.org/x/sys v0.22.0
## explicit; go 1.18
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/telemetry v0.0.0-20240612191826-8cad58b3fcbb
+# golang.org/x/telemetry v0.0.0-20240712210958-268b4a8ec2d7
## explicit; go 1.20
golang.org/x/telemetry
golang.org/x/telemetry/counter
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index 84821d43fcb149a12fe25a6d86b5814e0973606c..3ace8ad6897b888adc9717b7f1012a6614774ac6 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -6,7 +6,7 @@ package main
import (
"cmd/internal/objabi"
- "cmd/internal/telemetry"
+ "cmd/internal/telemetry/counter"
"flag"
"golang.org/x/tools/go/analysis/unitchecker"
@@ -47,10 +47,10 @@ "golang.org/x/tools/go/analysis/passes/unusedresult"
)
func main() {
- telemetry.OpenCounters()
+ counter.Open()
objabi.AddVersionFlag()
- telemetry.Inc("vet/invocations")
+ counter.Inc("vet/invocations")
unitchecker.Main(
appends.Analyzer,
asmdecl.Analyzer,
@@ -89,5 +89,5 @@ )
// It's possible that unitchecker will exit early. In
// those cases the flags won't be counted.
- telemetry.CountFlags("vet/flag:", *flag.CommandLine)
+ counter.CountFlags("vet/flag:", *flag.CommandLine)
}
diff --git a/src/context/context.go b/src/context/context.go
index 30adfe987d53cf2f08be331a18d4f4d399f78df3..763d4f777ffb867379fd88699c54a4b7285ec63a 100644
--- a/src/context/context.go
+++ b/src/context/context.go
@@ -739,6 +739,8 @@ case stringer:
return s.String()
case string:
return s
+ case nil:
+ return ""
}
return reflectlite.TypeOf(v).String()
}
diff --git a/src/context/x_test.go b/src/context/x_test.go
index 2c66ed42b2f1510142d4ca845e3717e57848f119..ab3c2757cf5834de0f9b78c502af9f55222dbe30 100644
--- a/src/context/x_test.go
+++ b/src/context/x_test.go
@@ -243,6 +243,10 @@
c4 := WithValue(c3, k1, nil)
check(c4, "c4", "", "c2k2", "c3k3")
+ if got, want := fmt.Sprint(c4), `context.Background.WithValue(context_test.key1, c1k1).WithValue(context_test.key2(1), c2k2).WithValue(context_test.key2(3), c3k3).WithValue(context_test.key1, )`; got != want {
+ t.Errorf("c.String() = %q want %q", got, want)
+ }
+
o0 := otherContext{Background()}
check(o0, "o0", "", "", "")
diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go
index 55415abf020799c4120705d061aac7d6b7e4f3b7..7accad763244a1f1d73f32cdcf5dda51eaf1501d 100644
--- a/src/crypto/hmac/hmac_test.go
+++ b/src/crypto/hmac/hmac_test.go
@@ -5,8 +5,8 @@
package hmac
import (
- "bytes"
"crypto/internal/boring"
+ "crypto/internal/cryptotest"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
@@ -621,39 +621,14 @@ t.Error("Equal accepted unequal slices")
}
}
-func TestWriteAfterSum(t *testing.T) {
- h := New(sha1.New, nil)
- h.Write([]byte("hello"))
- sumHello := h.Sum(nil)
-
- h = New(sha1.New, nil)
- h.Write([]byte("hello world"))
- sumHelloWorld := h.Sum(nil)
+func TestHMACHash(t *testing.T) {
+ for i, test := range hmacTests {
+ baseHash := test.hash
+ key := test.key
- // Test that Sum has no effect on future Sum or Write operations.
- // This is a bit unusual as far as usage, but it's allowed
- // by the definition of Go hash.Hash, and some clients expect it to work.
- h = New(sha1.New, nil)
- h.Write([]byte("hello"))
- if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
- t.Fatalf("1st Sum after hello = %x, want %x", sum, sumHello)
- }
- if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
- t.Fatalf("2nd Sum after hello = %x, want %x", sum, sumHello)
- }
-
- h.Write([]byte(" world"))
- if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
- t.Fatalf("1st Sum after hello world = %x, want %x", sum, sumHelloWorld)
- }
- if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
- t.Fatalf("2nd Sum after hello world = %x, want %x", sum, sumHelloWorld)
- }
-
- h.Reset()
- h.Write([]byte("hello"))
- if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
- t.Fatalf("Sum after Reset + hello = %x, want %x", sum, sumHello)
+ t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) {
+ cryptotest.TestHash(t, func() hash.Hash { return New(baseHash, key) })
+ })
}
}
diff --git a/src/crypto/internal/cryptotest/hash.go b/src/crypto/internal/cryptotest/hash.go
new file mode 100644
index 0000000000000000000000000000000000000000..a950dcb282140d42ad1e8ab5993b5757cf48f18b
--- /dev/null
+++ b/src/crypto/internal/cryptotest/hash.go
@@ -0,0 +1,189 @@
+// 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 cryptotest
+
+import (
+ "bytes"
+ "hash"
+ "io"
+ "math/rand"
+ "testing"
+ "time"
+)
+
+type MakeHash func() hash.Hash
+
+// TestHash performs a set of tests on hash.Hash implementations, checking the
+// documented requirements of Write, Sum, Reset, Size, and BlockSize.
+func TestHash(t *testing.T, mh MakeHash) {
+
+ // Test that Sum returns an appended digest matching output of Size
+ t.Run("SumAppend", func(t *testing.T) {
+ h := mh()
+ rng := newRandReader(t)
+
+ emptyBuff := []byte("")
+ shortBuff := []byte("a")
+ longBuff := make([]byte, h.BlockSize()+1)
+ rng.Read(longBuff)
+
+ // Set of example strings to append digest to
+ prefixes := [][]byte{nil, emptyBuff, shortBuff, longBuff}
+
+ // Go to each string and check digest gets appended to and is correct size.
+ for _, prefix := range prefixes {
+ h.Reset()
+
+ sum := getSum(t, h, prefix) // Append new digest to prefix
+
+ // Check that Sum didn't alter the prefix
+ if !bytes.Equal(sum[0:len(prefix)], prefix) {
+ t.Errorf("Sum alters passed buffer instead of appending; got %x, want %x", sum[0:len(prefix)], prefix)
+ }
+
+ // Check that the appended sum wasn't affected by the prefix
+ if expectedSum := getSum(t, h, nil); !bytes.Equal(sum[len(prefix):], expectedSum) {
+ t.Errorf("Sum behavior affected by data in the input buffer; got %x, want %x", sum[len(prefix):], expectedSum)
+ }
+
+ // Check size of append
+ if got, want := len(sum)-len(prefix), h.Size(); got != want {
+ t.Errorf("Sum appends number of bytes != Size; got %v , want %v", got, want)
+ }
+ }
+ })
+
+ // Test that Hash.Write never returns error.
+ t.Run("WriteWithoutError", func(t *testing.T) {
+ h := mh()
+ rng := newRandReader(t)
+
+ emptySlice := []byte("")
+ shortSlice := []byte("a")
+ longSlice := make([]byte, h.BlockSize()+1)
+ rng.Read(longSlice)
+
+ // Set of example strings to append digest to
+ slices := [][]byte{emptySlice, shortSlice, longSlice}
+
+ for _, slice := range slices {
+ writeToHash(t, h, slice) // Writes and checks Write doesn't error
+ }
+ })
+
+ t.Run("ResetState", func(t *testing.T) {
+ h := mh()
+ rng := newRandReader(t)
+
+ emptySum := getSum(t, h, nil)
+
+ // Write to hash and then Reset it and see if Sum is same as emptySum
+ writeEx := make([]byte, h.BlockSize())
+ rng.Read(writeEx)
+ writeToHash(t, h, writeEx)
+ h.Reset()
+ resetSum := getSum(t, h, nil)
+
+ if !bytes.Equal(emptySum, resetSum) {
+ t.Errorf("Reset hash yields different Sum than new hash; got %x, want %x", emptySum, resetSum)
+ }
+ })
+
+ // Check that Write isn't reading from beyond input slice's bounds
+ t.Run("OutOfBoundsRead", func(t *testing.T) {
+ h := mh()
+ blockSize := h.BlockSize()
+ rng := newRandReader(t)
+
+ msg := make([]byte, blockSize)
+ rng.Read(msg)
+ writeToHash(t, h, msg)
+ expectedDigest := getSum(t, h, nil) // Record control digest
+
+ h.Reset()
+
+ // Make a buffer with msg in the middle and data on either end
+ buff := make([]byte, blockSize*3)
+ endOfPrefix, startOfSuffix := blockSize, blockSize*2
+
+ copy(buff[endOfPrefix:startOfSuffix], msg)
+ rng.Read(buff[:endOfPrefix])
+ rng.Read(buff[startOfSuffix:])
+
+ writeToHash(t, h, buff[endOfPrefix:startOfSuffix])
+ testDigest := getSum(t, h, nil)
+
+ if !bytes.Equal(testDigest, expectedDigest) {
+ t.Errorf("Write affected by data outside of input slice bounds; got %x, want %x", testDigest, expectedDigest)
+ }
+ })
+
+ // Test that multiple calls to Write is stateful
+ t.Run("StatefulWrite", func(t *testing.T) {
+ h := mh()
+ rng := newRandReader(t)
+
+ prefix, suffix := make([]byte, h.BlockSize()), make([]byte, h.BlockSize())
+ rng.Read(prefix)
+ rng.Read(suffix)
+
+ // Write prefix then suffix sequentially and record resulting hash
+ writeToHash(t, h, prefix)
+ writeToHash(t, h, suffix)
+ serialSum := getSum(t, h, nil)
+
+ h.Reset()
+
+ // Write prefix and suffix at the same time and record resulting hash
+ writeToHash(t, h, append(prefix, suffix...))
+ compositeSum := getSum(t, h, nil)
+
+ // Check that sequential writing results in the same as writing all at once
+ if !bytes.Equal(compositeSum, serialSum) {
+ t.Errorf("two successive Write calls resulted in a different Sum than a single one; got %x, want %x", compositeSum, serialSum)
+ }
+ })
+}
+
+// Helper function for writing. Verifies that Write does not error.
+func writeToHash(t *testing.T, h hash.Hash, p []byte) {
+ t.Helper()
+
+ before := make([]byte, len(p))
+ copy(before, p)
+
+ n, err := h.Write(p)
+ if err != nil || n != len(p) {
+ t.Errorf("Write returned error; got (%v, %v), want (nil, %v)", err, n, len(p))
+ }
+
+ if !bytes.Equal(p, before) {
+ t.Errorf("Write modified input slice; got %x, want %x", p, before)
+ }
+}
+
+// Helper function for getting Sum. Checks that Sum doesn't change hash state.
+func getSum(t *testing.T, h hash.Hash, buff []byte) []byte {
+ t.Helper()
+
+ testBuff := make([]byte, len(buff))
+ copy(testBuff, buff)
+
+ sum := h.Sum(buff)
+ testSum := h.Sum(testBuff)
+
+ // Check that Sum doesn't change underlying hash state
+ if !bytes.Equal(sum, testSum) {
+ t.Errorf("successive calls to Sum yield different results; got %x, want %x", sum, testSum)
+ }
+
+ return sum
+}
+
+func newRandReader(t *testing.T) io.Reader {
+ seed := time.Now().UnixNano()
+ t.Logf("Deterministic RNG seed: 0x%x", seed)
+ return rand.New(rand.NewSource(seed))
+}
diff --git a/src/crypto/md5/md5_test.go b/src/crypto/md5/md5_test.go
index 851e7fb10d42f59530d8a5dd9d6933d71dff908a..a5b661126dd7160fb92ed0725a286c76b0ba561e 100644
--- a/src/crypto/md5/md5_test.go
+++ b/src/crypto/md5/md5_test.go
@@ -6,6 +6,7 @@ package md5
import (
"bytes"
+ "crypto/internal/cryptotest"
"crypto/rand"
"encoding"
"fmt"
@@ -223,6 +224,10 @@ }))
if n > 0 {
t.Errorf("allocs = %d, want 0", n)
}
+}
+
+func TestMD5Hash(t *testing.T) {
+ cryptotest.TestHash(t, New)
}
var bench = New()
diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go
index 85ed12609154ff36ebddaedcbe527044be76f87a..634ab9de1ba4cb1bf846290bcc9c4690a7615542 100644
--- a/src/crypto/sha1/sha1_test.go
+++ b/src/crypto/sha1/sha1_test.go
@@ -9,6 +9,7 @@
import (
"bytes"
"crypto/internal/boring"
+ "crypto/internal/cryptotest"
"crypto/rand"
"encoding"
"fmt"
@@ -232,6 +233,10 @@ }))
if n > 0 {
t.Errorf("allocs = %d, want 0", n)
}
+}
+
+func TestSHA1Hash(t *testing.T) {
+ cryptotest.TestHash(t, New)
}
var bench = New()
diff --git a/src/crypto/sha256/sha256_test.go b/src/crypto/sha256/sha256_test.go
index 7304678346b32e9ecc60197f3b911ef048c6bced..d91f01e9ba3a5f44d912d0b4097857b7f2de8557 100644
--- a/src/crypto/sha256/sha256_test.go
+++ b/src/crypto/sha256/sha256_test.go
@@ -9,6 +9,7 @@
import (
"bytes"
"crypto/internal/boring"
+ "crypto/internal/cryptotest"
"crypto/rand"
"encoding"
"fmt"
@@ -323,6 +324,15 @@ d.Ptr = d
h := New()
h.Write(d.Data[:])
h.Sum(nil)
+}
+
+func TestSHA256Hash(t *testing.T) {
+ t.Run("SHA-224", func(t *testing.T) {
+ cryptotest.TestHash(t, New224)
+ })
+ t.Run("SHA-256", func(t *testing.T) {
+ cryptotest.TestHash(t, New)
+ })
}
var bench = New()
diff --git a/src/crypto/sha512/sha512_test.go b/src/crypto/sha512/sha512_test.go
index 921cdbb7bbd477952f83de91432df7c62ac7119c..a1ff571383e542aedafa497b563f63e399f0d5d5 100644
--- a/src/crypto/sha512/sha512_test.go
+++ b/src/crypto/sha512/sha512_test.go
@@ -9,6 +9,7 @@
import (
"bytes"
"crypto/internal/boring"
+ "crypto/internal/cryptotest"
"crypto/rand"
"encoding"
"encoding/hex"
@@ -907,6 +908,21 @@ }))
if n > 0 {
t.Errorf("allocs = %d, want 0", n)
}
+}
+
+func TestSHA512Hash(t *testing.T) {
+ t.Run("SHA-384", func(t *testing.T) {
+ cryptotest.TestHash(t, New384)
+ })
+ t.Run("SHA-512/224", func(t *testing.T) {
+ cryptotest.TestHash(t, New512_224)
+ })
+ t.Run("SHA-512/256", func(t *testing.T) {
+ cryptotest.TestHash(t, New512_256)
+ })
+ t.Run("SHA-512", func(t *testing.T) {
+ cryptotest.TestHash(t, New)
+ })
}
var bench = New()
diff --git a/src/crypto/tls/bogo_shim_test.go b/src/crypto/tls/bogo_shim_test.go
index 5dc3b7c13ea79123982313dcd2039f126a445ef7..f481a5a40fbf31a7830a96281cd645aaa875627e 100644
--- a/src/crypto/tls/bogo_shim_test.go
+++ b/src/crypto/tls/bogo_shim_test.go
@@ -33,8 +33,9 @@ certfile = flag.String("cert-file", "", "")
trustCert = flag.String("trust-cert", "", "")
- minVersion = flag.Int("min-version", VersionSSL30, "")
- maxVersion = flag.Int("max-version", VersionTLS13, "")
+ minVersion = flag.Int("min-version", VersionSSL30, "")
+ maxVersion = flag.Int("max-version", VersionTLS13, "")
+ expectVersion = flag.Int("expect-version", 0, "")
noTLS13 = flag.Bool("no-tls13", false, "")
@@ -53,6 +54,7 @@
echConfigListB64 = flag.String("ech-config-list", "", "")
expectECHAccepted = flag.Bool("expect-ech-accept", false, "")
expectHRR = flag.Bool("expect-hrr", false, "")
+ expectNoHRR = flag.Bool("expect-no-hrr", false, "")
expectedECHRetryConfigs = flag.String("expect-ech-retry-configs", "", "")
expectNoECHRetryConfigs = flag.Bool("expect-no-ech-retry-configs", false, "")
onInitialExpectECHAccepted = flag.Bool("on-initial-expect-ech-accept", false, "")
@@ -74,6 +76,8 @@ onResumeShimWritesFirst = flag.Bool("on-resume-shim-writes-first", false, "")
advertiseALPN = flag.String("advertise-alpn", "", "")
expectALPN = flag.String("expect-alpn", "", "")
+ rejectALPN = flag.Bool("reject-alpn", false, "")
+ declineALPN = flag.Bool("decline-alpn", false, "")
hostName = flag.String("host-name", "", "")
@@ -123,6 +127,14 @@ alpnLen := int(alpns[0])
cfg.NextProtos = append(cfg.NextProtos, alpns[1:1+alpnLen])
alpns = alpns[alpnLen+1:]
}
+ }
+
+ if *rejectALPN {
+ cfg.NextProtos = []string{"unnegotiableprotocol"}
+ }
+
+ if *declineALPN {
+ cfg.NextProtos = []string{}
}
if *hostName != "" {
@@ -252,7 +264,12 @@ if cs.HandshakeComplete {
if *expectALPN != "" && cs.NegotiatedProtocol != *expectALPN {
log.Fatalf("unexpected protocol negotiated: want %q, got %q", *expectALPN, cs.NegotiatedProtocol)
}
-
+ if *expectVersion != 0 && cs.Version != uint16(*expectVersion) {
+ log.Fatalf("expected ssl version %q, got %q", uint16(*expectVersion), cs.Version)
+ }
+ if *declineALPN && cs.NegotiatedProtocol != "" {
+ log.Fatal("unexpected ALPN protocol")
+ }
if *expectECHAccepted && !cs.ECHAccepted {
log.Fatal("expected ECH to be accepted, but connection state shows it was not")
} else if i == 0 && *onInitialExpectECHAccepted && !cs.ECHAccepted {
@@ -265,6 +282,10 @@ }
if *expectHRR && !cs.testingOnlyDidHRR {
log.Fatal("expected HRR but did not do it")
+ }
+
+ if *expectNoHRR && cs.testingOnlyDidHRR {
+ log.Fatal("expected no HRR but did do it")
}
if *expectSessionMiss && cs.DidResume {
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 553d2dde01de2d275f391cf24a0352945297c743..5025657590d32c5a9fab8d4ade234820b123a7dc 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -478,7 +478,9 @@ return nil, nil, nil, nil
}
if c.quic != nil {
- c.quicResumeSession(session)
+ if c.quic.enableSessionEvents {
+ c.quicResumeSession(session)
+ }
// For 0-RTT, the cipher suite has to match exactly, and we need to be
// offering the same ALPN.
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index 4570f5b05edfddba5fc1c427bc7b897c47a915d7..501f9c6755f9e3fea103fd5b8844f620f9bb1bac 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -283,7 +283,7 @@ return parseTestData(in)
}
func (test *clientTest) run(t *testing.T, write bool) {
- var clientConn, serverConn net.Conn
+ var clientConn net.Conn
var recordingConn *recordingConn
var childProcess *exec.Cmd
var stdin opensslInput
@@ -302,178 +302,138 @@ t.Logf("OpenSSL output:\n\n%s", stdout.all)
}
}()
} else {
- clientConn, serverConn = localPipe(t)
+ flows, err := test.loadData()
+ if err != nil {
+ t.Fatalf("failed to load data from %s: %v", test.dataPath(), err)
+ }
+ clientConn = &replayingConn{t: t, flows: flows, reading: false}
}
- doneChan := make(chan bool)
- defer func() {
- clientConn.Close()
- <-doneChan
- }()
- go func() {
- defer close(doneChan)
+ config := test.config
+ if config == nil {
+ config = testConfig
+ }
+ client := Client(clientConn, config)
+ defer client.Close()
- config := test.config
- if config == nil {
- config = testConfig
- }
- client := Client(clientConn, config)
- defer client.Close()
+ if _, err := client.Write([]byte("hello\n")); err != nil {
+ t.Errorf("Client.Write failed: %s", err)
+ return
+ }
- if _, err := client.Write([]byte("hello\n")); err != nil {
- t.Errorf("Client.Write failed: %s", err)
- return
+ for i := 1; i <= test.numRenegotiations; i++ {
+ // The initial handshake will generate a
+ // handshakeComplete signal which needs to be quashed.
+ if i == 1 && write {
+ <-stdout.handshakeComplete
}
- for i := 1; i <= test.numRenegotiations; i++ {
- // The initial handshake will generate a
- // handshakeComplete signal which needs to be quashed.
- if i == 1 && write {
- <-stdout.handshakeComplete
- }
-
- // OpenSSL will try to interleave application data and
- // a renegotiation if we send both concurrently.
- // Therefore: ask OpensSSL to start a renegotiation, run
- // a goroutine to call client.Read and thus process the
- // renegotiation request, watch for OpenSSL's stdout to
- // indicate that the handshake is complete and,
- // finally, have OpenSSL write something to cause
- // client.Read to complete.
- if write {
- stdin <- opensslRenegotiate
- }
-
- signalChan := make(chan struct{})
+ // OpenSSL will try to interleave application data and
+ // a renegotiation if we send both concurrently.
+ // Therefore: ask OpensSSL to start a renegotiation, run
+ // a goroutine to call client.Read and thus process the
+ // renegotiation request, watch for OpenSSL's stdout to
+ // indicate that the handshake is complete and,
+ // finally, have OpenSSL write something to cause
+ // client.Read to complete.
+ if write {
+ stdin <- opensslRenegotiate
+ }
- go func() {
- defer close(signalChan)
+ signalChan := make(chan struct{})
- buf := make([]byte, 256)
- n, err := client.Read(buf)
+ go func() {
+ defer close(signalChan)
- if test.checkRenegotiationError != nil {
- newErr := test.checkRenegotiationError(i, err)
- if err != nil && newErr == nil {
- return
- }
- err = newErr
- }
+ buf := make([]byte, 256)
+ n, err := client.Read(buf)
- if err != nil {
- t.Errorf("Client.Read failed after renegotiation #%d: %s", i, err)
+ if test.checkRenegotiationError != nil {
+ newErr := test.checkRenegotiationError(i, err)
+ if err != nil && newErr == nil {
return
}
+ err = newErr
+ }
- buf = buf[:n]
- if !bytes.Equal([]byte(opensslSentinel), buf) {
- t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
- }
-
- if expected := i + 1; client.handshakes != expected {
- t.Errorf("client should have recorded %d handshakes, but believes that %d have occurred", expected, client.handshakes)
- }
- }()
-
- if write && test.renegotiationExpectedToFail != i {
- <-stdout.handshakeComplete
- stdin <- opensslSendSentinel
+ if err != nil {
+ t.Errorf("Client.Read failed after renegotiation #%d: %s", i, err)
+ return
}
- <-signalChan
- }
- if test.sendKeyUpdate {
- if write {
- <-stdout.handshakeComplete
- stdin <- opensslKeyUpdate
+ buf = buf[:n]
+ if !bytes.Equal([]byte(opensslSentinel), buf) {
+ t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
}
- doneRead := make(chan struct{})
+ if expected := i + 1; client.handshakes != expected {
+ t.Errorf("client should have recorded %d handshakes, but believes that %d have occurred", expected, client.handshakes)
+ }
+ }()
- go func() {
- defer close(doneRead)
+ if write && test.renegotiationExpectedToFail != i {
+ <-stdout.handshakeComplete
+ stdin <- opensslSendSentinel
+ }
+ <-signalChan
+ }
- buf := make([]byte, 256)
- n, err := client.Read(buf)
+ if test.sendKeyUpdate {
+ if write {
+ <-stdout.handshakeComplete
+ stdin <- opensslKeyUpdate
+ }
- if err != nil {
- t.Errorf("Client.Read failed after KeyUpdate: %s", err)
- return
- }
+ doneRead := make(chan struct{})
- buf = buf[:n]
- if !bytes.Equal([]byte(opensslSentinel), buf) {
- t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
- }
- }()
+ go func() {
+ defer close(doneRead)
- if write {
- // There's no real reason to wait for the client KeyUpdate to
- // send data with the new server keys, except that s_server
- // drops writes if they are sent at the wrong time.
- <-stdout.readKeyUpdate
- stdin <- opensslSendSentinel
- }
- <-doneRead
+ buf := make([]byte, 256)
+ n, err := client.Read(buf)
- if _, err := client.Write([]byte("hello again\n")); err != nil {
- t.Errorf("Client.Write failed: %s", err)
+ if err != nil {
+ t.Errorf("Client.Read failed after KeyUpdate: %s", err)
return
}
- }
- if test.validate != nil {
- if err := test.validate(client.ConnectionState()); err != nil {
- t.Errorf("validate callback returned error: %s", err)
+ buf = buf[:n]
+ if !bytes.Equal([]byte(opensslSentinel), buf) {
+ t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
}
- }
+ }()
- // If the server sent us an alert after our last flight, give it a
- // chance to arrive.
- if write && test.renegotiationExpectedToFail == 0 {
- if err := peekError(client); err != nil {
- t.Errorf("final Read returned an error: %s", err)
- }
+ if write {
+ // There's no real reason to wait for the client KeyUpdate to
+ // send data with the new server keys, except that s_server
+ // drops writes if they are sent at the wrong time.
+ <-stdout.readKeyUpdate
+ stdin <- opensslSendSentinel
}
- }()
+ <-doneRead
- if !write {
- flows, err := test.loadData()
- if err != nil {
- t.Fatalf("%s: failed to load data from %s: %v", test.name, test.dataPath(), err)
+ if _, err := client.Write([]byte("hello again\n")); err != nil {
+ t.Errorf("Client.Write failed: %s", err)
+ return
}
- for i, b := range flows {
- if i%2 == 1 {
- if *fast {
- serverConn.SetWriteDeadline(time.Now().Add(1 * time.Second))
- } else {
- serverConn.SetWriteDeadline(time.Now().Add(1 * time.Minute))
- }
- serverConn.Write(b)
- continue
- }
- bb := make([]byte, len(b))
- if *fast {
- serverConn.SetReadDeadline(time.Now().Add(1 * time.Second))
- } else {
- serverConn.SetReadDeadline(time.Now().Add(1 * time.Minute))
- }
- _, err := io.ReadFull(serverConn, bb)
- if err != nil {
- t.Fatalf("%s, flow %d: %s", test.name, i+1, err)
- }
- if !bytes.Equal(b, bb) {
- t.Fatalf("%s, flow %d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
- }
+ }
+
+ if test.validate != nil {
+ if err := test.validate(client.ConnectionState()); err != nil {
+ t.Errorf("validate callback returned error: %s", err)
}
}
- <-doneChan
- if !write {
- serverConn.Close()
+ // If the server sent us an alert after our last flight, give it a
+ // chance to arrive.
+ if write && test.renegotiationExpectedToFail == 0 {
+ if err := peekError(client); err != nil {
+ t.Errorf("final Read returned an error: %s", err)
+ }
}
if write {
+ clientConn.Close()
path := test.dataPath()
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go
index 6744e713c9ffa8952f67f7dbf1195e52a8d60190..db5e35d9a46c2e1deef7ecf05c49eba87a4b56c9 100644
--- a/src/crypto/tls/handshake_client_tls13.go
+++ b/src/crypto/tls/handshake_client_tls13.go
@@ -900,7 +900,7 @@ session.useBy = uint64(c.config.time().Add(lifetime).Unix())
session.ageAdd = msg.ageAdd
session.EarlyData = c.quic != nil && msg.maxEarlyData == 0xffffffff // RFC 9001, Section 4.6.1
session.ticket = msg.label
- if c.quic != nil && c.quic.enableStoreSessionEvent {
+ if c.quic != nil && c.quic.enableSessionEvents {
c.quicStoreSession(session)
return nil
}
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index 44bc8f1bb7442a5ddc5bb4980620a147052352d2..94d3d0f6dc87bc6f48ce9e592ce1e273cd30182c 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -21,6 +21,7 @@ "os"
"os/exec"
"path/filepath"
"runtime"
+ "slices"
"strings"
"testing"
"time"
@@ -659,7 +660,7 @@ return parseTestData(in)
}
func (test *serverTest) run(t *testing.T, write bool) {
- var clientConn, serverConn net.Conn
+ var serverConn net.Conn
var recordingConn *recordingConn
var childProcess *exec.Cmd
@@ -676,65 +677,33 @@ t.Logf("OpenSSL output:\n\n%s", childProcess.Stdout)
}
}()
} else {
- clientConn, serverConn = localPipe(t)
+ flows, err := test.loadData()
+ if err != nil {
+ t.Fatalf("Failed to load data from %s", test.dataPath())
+ }
+ serverConn = &replayingConn{t: t, flows: flows, reading: true}
}
config := test.config
if config == nil {
config = testConfig
}
server := Server(serverConn, config)
- connStateChan := make(chan ConnectionState, 1)
- go func() {
- _, err := server.Write([]byte("hello, world\n"))
- if len(test.expectHandshakeErrorIncluding) > 0 {
- if err == nil {
- t.Errorf("Error expected, but no error returned")
- } else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) {
- t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s)
- }
- } else {
- if err != nil {
- t.Logf("Error from Server.Write: '%s'", err)
- }
+
+ _, err := server.Write([]byte("hello, world\n"))
+ if len(test.expectHandshakeErrorIncluding) > 0 {
+ if err == nil {
+ t.Errorf("Error expected, but no error returned")
+ } else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) {
+ t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s)
}
- server.Close()
- serverConn.Close()
- connStateChan <- server.ConnectionState()
- }()
-
- if !write {
- flows, err := test.loadData()
+ } else {
if err != nil {
- t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
+ t.Logf("Error from Server.Write: '%s'", err)
}
- for i, b := range flows {
- if i%2 == 0 {
- if *fast {
- clientConn.SetWriteDeadline(time.Now().Add(1 * time.Second))
- } else {
- clientConn.SetWriteDeadline(time.Now().Add(1 * time.Minute))
- }
- clientConn.Write(b)
- continue
- }
- bb := make([]byte, len(b))
- if *fast {
- clientConn.SetReadDeadline(time.Now().Add(1 * time.Second))
- } else {
- clientConn.SetReadDeadline(time.Now().Add(1 * time.Minute))
- }
- n, err := io.ReadFull(clientConn, bb)
- if err != nil {
- t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
- }
- if !bytes.Equal(b, bb) {
- t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
- }
- }
- clientConn.Close()
}
+ server.Close()
- connState := <-connStateChan
+ connState := server.ConnectionState()
peerCerts := connState.PeerCertificates
if len(peerCerts) == len(test.expectedPeerCerts) {
for i, peerCert := range peerCerts {
@@ -754,6 +723,7 @@ }
}
if write {
+ serverConn.Close()
path := test.dataPath()
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
@@ -1330,37 +1300,14 @@ }
serverConn.Close()
flows := serverConn.(*recordingConn).flows
- feeder := make(chan struct{})
- clientConn, serverConn = localPipe(b)
-
- go func() {
- for range feeder {
- for i, f := range flows {
- if i%2 == 0 {
- clientConn.Write(f)
- continue
- }
- ff := make([]byte, len(f))
- n, err := io.ReadFull(clientConn, ff)
- if err != nil {
- b.Errorf("#%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", i+1, err, n, len(ff), ff[:n], f)
- }
- if !bytes.Equal(f, ff) {
- b.Errorf("#%d: mismatch on read: got:%x want:%x", i+1, ff, f)
- }
- }
- }
- }()
-
b.ResetTimer()
for i := 0; i < b.N; i++ {
- feeder <- struct{}{}
- server := Server(serverConn, config)
+ replay := &replayingConn{t: b, flows: slices.Clone(flows), reading: true}
+ server := Server(replay, config)
if err := server.Handshake(); err != nil {
b.Fatalf("handshake failed: %v", err)
}
}
- close(feeder)
}
func BenchmarkHandshakeServer(b *testing.B) {
diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go
index f24c2671acd4353d2cd5682c23de38677a3f0314..503a732e05765ec86f68027eaa1fd890c8009771 100644
--- a/src/crypto/tls/handshake_server_tls13.go
+++ b/src/crypto/tls/handshake_server_tls13.go
@@ -377,7 +377,7 @@ len(sessionState.verifiedChains) == 0 {
continue
}
- if c.quic != nil {
+ if c.quic != nil && c.quic.enableSessionEvents {
if err := c.quicResumeSession(sessionState); err != nil {
return err
}
diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go
index 57fc761dbb81088388aeb53b78939a9fd28e6d14..bc3d23d5adc24efcb1afdca9a4674c55bf7bb98f 100644
--- a/src/crypto/tls/handshake_test.go
+++ b/src/crypto/tls/handshake_test.go
@@ -6,6 +6,7 @@ package tls
import (
"bufio"
+ "bytes"
"crypto/ed25519"
"crypto/x509"
"encoding/hex"
@@ -42,7 +43,6 @@ // reference connection will always change.
var (
update = flag.Bool("update", false, "update golden files on failure")
- fast = flag.Bool("fast", false, "impose a quick, possibly flaky timeout on recorded tests")
keyFile = flag.String("keylog", "", "destination file for KeyLogWriter")
bogoMode = flag.Bool("bogo-mode", false, "Enabled bogo shim mode, ignore everything else")
bogoFilter = flag.String("bogo-filter", "", "BoGo test filter")
@@ -222,6 +222,76 @@ }
return flows, nil
}
+
+// replayingConn is a net.Conn that replays flows recorded by recordingConn.
+type replayingConn struct {
+ t testing.TB
+ sync.Mutex
+ flows [][]byte
+ reading bool
+}
+
+var _ net.Conn = (*replayingConn)(nil)
+
+func (r *replayingConn) Read(b []byte) (n int, err error) {
+ r.Lock()
+ defer r.Unlock()
+
+ if !r.reading {
+ r.t.Errorf("expected write, got read")
+ return 0, fmt.Errorf("recording expected write, got read")
+ }
+
+ n = copy(b, r.flows[0])
+ r.flows[0] = r.flows[0][n:]
+ if len(r.flows[0]) == 0 {
+ r.flows = r.flows[1:]
+ if len(r.flows) == 0 {
+ return n, io.EOF
+ } else {
+ r.reading = false
+ }
+ }
+ return n, nil
+}
+
+func (r *replayingConn) Write(b []byte) (n int, err error) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.reading {
+ r.t.Errorf("expected read, got write")
+ return 0, fmt.Errorf("recording expected read, got write")
+ }
+
+ if !bytes.HasPrefix(r.flows[0], b) {
+ r.t.Errorf("write mismatch: expected %x, got %x", r.flows[0], b)
+ return 0, fmt.Errorf("write mismatch")
+ }
+ r.flows[0] = r.flows[0][len(b):]
+ if len(r.flows[0]) == 0 {
+ r.flows = r.flows[1:]
+ r.reading = true
+ }
+ return len(b), nil
+}
+
+func (r *replayingConn) Close() error {
+ r.Lock()
+ defer r.Unlock()
+
+ if len(r.flows) > 0 {
+ r.t.Errorf("closed with unfinished flows")
+ return fmt.Errorf("unexpected close")
+ }
+ return nil
+}
+
+func (r *replayingConn) LocalAddr() net.Addr { return nil }
+func (r *replayingConn) RemoteAddr() net.Addr { return nil }
+func (r *replayingConn) SetDeadline(t time.Time) error { return nil }
+func (r *replayingConn) SetReadDeadline(t time.Time) error { return nil }
+func (r *replayingConn) SetWriteDeadline(t time.Time) error { return nil }
// tempFile creates a temp file containing contents and returns its path.
func tempFile(contents string) string {
diff --git a/src/crypto/tls/quic.go b/src/crypto/tls/quic.go
index 8e722c6a590578881e66d0d906a68c033e59ef7c..9dd6168b62356ebac3f911cecb5b7f9284757a78 100644
--- a/src/crypto/tls/quic.go
+++ b/src/crypto/tls/quic.go
@@ -50,12 +50,12 @@ // A QUICConfig configures a [QUICConn].
type QUICConfig struct {
TLSConfig *Config
- // EnableStoreSessionEvent may be set to true to enable the
- // [QUICStoreSession] event for client connections.
+ // EnableSessionEvents may be set to true to enable the
+ // [QUICStoreSession] and [QUICResumeSession] events for client connections.
// When this event is enabled, sessions are not automatically
// stored in the client session cache.
// The application should use [QUICConn.StoreSession] to store sessions.
- EnableStoreSessionEvent bool
+ EnableSessionEvents bool
}
// A QUICEventKind is a type of operation on a QUIC connection.
@@ -113,7 +113,7 @@
// QUICStoreSession indicates that the server has provided state permitting
// the client to resume the session.
// [QUICEvent.SessionState] is set.
- // The application should use [QUICConn.Store] session to store the [SessionState].
+ // The application should use [QUICConn.StoreSession] session to store the [SessionState].
// The application may modify the [SessionState] before storing it.
// This event only occurs on client connections.
QUICStoreSession
@@ -165,7 +165,7 @@ readbuf []byte
transportParams []byte // to send to the peer
- enableStoreSessionEvent bool
+ enableSessionEvents bool
}
// QUICClient returns a new TLS client side connection using QUICTransport as the
@@ -186,9 +186,9 @@ }
func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn {
conn.quic = &quicState{
- signalc: make(chan struct{}),
- blockedc: make(chan struct{}),
- enableStoreSessionEvent: config.EnableStoreSessionEvent,
+ signalc: make(chan struct{}),
+ blockedc: make(chan struct{}),
+ enableSessionEvents: config.EnableSessionEvents,
}
conn.quic.events = conn.quic.eventArr[:0]
return &QUICConn{
diff --git a/src/crypto/tls/quic_test.go b/src/crypto/tls/quic_test.go
index 5a6f66e4deaeb4624a2ca5721ae0c99deb2b06d7..1bb2e55bddcbeac5a1841c3a312a67e6e583a689 100644
--- a/src/crypto/tls/quic_test.go
+++ b/src/crypto/tls/quic_test.go
@@ -24,22 +24,22 @@ earlyDataRejected bool
complete bool
}
-func newTestQUICClient(t *testing.T, config *Config) *testQUICConn {
- q := &testQUICConn{t: t}
- q.conn = QUICClient(&QUICConfig{
- TLSConfig: config,
- })
+func newTestQUICClient(t *testing.T, config *QUICConfig) *testQUICConn {
+ q := &testQUICConn{
+ t: t,
+ conn: QUICClient(config),
+ }
t.Cleanup(func() {
q.conn.Close()
})
return q
}
-func newTestQUICServer(t *testing.T, config *Config) *testQUICConn {
- q := &testQUICConn{t: t}
- q.conn = QUICServer(&QUICConfig{
- TLSConfig: config,
- })
+func newTestQUICServer(t *testing.T, config *QUICConfig) *testQUICConn {
+ q := &testQUICConn{
+ t: t,
+ conn: QUICServer(config),
+ }
t.Cleanup(func() {
q.conn.Close()
})
@@ -140,6 +140,11 @@ if err := srv.conn.SendSessionTicket(srv.ticketOpts); err != nil {
return err
}
}
+ case QUICStoreSession:
+ if a != cli {
+ return errors.New("unexpected QUICStoreSession event received by server")
+ }
+ a.conn.StoreSession(e.SessionState)
case QUICResumeSession:
if a.onResumeSession != nil {
a.onResumeSession(e.SessionState)
@@ -154,8 +159,8 @@ }
}
func TestQUICConnection(t *testing.T) {
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, config)
cli.conn.SetTransportParameters(nil)
@@ -196,13 +201,13 @@ }
}
func TestQUICSessionResumption(t *testing.T) {
- clientConfig := testConfig.Clone()
- clientConfig.MinVersion = VersionTLS13
- clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
- clientConfig.ServerName = "example.go.dev"
+ clientConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ clientConfig.TLSConfig.MinVersion = VersionTLS13
+ clientConfig.TLSConfig.ClientSessionCache = NewLRUClientSessionCache(1)
+ clientConfig.TLSConfig.ServerName = "example.go.dev"
- serverConfig := testConfig.Clone()
- serverConfig.MinVersion = VersionTLS13
+ serverConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ serverConfig.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, clientConfig)
cli.conn.SetTransportParameters(nil)
@@ -228,13 +233,13 @@ }
}
func TestQUICFragmentaryData(t *testing.T) {
- clientConfig := testConfig.Clone()
- clientConfig.MinVersion = VersionTLS13
- clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
- clientConfig.ServerName = "example.go.dev"
+ clientConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ clientConfig.TLSConfig.MinVersion = VersionTLS13
+ clientConfig.TLSConfig.ClientSessionCache = NewLRUClientSessionCache(1)
+ clientConfig.TLSConfig.ServerName = "example.go.dev"
- serverConfig := testConfig.Clone()
- serverConfig.MinVersion = VersionTLS13
+ serverConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ serverConfig.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, clientConfig)
cli.conn.SetTransportParameters(nil)
@@ -260,8 +265,8 @@ }
func TestQUICPostHandshakeClientAuthentication(t *testing.T) {
// RFC 9001, Section 4.4.
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, config)
cli.conn.SetTransportParameters(nil)
srv := newTestQUICServer(t, config)
@@ -288,8 +293,8 @@ }
func TestQUICPostHandshakeKeyUpdate(t *testing.T) {
// RFC 9001, Section 6.
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, config)
cli.conn.SetTransportParameters(nil)
srv := newTestQUICServer(t, config)
@@ -312,8 +317,8 @@ }
}
func TestQUICPostHandshakeMessageTooLarge(t *testing.T) {
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, config)
cli.conn.SetTransportParameters(nil)
srv := newTestQUICServer(t, config)
@@ -334,13 +339,13 @@ }
}
func TestQUICHandshakeError(t *testing.T) {
- clientConfig := testConfig.Clone()
- clientConfig.MinVersion = VersionTLS13
- clientConfig.InsecureSkipVerify = false
- clientConfig.ServerName = "name"
+ clientConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ clientConfig.TLSConfig.MinVersion = VersionTLS13
+ clientConfig.TLSConfig.InsecureSkipVerify = false
+ clientConfig.TLSConfig.ServerName = "name"
- serverConfig := testConfig.Clone()
- serverConfig.MinVersion = VersionTLS13
+ serverConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ serverConfig.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, clientConfig)
cli.conn.SetTransportParameters(nil)
@@ -360,9 +365,9 @@ // Test that QUICConn.ConnectionState can be used during the handshake,
// and that it reports the application protocol as soon as it has been
// negotiated.
func TestQUICConnectionState(t *testing.T) {
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
- config.NextProtos = []string{"h3"}
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
+ config.TLSConfig.NextProtos = []string{"h3"}
cli := newTestQUICClient(t, config)
cli.conn.SetTransportParameters(nil)
srv := newTestQUICServer(t, config)
@@ -391,10 +396,10 @@ func TestQUICStartContextPropagation(t *testing.T) {
const key = "key"
const value = "value"
ctx := context.WithValue(context.Background(), key, value)
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
calls := 0
- config.GetConfigForClient = func(info *ClientHelloInfo) (*Config, error) {
+ config.TLSConfig.GetConfigForClient = func(info *ClientHelloInfo) (*Config, error) {
calls++
got, _ := info.Context().Value(key).(string)
if got != value {
@@ -415,13 +420,13 @@ }
}
func TestQUICDelayedTransportParameters(t *testing.T) {
- clientConfig := testConfig.Clone()
- clientConfig.MinVersion = VersionTLS13
- clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
- clientConfig.ServerName = "example.go.dev"
+ clientConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ clientConfig.TLSConfig.MinVersion = VersionTLS13
+ clientConfig.TLSConfig.ClientSessionCache = NewLRUClientSessionCache(1)
+ clientConfig.TLSConfig.ServerName = "example.go.dev"
- serverConfig := testConfig.Clone()
- serverConfig.MinVersion = VersionTLS13
+ serverConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ serverConfig.TLSConfig.MinVersion = VersionTLS13
cliParams := "client params"
srvParams := "server params"
@@ -449,8 +454,8 @@ }
}
func TestQUICEmptyTransportParameters(t *testing.T) {
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, config)
cli.conn.SetTransportParameters(nil)
@@ -475,8 +480,8 @@ }
}
func TestQUICCanceledWaitingForData(t *testing.T) {
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, config)
cli.conn.SetTransportParameters(nil)
cli.conn.Start(context.Background())
@@ -489,8 +494,8 @@ }
}
func TestQUICCanceledWaitingForTransportParams(t *testing.T) {
- config := testConfig.Clone()
- config.MinVersion = VersionTLS13
+ config := &QUICConfig{TLSConfig: testConfig.Clone()}
+ config.TLSConfig.MinVersion = VersionTLS13
cli := newTestQUICClient(t, config)
cli.conn.Start(context.Background())
for cli.conn.NextEvent().Kind != QUICTransportParametersRequired {
@@ -502,15 +507,15 @@ }
}
func TestQUICEarlyData(t *testing.T) {
- clientConfig := testConfig.Clone()
- clientConfig.MinVersion = VersionTLS13
- clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
- clientConfig.ServerName = "example.go.dev"
- clientConfig.NextProtos = []string{"h3"}
+ clientConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ clientConfig.TLSConfig.MinVersion = VersionTLS13
+ clientConfig.TLSConfig.ClientSessionCache = NewLRUClientSessionCache(1)
+ clientConfig.TLSConfig.ServerName = "example.go.dev"
+ clientConfig.TLSConfig.NextProtos = []string{"h3"}
- serverConfig := testConfig.Clone()
- serverConfig.MinVersion = VersionTLS13
- serverConfig.NextProtos = []string{"h3"}
+ serverConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ serverConfig.TLSConfig.MinVersion = VersionTLS13
+ serverConfig.TLSConfig.NextProtos = []string{"h3"}
cli := newTestQUICClient(t, clientConfig)
cli.conn.SetTransportParameters(nil)
@@ -528,7 +533,14 @@ cli2 := newTestQUICClient(t, clientConfig)
cli2.conn.SetTransportParameters(nil)
srv2 := newTestQUICServer(t, serverConfig)
srv2.conn.SetTransportParameters(nil)
- if err := runTestQUICConnection(context.Background(), cli2, srv2, nil); err != nil {
+ onEvent := func(e QUICEvent, src, dst *testQUICConn) bool {
+ switch e.Kind {
+ case QUICStoreSession, QUICResumeSession:
+ t.Errorf("with EnableSessionEvents=false, got unexpected event %v", e.Kind)
+ }
+ return false
+ }
+ if err := runTestQUICConnection(context.Background(), cli2, srv2, onEvent); err != nil {
t.Fatalf("error during second connection handshake: %v", err)
}
if !cli2.conn.ConnectionState().DidResume {
@@ -557,15 +569,17 @@ })
}
func testQUICEarlyDataDeclined(t *testing.T, server bool) {
- clientConfig := testConfig.Clone()
- clientConfig.MinVersion = VersionTLS13
- clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
- clientConfig.ServerName = "example.go.dev"
- clientConfig.NextProtos = []string{"h3"}
+ clientConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ clientConfig.EnableSessionEvents = true
+ clientConfig.TLSConfig.MinVersion = VersionTLS13
+ clientConfig.TLSConfig.ClientSessionCache = NewLRUClientSessionCache(1)
+ clientConfig.TLSConfig.ServerName = "example.go.dev"
+ clientConfig.TLSConfig.NextProtos = []string{"h3"}
- serverConfig := testConfig.Clone()
- serverConfig.MinVersion = VersionTLS13
- serverConfig.NextProtos = []string{"h3"}
+ serverConfig := &QUICConfig{TLSConfig: testConfig.Clone()}
+ serverConfig.EnableSessionEvents = true
+ serverConfig.TLSConfig.MinVersion = VersionTLS13
+ serverConfig.TLSConfig.NextProtos = []string{"h3"}
cli := newTestQUICClient(t, clientConfig)
cli.conn.SetTransportParameters(nil)
diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go
index da310bfb12a0bc38f82508d10de348e6a6dc80e2..d0892e80fc28d5e54275751e2861306f926698bd 100644
--- a/src/database/sql/driver/driver.go
+++ b/src/database/sql/driver/driver.go
@@ -415,7 +415,7 @@ // Deprecated: Drivers should implement [NamedValueChecker].
type ColumnConverter interface {
// ColumnConverter returns a ValueConverter for the provided
// column index. If the type of a specific column isn't known
- // or shouldn't be handled specially, DefaultValueConverter
+ // or shouldn't be handled specially, [DefaultParameterConverter]
// can be returned.
ColumnConverter(idx int) ValueConverter
}
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index efceecdf82b04dcc764891d43834969791d842ef..f8205704e38b7ffa86b21816ae96ef4374b1184c 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -73,8 +73,7 @@ // To unmarshal a JSON object into a map, Unmarshal first establishes a map to
// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
// reuses the existing map, keeping existing entries. Unmarshal then stores
// key-value pairs from the JSON object into the map. The map's key type must
-// either be any string type, an integer, implement [json.Unmarshaler], or
-// implement [encoding.TextUnmarshaler].
+// either be any string type, an integer, or implement [encoding.TextUnmarshaler].
//
// If the JSON-encoded data contain a syntax error, Unmarshal returns a [SyntaxError].
//
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index cb28feb279f6c0d5bb23e056b024f9473a188f46..7bee1a6805f4dc2d836a9afe1f8cb28b0930b325 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -141,7 +141,7 @@ // string, an integer type, or implement [encoding.TextMarshaler]. The map keys
// are sorted and used as JSON object keys by applying the following rules,
// subject to the UTF-8 coercion described for string values above:
// - keys of any string type are used directly
-// - [encoding.TextMarshalers] are marshaled
+// - keys that implement [encoding.TextMarshaler] are marshaled
// - integer keys are converted to strings
//
// Pointer values encode as the value pointed to.
diff --git a/src/go.mod b/src/go.mod
index b38dee7e6ddc282b893657f7d561e126b82cada9..789f5aaa1d3e26960da1fa9189a8f40cf6225052 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -8,6 +8,6 @@ golang.org/x/net v0.25.1-0.20240603202750-6249541f2a6c
)
require (
- golang.org/x/sys v0.21.0 // indirect
+ golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
)
diff --git a/src/go.sum b/src/go.sum
index c5eab7d4b2f93b3443f296c14d2437192f364a1c..a75ea98c7312df25b5111de8a92ce5df5ca27fcc 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -2,7 +2,7 @@ golang.org/x/crypto v0.23.1-0.20240603234054-0b431c7de36a h1:37MIv+iGfwMYzWJECGyrPCtd5nuqcciRUeJfkNCkCf0=
golang.org/x/crypto v0.23.1-0.20240603234054-0b431c7de36a/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.25.1-0.20240603202750-6249541f2a6c h1:CR/7/SLUhIJw6g675eeoDiwggElO2MV9rGkNYjqi8GM=
golang.org/x/net v0.25.1-0.20240603202750-6249541f2a6c/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 84b0096c770f4420d1aad5980e115b674ea03aa8..9146cae492e8ac62e3d51def288f81c0f0529b15 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -642,6 +642,9 @@
FMT
< internal/txtar;
+ CRYPTO-MATH, testing
+ < crypto/internal/cryptotest;
+
# v2 execution trace parser.
FMT
< internal/trace/event;
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
index c99c9a9550da24e6d938751ddd96a1cff303315c..3f459d3883017efcd4e78d482948588376d43e95 100644
--- a/src/go/types/issues_test.go
+++ b/src/go/types/issues_test.go
@@ -1102,3 +1102,32 @@ // even though the (module) Go version is set to go1.17.
conf := Config{GoVersion: "go1.17"}
mustTypecheck(src, &conf, nil)
}
+
+func TestIssue68334(t *testing.T) {
+ const src = `
+package p
+
+func f(x int) {
+ for i, j := range x {
+ _, _ = i, j
+ }
+ var a, b int
+ for a, b = range x {
+ _, _ = a, b
+ }
+}
+`
+
+ got := ""
+ conf := Config{
+ GoVersion: "go1.21", // #68334 requires GoVersion <= 1.21
+ Error: func(err error) { got += err.Error() + "\n" }, // #68334 requires Error != nil
+ }
+ typecheck(src, &conf, nil) // do not crash
+
+ want := "p:5:20: cannot range over x (variable of type int): requires go1.22 or later\n" +
+ "p:9:19: cannot range over x (variable of type int): requires go1.22 or later\n"
+ if got != want {
+ t.Errorf("got: %s want: %s", got, want)
+ }
+}
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
index 215b20160d8e11b1240a6beaf4f3532da8da91b8..c9f7a4f929ad50c14de4150411d50f3afe5df27f 100644
--- a/src/go/types/stmt.go
+++ b/src/go/types/stmt.go
@@ -922,14 +922,15 @@ assert(obj.typ == nil)
// initialize lhs iteration variable, if any
typ := rhs[i]
- if typ == nil {
+ if typ == nil || typ == Typ[Invalid] {
+ // typ == Typ[Invalid] can happen if allowVersion fails.
obj.typ = Typ[Invalid]
obj.used = true // don't complain about unused variable
continue
}
if rangeOverInt {
- assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
+ assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
check.initVar(obj, &x, "range clause")
} else {
var y operand
@@ -959,12 +960,12 @@ }
// assign to lhs iteration variable, if any
typ := rhs[i]
- if typ == nil {
+ if typ == nil || typ == Typ[Invalid] {
continue
}
if rangeOverInt {
- assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
+ assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
check.assignVar(lhs, nil, &x, "range clause")
// If the assignment succeeded, if x was untyped before, it now
// has a type inferred via the assignment. It must be an integer.
diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go
index 58a02de86029b120e987536ea30361006351890f..789b63d7a15aaebd127c60a41553f057fcca55bc 100644
--- a/src/go/types/typeparam.go
+++ b/src/go/types/typeparam.go
@@ -28,8 +28,8 @@ bound Type // any type, but underlying is eventually *Interface for correct programs (see TypeParam.iface)
}
// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
-// or Signature type by calling SetTypeParams. Setting a type parameter on more
-// than one type will result in a panic.
+// type by calling SetTypeParams. Setting a type parameter on more than one type
+// will result in a panic.
//
// The constraint argument can be nil, and set later via SetConstraint. If the
// constraint is non-nil, it must be fully defined.
diff --git a/src/internal/coverage/defs.go b/src/internal/coverage/defs.go
index 340ac9563559d016ca2f42189284b143d50d52e7..1ef47638e626a4a7ba1c5c6c8cf4426995162cc2 100644
--- a/src/internal/coverage/defs.go
+++ b/src/internal/coverage/defs.go
@@ -267,7 +267,7 @@ // in a "go test -coverpkg=... ..." run. This constant is shared
// by the Go command and by the coverage runtime.
const MetaFilesFileName = "metafiles.txt"
-// MetaFilePaths contains information generated by the Go command and
+// MetaFileCollection contains information generated by the Go command and
// the read in by coverage test support functions within an executing
// "go test -cover" binary.
type MetaFileCollection struct {
diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go
index 4c084635fbe1b0c4f0f68504ef2b5edd8a420b1c..a802ac9c3708d10065346c6e0ee80f8f312f12ab 100644
--- a/src/internal/godebugs/table.go
+++ b/src/internal/godebugs/table.go
@@ -25,7 +25,7 @@ //
// Note: After adding entries to this table, update the list in doc/godebug.md as well.
// (Otherwise the test in this package will fail.)
var All = []Info{
- {Name: "asynctimerchan", Package: "time", Changed: 23, Old: "1", Opaque: true},
+ {Name: "asynctimerchan", Package: "time", Changed: 23, Old: "1"},
{Name: "execerrdot", Package: "os/exec"},
{Name: "gocachehash", Package: "cmd/go"},
{Name: "gocachetest", Package: "cmd/go"},
diff --git a/src/io/pipe_test.go b/src/io/pipe_test.go
index a8c4e306cc35ec38fa68298ac4b8816db4fe8237..fcf94d52d21bcd4234c3492e6f39910fa2abf582 100644
--- a/src/io/pipe_test.go
+++ b/src/io/pipe_test.go
@@ -421,3 +421,21 @@ }
slices.SortFunc(groups, bytes.Compare)
return bytes.Join(groups, nil)
}
+
+var (
+ rSink *PipeReader
+ wSink *PipeWriter
+)
+
+func TestPipeAllocations(t *testing.T) {
+ numAllocs := testing.AllocsPerRun(10, func() {
+ rSink, wSink = Pipe()
+ })
+
+ // go.dev/cl/473535 claimed Pipe() should only do 2 allocations,
+ // plus the 2 escaping to heap for simulating real world usages.
+ expectedAllocs := 4
+ if int(numAllocs) > expectedAllocs {
+ t.Fatalf("too many allocations for io.Pipe() call: %f", numAllocs)
+ }
+}
diff --git a/src/iter/iter.go b/src/iter/iter.go
index 4ea919b0724f6dbfb7235c52bd2e5128fdc7e56f..14fd8f8115f3f6f73d0b3d8f284d263b68c657f6 100644
--- a/src/iter/iter.go
+++ b/src/iter/iter.go
@@ -31,7 +31,7 @@
Iterator functions are most often called by a range loop, as in:
func PrintAll[V any](seq iter.Seq[V]) {
- for _, v := range seq {
+ for v := range seq {
fmt.Println(v)
}
}
@@ -92,9 +92,8 @@ sequence only once. These “single-use iterators” typically report values
from a data stream that cannot be rewound to start over.
Calling the iterator again after stopping early may continue the
stream, but calling it again after the sequence is finished will yield
-no values at all, immediately returning true. Doc comments for
-functions or methods that return single-use iterators should document
-this fact:
+no values at all. Doc comments for functions or methods that return
+single-use iterators should document this fact:
// Lines returns an iterator over lines read from r.
// It returns a single-use iterator.
@@ -119,17 +118,24 @@ For example:
// Pairs returns an iterator over successive pairs of values from seq.
func Pairs[V any](seq iter.Seq[V]) iter.Seq2[V, V] {
- return func(yield func(V, V) bool) bool {
+ return func(yield func(V, V) bool) {
next, stop := iter.Pull(seq)
defer stop()
- v1, ok1 := next()
- v2, ok2 := next()
- for ok1 || ok2 {
+ for {
+ v1, ok1 := next()
+ if !ok1 {
+ return
+ }
+ v2, ok2 := next()
+ // If ok2 is false, v2 should be the
+ // zero value; yield one last pair.
if !yield(v1, v2) {
- return false
+ return
+ }
+ if !ok2 {
+ return
}
}
- return true
}
}
diff --git a/src/log/slog/internal/buffer/buffer.go b/src/log/slog/internal/buffer/buffer.go
index 310ec37d4a12156814874e2db084057f008031ec..110c6281ab29ab610e846e8bacb91a568e5417cd 100644
--- a/src/log/slog/internal/buffer/buffer.go
+++ b/src/log/slog/internal/buffer/buffer.go
@@ -7,7 +7,10 @@ package buffer
import "sync"
-// buffer adapted from go/src/fmt/print.go
+// Buffer is a byte buffer.
+//
+// This implementation is adapted from the unexported type buffer
+// in go/src/fmt/print.go.
type Buffer []byte
// Having an initial size gives a dramatic speedup.
diff --git a/src/math/floor_asm.go b/src/math/floor_asm.go
index 5cb45f5a7e84e16f1e08884892c95293fd131d79..fb419d6da2f6bfc98fcf8d12a82b39dc987f86d0 100644
--- a/src/math/floor_asm.go
+++ b/src/math/floor_asm.go
@@ -2,7 +2,7 @@ // Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build 386 || amd64 || arm64 || ppc64 || ppc64le || riscv64 || s390x || wasm
+//go:build 386 || amd64 || arm64 || ppc64 || ppc64le || s390x || wasm
package math
diff --git a/src/math/floor_noasm.go b/src/math/floor_noasm.go
index 6754ca8fc806e18cba71cd55c913175468472fad..5641c7ea0a49caf563cf496e2be234612dd0d2c8 100644
--- a/src/math/floor_noasm.go
+++ b/src/math/floor_noasm.go
@@ -2,7 +2,7 @@ // Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build !386 && !amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x && !wasm
+//go:build !386 && !amd64 && !arm64 && !ppc64 && !ppc64le && !s390x && !wasm
package math
diff --git a/src/math/floor_riscv64.s b/src/math/floor_riscv64.s
deleted file mode 100644
index 62ce963781aa4727e946d0e41272d356d0226305..0000000000000000000000000000000000000000
--- a/src/math/floor_riscv64.s
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2023 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.
-
-#include "textflag.h"
-
-#define PosInf 0x7FF0000000000000
-
-// The rounding mode of RISC-V is different from Go spec.
-
-#define ROUNDFN(NAME, MODE) \
-TEXT NAME(SB),NOSPLIT,$0; \
- MOVD x+0(FP), F0; \
- /* whether x is NaN */; \
- FEQD F0, F0, X6; \
- BNEZ X6, 3(PC); \
- /* return NaN if x is NaN */; \
- MOVD F0, ret+8(FP); \
- RET; \
- MOV $PosInf, X6; \
- FMVDX X6, F1; \
- FABSD F0, F2; \
- /* if abs(x) > +Inf, return Inf instead of round(x) */; \
- FLTD F1, F2, X6; \
- /* Inf should keep same signed with x then return */; \
- BEQZ X6, 3(PC); \
- FCVTLD.MODE F0, X6; \
- FCVTDL X6, F1; \
- /* rounding will drop signed bit in RISCV, restore it */; \
- FSGNJD F0, F1, F0; \
- MOVD F0, ret+8(FP); \
- RET
-
-// func archFloor(x float64) float64
-ROUNDFN(·archFloor, RDN)
-
-// func archCeil(x float64) float64
-ROUNDFN(·archCeil, RUP)
-
-// func archTrunc(x float64) float64
-ROUNDFN(·archTrunc, RTZ)
diff --git a/src/net/http/filetransport.go b/src/net/http/filetransport.go
index 7384b22fbe927c4781b6d1161a6d56673e8fe0fd..b08bae63487dab5506b6c52d4198ba77ad4bfdac 100644
--- a/src/net/http/filetransport.go
+++ b/src/net/http/filetransport.go
@@ -35,7 +35,7 @@
// NewFileTransportFS returns a new [RoundTripper], serving the provided
// file system fsys. The returned RoundTripper ignores the URL host in its
// incoming requests, as well as most other properties of the
-// request.
+// request. The files provided by fsys must implement [io.Seeker].
//
// The typical use case for NewFileTransportFS is to register the "file"
// protocol with a [Transport], as in:
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index 70653550f027f61bcbdfe9738b05dcc80ea0b485..3a716fbd2cc7f8d480c831e330ed4f6318d2d33f 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -819,6 +819,7 @@ }
// ServeFileFS replies to the request with the contents
// of the named file or directory from the file system fsys.
+// The files provided by fsys must implement [io.Seeker].
//
// If the provided name is constructed from user input, it should be
// sanitized before calling [ServeFileFS].
@@ -965,6 +966,7 @@ }
// FileServerFS returns a handler that serves HTTP requests
// with the contents of the file system fsys.
+// The files provided by fsys must implement [io.Seeker].
//
// As a special case, the returned file server redirects any request
// ending in "/index.html" to the same path, without the final
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 456615a79ad59b7e95eff0d69d2c7f03ac850a25..ad1b5a620b07ae1d6145ee1bcc7a1fc0f7158d27 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -377,6 +377,8 @@
// Clone returns a deep copy of r with its context changed to ctx.
// The provided ctx must be non-nil.
//
+// Clone only makes a shallow copy of the Body field.
+//
// For an outgoing client request, the context controls the entire
// lifetime of a request and its response: obtaining a connection,
// sending the request, and reading the response headers and body.
diff --git a/src/net/http/routing_tree_test.go b/src/net/http/routing_tree_test.go
index 7de6b19507230ee4fa416eac077a666adfd24d29..f3f216357d91b6125581f4b5e2ef86d977f2171d 100644
--- a/src/net/http/routing_tree_test.go
+++ b/src/net/http/routing_tree_test.go
@@ -7,6 +7,7 @@
import (
"fmt"
"io"
+ "maps"
"strings"
"testing"
@@ -261,9 +262,7 @@ } {
t.Run(test.name, func(t *testing.T) {
ms := map[string]bool{}
test.tree.matchingMethods(test.host, test.path, ms)
- keys := mapKeys(ms)
- slices.Sort(keys)
- got := strings.Join(keys, ",")
+ got := strings.Join(slices.Sorted(maps.Keys(ms)), ",")
if got != test.want {
t.Errorf("got %s, want %s", got, test.want)
}
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 3ec10c2f14da56d0ac2c3cfb96db944919658373..b2858ba8f2b55956331e2f66c6552c4a33c66d66 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -613,6 +613,22 @@ t.Errorf("got %d, want %d", g, w)
}
}
+// Test that we don't attempt trailing-slash response 405 on a path that already has
+// a trailing slash.
+// See issue #67657.
+func TestMuxNoSlash405WithTrailingSlash(t *testing.T) {
+ mux := NewServeMux()
+ mux.HandleFunc("GET /{x}/", func(w ResponseWriter, r *Request) {
+ fmt.Fprintln(w, "ok")
+ })
+ w := httptest.NewRecorder()
+ req, _ := NewRequest("GET", "/", nil)
+ mux.ServeHTTP(w, req)
+ if g, w := w.Code, 404; g != w {
+ t.Errorf("got %d, want %d", g, w)
+ }
+}
+
func TestShouldRedirectConcurrency(t *testing.T) { run(t, testShouldRedirectConcurrency) }
func testShouldRedirectConcurrency(t *testing.T, mode testMode) {
mux := NewServeMux()
diff --git a/src/net/http/server.go b/src/net/http/server.go
index a5e98f1d957dcba585d501cf3dcafc833d2e5ee3..1ff72a04550c42b1fdb0579a6b2ae373cbb2dadf 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -16,6 +16,7 @@ "fmt"
"internal/godebug"
"io"
"log"
+ "maps"
"math/rand"
"net"
"net/textproto"
@@ -2721,19 +2722,10 @@ defer mux.mu.RUnlock()
ms := map[string]bool{}
mux.tree.matchingMethods(host, path, ms)
// matchOrRedirect will try appending a trailing slash if there is no match.
- mux.tree.matchingMethods(host, path+"/", ms)
- methods := mapKeys(ms)
- slices.Sort(methods)
- return methods
-}
-
-// TODO(jba): replace with maps.Keys when it is defined.
-func mapKeys[K comparable, V any](m map[K]V) []K {
- var ks []K
- for k := range m {
- ks = append(ks, k)
+ if !strings.HasSuffix(path, "/") {
+ mux.tree.matchingMethods(host, path+"/", ms)
}
- return ks
+ return slices.Sorted(maps.Keys(ms))
}
// ServeHTTP dispatches the request to the handler whose
diff --git a/src/net/netip/export_test.go b/src/net/netip/export_test.go
index 4febcad89365446886660d7728ae7debed323161..b2fae1aa47eedc2c9fcdfe38af20b2bf2495b42e 100644
--- a/src/net/netip/export_test.go
+++ b/src/net/netip/export_test.go
@@ -16,6 +16,10 @@ type Uint128 = uint128
type AddrDetail = addrDetail
+func MakeAddrDetail(isV6 bool, zoneV6 string) AddrDetail {
+ return AddrDetail{isV6: isV6, zoneV6: zoneV6}
+}
+
func Mk128(hi, lo uint64) Uint128 {
return uint128{hi, lo}
}
diff --git a/src/net/netip/netip.go b/src/net/netip/netip.go
index 57063eeb718a27e447ffe9d6f5310b3d4885ac82..a1e93cb29bfbd9427f51debc43f89df841d8bd74 100644
--- a/src/net/netip/netip.go
+++ b/src/net/netip/netip.go
@@ -59,8 +59,8 @@ }
// addrDetail represents the details of an Addr, like address family and IPv6 zone.
type addrDetail struct {
- IsV6 bool // IPv4 is false, IPv6 is true.
- ZoneV6 string // != "" only if IsV6 is true.
+ isV6 bool // IPv4 is false, IPv6 is true.
+ zoneV6 string // != "" only if IsV6 is true.
}
// z0, z4, and z6noz are sentinel Addr.z values.
@@ -68,7 +68,7 @@ // See the Addr type's field docs.
var (
z0 unique.Handle[addrDetail]
z4 = unique.Make(addrDetail{})
- z6noz = unique.Make(addrDetail{IsV6: true})
+ z6noz = unique.Make(addrDetail{isV6: true})
)
// IPv6LinkLocalAllNodes returns the IPv6 link-local all nodes multicast
@@ -410,7 +410,7 @@ func (ip Addr) Zone() string {
if ip.z == z0 {
return ""
}
- return ip.z.Value().ZoneV6
+ return ip.z.Value().zoneV6
}
// Compare returns an integer comparing two IPs.
@@ -495,7 +495,7 @@ if zone == "" {
ip.z = z6noz
return ip
}
- ip.z = unique.Make(addrDetail{IsV6: true, ZoneV6: zone})
+ ip.z = unique.Make(addrDetail{isV6: true, zoneV6: zone})
return ip
}
diff --git a/src/net/netip/netip_test.go b/src/net/netip/netip_test.go
index ad0e7542082a23c962c605a627ca6120e8fce0a1..e1a0a83f64511d97fc8681e024732bd032fd2abf 100644
--- a/src/net/netip/netip_test.go
+++ b/src/net/netip/netip_test.go
@@ -112,18 +112,18 @@ },
// IPv6 with a zone specifier.
{
in: "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b%eth0",
- ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b430b), unique.Make(AddrDetail{IsV6: true, ZoneV6: "eth0"})),
+ ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b430b), unique.Make(MakeAddrDetail(true, "eth0"))),
},
// IPv6 with dotted decimal and zone specifier.
{
in: "1:2::ffff:192.168.140.255%eth1",
- ip: MkAddr(Mk128(0x0001000200000000, 0x0000ffffc0a88cff), unique.Make(AddrDetail{IsV6: true, ZoneV6: "eth1"})),
+ ip: MkAddr(Mk128(0x0001000200000000, 0x0000ffffc0a88cff), unique.Make(MakeAddrDetail(true, "eth1"))),
str: "1:2::ffff:c0a8:8cff%eth1",
},
// 4-in-6 with zone
{
in: "::ffff:192.168.140.255%eth1",
- ip: MkAddr(Mk128(0, 0x0000ffffc0a88cff), unique.Make(AddrDetail{IsV6: true, ZoneV6: "eth1"})),
+ ip: MkAddr(Mk128(0, 0x0000ffffc0a88cff), unique.Make(MakeAddrDetail(true, "eth1"))),
str: "::ffff:192.168.140.255%eth1",
},
// IPv6 with capital letters.
@@ -893,6 +893,15 @@
{mustIP("::1%a"), mustIP("::1%b"), true},
{mustIP("::1%a"), mustIP("::1%a"), false},
{mustIP("::1%b"), mustIP("::1%a"), false},
+
+ // For Issue 68113, verify that an IPv4 address and a
+ // v4-mapped-IPv6 address differing only in their zone
+ // pointer are unequal via all three of
+ // ==/Compare/reflect.DeepEqual. In Go 1.22 and
+ // earlier, these were accidentally equal via
+ // DeepEqual due to their zone pointers (z) differing
+ // but pointing to identical structures.
+ {mustIP("::ffff:11.1.1.12"), mustIP("11.1.1.12"), false},
}
for _, tt := range tests {
got := tt.a.Less(tt.b)
@@ -919,6 +928,12 @@ got2 := tt.b.Less(tt.a)
if got2 {
t.Errorf("Less(%q, %q) was correctly %v, but so was Less(%q, %q)", tt.a, tt.b, got, tt.b, tt.a)
}
+ }
+
+ // Also check reflect.DeepEqual. See issue 68113.
+ deepEq := reflect.DeepEqual(tt.a, tt.b)
+ if (cmp == 0) != deepEq {
+ t.Errorf("%q and %q differ in == (%v) vs reflect.DeepEqual (%v)", tt.a, tt.b, cmp == 0, deepEq)
}
}
@@ -1723,7 +1738,7 @@ {"v6_zone", "1:2::ffff:192.168.140.255%eth1"},
}
func BenchmarkParseAddr(b *testing.B) {
- sinkInternValue = unique.Make(AddrDetail{IsV6: true, ZoneV6: "eth1"}) // Pin to not benchmark the intern package
+ sinkInternValue = unique.Make(MakeAddrDetail(true, "eth1")) // Pin to not benchmark the intern package
for _, test := range parseBenchInputs {
b.Run(test.name, func(b *testing.B) {
b.ReportAllocs()
diff --git a/src/os/error.go b/src/os/error.go
index 5a824a9e0e1fc9664131f08a9d8e9247ffadea3f..284b9e992cd425415114871476e74bccfc39d1da 100644
--- a/src/os/error.go
+++ b/src/os/error.go
@@ -71,7 +71,7 @@ }
return &SyscallError{syscall, err}
}
-// IsExist returns a boolean indicating whether the error is known to report
+// IsExist returns a boolean indicating whether its argument is known to report
// that a file or directory already exists. It is satisfied by [ErrExist] as
// well as some syscall errors.
//
@@ -81,7 +81,7 @@ func IsExist(err error) bool {
return underlyingErrorIs(err, ErrExist)
}
-// IsNotExist returns a boolean indicating whether the error is known to
+// IsNotExist returns a boolean indicating whether its argument is known to
// report that a file or directory does not exist. It is satisfied by
// [ErrNotExist] as well as some syscall errors.
//
@@ -91,7 +91,7 @@ func IsNotExist(err error) bool {
return underlyingErrorIs(err, ErrNotExist)
}
-// IsPermission returns a boolean indicating whether the error is known to
+// IsPermission returns a boolean indicating whether its argument is known to
// report that permission is denied. It is satisfied by [ErrPermission] as well
// as some syscall errors.
//
@@ -101,7 +101,7 @@ func IsPermission(err error) bool {
return underlyingErrorIs(err, ErrPermission)
}
-// IsTimeout returns a boolean indicating whether the error is known
+// IsTimeout returns a boolean indicating whether its argument is known
// to report that a timeout occurred.
//
// This function predates [errors.Is], and the notion of whether an
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index 50ed3a8d165886c094bbd53e2ecc4ee9729146ad..da9f68fe28f14b74d2f15ad00481f80a79e387c6 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -334,8 +334,10 @@ // and https://go.dev/issue/43724 for more context.
lookPathErr error
// cachedLookExtensions caches the result of calling lookExtensions.
+ // It is set when Command is called with an absolute path, letting it do
+ // the work of resolving the extension, so Start doesn't need to do it again.
// This is only used on Windows.
- cachedLookExtensions string
+ cachedLookExtensions struct{ in, out string }
}
// A ctxResult reports the result of watching the Context associated with a
@@ -436,12 +438,12 @@ // or verify an extension that is already present.
// Since the path is absolute, its extension should be unambiguous
// and independent of cmd.Dir, and we can go ahead and cache the lookup now.
//
- // Note that we cannot add an extension here for relative paths, because
- // cmd.Dir may be set after we return from this function and that may cause
- // the command to resolve to a different extension.
- lp, err := lookExtensions(name, "")
- cmd.cachedLookExtensions = lp
- if err != nil {
+ // Note that we don't cache anything here for relative paths, because
+ // cmd.Dir may be set after we return from this function and that may
+ // cause the command to resolve to a different extension.
+ if lp, err := lookExtensions(name, ""); err == nil {
+ cmd.cachedLookExtensions.in, cmd.cachedLookExtensions.out = name, lp
+ } else {
cmd.Err = err
}
}
@@ -642,29 +644,32 @@ }
return c.Err
}
lp := c.Path
- if c.cachedLookExtensions != "" {
- lp = c.cachedLookExtensions
- }
- if runtime.GOOS == "windows" && c.cachedLookExtensions == "" {
- // If c.Path is relative, we had to wait until now
- // to resolve it in case c.Dir was changed.
- // (If it is absolute, we already resolved its extension in Command
- // and shouldn't need to do so again.)
- //
- // Unfortunately, we cannot write the result back to c.Path because programs
- // may assume that they can call Start concurrently with reading the path.
- // (It is safe and non-racy to do so on Unix platforms, and users might not
- // test with the race detector on all platforms;
- // see https://go.dev/issue/62596.)
- //
- // So we will pass the fully resolved path to os.StartProcess, but leave
- // c.Path as is: missing a bit of logging information seems less harmful
- // than triggering a surprising data race, and if the user really cares
- // about that bit of logging they can always use LookPath to resolve it.
- var err error
- lp, err = lookExtensions(c.Path, c.Dir)
- if err != nil {
- return err
+ if runtime.GOOS == "windows" {
+ if c.Path == c.cachedLookExtensions.in {
+ // If Command was called with an absolute path, we already resolved
+ // its extension and shouldn't need to do so again (provided c.Path
+ // wasn't set to another value between the calls to Command and Start).
+ lp = c.cachedLookExtensions.out
+ } else {
+ // If *Cmd was made without using Command at all, or if Command was
+ // called with a relative path, we had to wait until now to resolve
+ // it in case c.Dir was changed.
+ //
+ // Unfortunately, we cannot write the result back to c.Path because programs
+ // may assume that they can call Start concurrently with reading the path.
+ // (It is safe and non-racy to do so on Unix platforms, and users might not
+ // test with the race detector on all platforms;
+ // see https://go.dev/issue/62596.)
+ //
+ // So we will pass the fully resolved path to os.StartProcess, but leave
+ // c.Path as is: missing a bit of logging information seems less harmful
+ // than triggering a surprising data race, and if the user really cares
+ // about that bit of logging they can always use LookPath to resolve it.
+ var err error
+ lp, err = lookExtensions(c.Path, c.Dir)
+ if err != nil {
+ return err
+ }
}
}
if c.Cancel != nil && c.ctx == nil {
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index dbe59fea119e70153ea28968dd934864dfd22010..a0bb89e203ddf195b424207d6f83aa22d67ed3e0 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -1838,7 +1838,7 @@ }
func TestAbsPathExec(t *testing.T) {
testenv.MustHaveExec(t)
- testenv.MustHaveGoBuild(t) // must have GOROOT/bin/gofmt, but close enough
+ testenv.MustHaveGoBuild(t) // must have GOROOT/bin/{go,gofmt}
// A simple exec of a full path should work.
// Go 1.22 broke this on Windows, requiring ".exe"; see #66586.
@@ -1863,4 +1863,24 @@ err = cmd.Run()
if err == nil {
t.Errorf("using exec.Cmd{Path: %#q}: unexpected success", cmd.Path)
}
+
+ // A simple exec after modifying Cmd.Path should work.
+ // This broke on Windows. See go.dev/issue/68314.
+ t.Run("modified", func(t *testing.T) {
+ if exec.Command(filepath.Join(testenv.GOROOT(t), "bin/go")).Run() == nil {
+ // The implementation of the test case below relies on the go binary
+ // exiting with a non-zero exit code when run without any arguments.
+ // In the unlikely case that changes, we need to use another binary.
+ t.Fatal("test case needs updating to verify fix for go.dev/issue/68314")
+ }
+ exe1 := filepath.Join(testenv.GOROOT(t), "bin/go")
+ exe2 := filepath.Join(testenv.GOROOT(t), "bin/gofmt")
+ cmd := exec.Command(exe1)
+ cmd.Path = exe2
+ cmd.Args = []string{cmd.Path}
+ err := cmd.Run()
+ if err != nil {
+ t.Error("ran wrong binary")
+ }
+ })
}
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 7348a9f01caa1133a7a15dbf0ebd32a3d747a6dd..878974384dbcbaf1979c9d88047a6c93f5d6f1f7 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -158,28 +158,20 @@ }
return
}
-// localTmp returns a local temporary directory not on NFS.
-func localTmp() string {
- switch runtime.GOOS {
- case "android", "ios", "windows":
- return TempDir()
- }
- return "/tmp"
-}
-
-func newFile(testName string, t *testing.T) (f *File) {
- f, err := CreateTemp(localTmp(), "_Go_"+testName)
- if err != nil {
- t.Fatalf("TempFile %s: %s", testName, err)
- }
- return
-}
-
-func newDir(testName string, t *testing.T) (name string) {
- name, err := MkdirTemp(localTmp(), "_Go_"+testName)
+func newFile(t *testing.T) (f *File) {
+ t.Helper()
+ f, err := CreateTemp("", "_Go_"+t.Name())
if err != nil {
- t.Fatalf("TempDir %s: %s", testName, err)
+ t.Fatal(err)
}
+ t.Cleanup(func() {
+ if err := f.Close(); err != nil && !errors.Is(err, ErrClosed) {
+ t.Fatal(err)
+ }
+ if err := Remove(f.Name()); err != nil {
+ t.Fatal(err)
+ }
+ })
return
}
@@ -1276,9 +1268,7 @@ t.Skip("Chmod is not supported on " + runtime.GOOS)
}
t.Parallel()
- f := newFile("TestChmod", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
// Creation mode is read write
fm := FileMode(0456)
@@ -1314,9 +1304,7 @@
func TestFTruncate(t *testing.T) {
t.Parallel()
- f := newFile("TestFTruncate", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
checkSize(t, f, 0)
f.Write([]byte("hello, world\n"))
@@ -1336,9 +1324,7 @@
func TestTruncate(t *testing.T) {
t.Parallel()
- f := newFile("TestTruncate", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
checkSize(t, f, 0)
f.Write([]byte("hello, world\n"))
@@ -1375,15 +1361,21 @@ _, err = Stat(path)
assertPathError(t, path, err)
}
-// Use TempDir (via newFile) to make sure we're on a local file system,
-// so that timings are not distorted by latency and caching.
-// On NFS, timings can be off due to caching of meta-data on
-// NFS servers (Issue 848).
+var hasNoatime = sync.OnceValue(func() bool {
+ // A sloppy way to check if noatime flag is set (as all filesystems are
+ // checked, not just the one we're interested in). A correct way
+ // would be to use statvfs syscall and check if flags has ST_NOATIME,
+ // but the syscall is OS-specific and is not even wired into Go stdlib.
+ //
+ // Only used on NetBSD (which ignores explicit atime updates with noatime).
+ mounts, _ := ReadFile("/proc/mounts")
+ return bytes.Contains(mounts, []byte("noatime"))
+})
+
func TestChtimes(t *testing.T) {
t.Parallel()
- f := newFile("TestChtimes", t)
- defer Remove(f.Name())
+ f := newFile(t)
f.Write([]byte("hello, world\n"))
f.Close()
@@ -1391,139 +1383,119 @@
testChtimes(t, f.Name())
}
-func TestChtimesWithZeroTimes(t *testing.T) {
- file := newFile("chtimes-with-zero", t)
+func TestChtimesOmit(t *testing.T) {
+ t.Parallel()
+
+ testChtimesOmit(t, true, false)
+ testChtimesOmit(t, false, true)
+ testChtimesOmit(t, true, true)
+ testChtimesOmit(t, false, false) // Same as TestChtimes.
+}
+
+func testChtimesOmit(t *testing.T, omitAt, omitMt bool) {
+ t.Logf("omit atime: %v, mtime: %v", omitAt, omitMt)
+ file := newFile(t)
_, err := file.Write([]byte("hello, world\n"))
if err != nil {
- t.Fatalf("Write: %s", err)
+ t.Fatal(err)
}
- fName := file.Name()
- defer Remove(file.Name())
+ name := file.Name()
err = file.Close()
if err != nil {
- t.Errorf("%v", err)
+ t.Error(err)
}
- fs, err := Stat(fName)
+ fs, err := Stat(name)
if err != nil {
t.Fatal(err)
}
- startAtime := Atime(fs)
- startMtime := fs.ModTime()
+
+ wantAtime := Atime(fs)
+ wantMtime := fs.ModTime()
switch runtime.GOOS {
case "js":
- startAtime = startAtime.Truncate(time.Second)
- startMtime = startMtime.Truncate(time.Second)
+ wantAtime = wantAtime.Truncate(time.Second)
+ wantMtime = wantMtime.Truncate(time.Second)
}
- at0 := startAtime
- mt0 := startMtime
- t0 := startMtime.Truncate(time.Second).Add(1 * time.Hour)
- tests := []struct {
- aTime time.Time
- mTime time.Time
- wantATime time.Time
- wantMTime time.Time
- }{
- {
- aTime: time.Time{},
- mTime: time.Time{},
- wantATime: startAtime,
- wantMTime: startMtime,
- },
- {
- aTime: t0.Add(200 * time.Second),
- mTime: time.Time{},
- wantATime: t0.Add(200 * time.Second),
- wantMTime: startMtime,
- },
- {
- aTime: time.Time{},
- mTime: t0.Add(100 * time.Second),
- wantATime: t0.Add(200 * time.Second),
- wantMTime: t0.Add(100 * time.Second),
- },
- {
- aTime: t0.Add(300 * time.Second),
- mTime: t0.Add(100 * time.Second),
- wantATime: t0.Add(300 * time.Second),
- wantMTime: t0.Add(100 * time.Second),
- },
+ var setAtime, setMtime time.Time // Zero value means omit.
+ if !omitAt {
+ wantAtime = wantAtime.Add(-1 * time.Second)
+ setAtime = wantAtime
+ }
+ if !omitMt {
+ wantMtime = wantMtime.Add(-1 * time.Second)
+ setMtime = wantMtime
}
- for _, tt := range tests {
- // Now change the times accordingly.
- if err := Chtimes(fName, tt.aTime, tt.mTime); err != nil {
- t.Error(err)
- }
+ // Change the times accordingly.
+ if err := Chtimes(name, setAtime, setMtime); err != nil {
+ t.Error(err)
+ }
- // Finally verify the expectations.
- fs, err = Stat(fName)
- if err != nil {
- t.Error(err)
- }
- at0 = Atime(fs)
- mt0 = fs.ModTime()
+ // Verify the expectations.
+ fs, err = Stat(name)
+ if err != nil {
+ t.Error(err)
+ }
+ gotAtime := Atime(fs)
+ gotMtime := fs.ModTime()
- if got, want := at0, tt.wantATime; !got.Equal(want) {
- errormsg := fmt.Sprintf("AccessTime mismatch with values ATime:%q-MTime:%q\ngot: %q\nwant: %q", tt.aTime, tt.mTime, got, want)
- switch runtime.GOOS {
- case "plan9":
- // Mtime is the time of the last change of
- // content. Similarly, atime is set whenever
- // the contents are accessed; also, it is set
- // whenever mtime is set.
- case "windows":
+ // TODO: remove the dragonfly omitAt && omitMt exceptions below once the
+ // fix (https://github.com/DragonFlyBSD/DragonFlyBSD/commit/c7c71870ed0)
+ // is available generally and on CI runners.
+ if !gotAtime.Equal(wantAtime) {
+ errormsg := fmt.Sprintf("atime mismatch, got: %q, want: %q", gotAtime, wantAtime)
+ switch runtime.GOOS {
+ case "plan9":
+ // Mtime is the time of the last change of content.
+ // Similarly, atime is set whenever the contents are
+ // accessed; also, it is set whenever mtime is set.
+ case "dragonfly":
+ if omitAt && omitMt {
+ t.Log(errormsg)
+ t.Log("Known DragonFly BSD issue (won't work when both times are omitted); ignoring.")
+ } else {
+ // Assume hammer2 fs; https://www.dragonflybsd.org/hammer/ says:
+ // > Because HAMMER2 is a block copy-on-write filesystem,
+ // > the "atime" field is not supported and will typically
+ // > just reflect local system in-memory caches or mtime.
+ //
+ // TODO: if only can CI define TMPDIR to point to a tmpfs
+ // (e.g. /var/run/shm), this exception can be removed.
+ t.Log(errormsg)
+ t.Log("Known DragonFly BSD issue (atime not supported on hammer2); ignoring.")
+ }
+ case "netbsd":
+ if !omitAt && hasNoatime() {
+ t.Log(errormsg)
+ t.Log("Known NetBSD issue (atime not changed on fs mounted with noatime); ignoring.")
+ } else {
t.Error(errormsg)
- default: // unix's
- if got, want := at0, tt.wantATime; !got.Equal(want) {
- mounts, err := ReadFile("/bin/mounts")
- if err != nil {
- mounts, err = ReadFile("/etc/mtab")
- }
- if strings.Contains(string(mounts), "noatime") {
- t.Log(errormsg)
- t.Log("A filesystem is mounted with noatime; ignoring.")
- } else {
- switch runtime.GOOS {
- case "netbsd", "dragonfly":
- // On a 64-bit implementation, birth time is generally supported and cannot be changed.
- // When supported, atime update is restricted and depends on the file system and on the
- // OS configuration.
- if strings.Contains(runtime.GOARCH, "64") {
- t.Log(errormsg)
- t.Log("Filesystem might not support atime changes; ignoring.")
- }
- default:
- t.Error(errormsg)
- }
- }
- }
}
+ default:
+ t.Error(errormsg)
}
- if got, want := mt0, tt.wantMTime; !got.Equal(want) {
- errormsg := fmt.Sprintf("ModTime mismatch with values ATime:%q-MTime:%q\ngot: %q\nwant: %q", tt.aTime, tt.mTime, got, want)
- switch runtime.GOOS {
- case "dragonfly":
+ }
+ if !gotMtime.Equal(wantMtime) {
+ errormsg := fmt.Sprintf("mtime mismatch, got: %q, want: %q", gotMtime, wantMtime)
+ switch runtime.GOOS {
+ case "dragonfly":
+ if omitAt && omitMt {
t.Log(errormsg)
- t.Log("Mtime is always updated; ignoring.")
- default:
+ t.Log("Known DragonFly BSD issue (won't work when both times are omitted); ignoring.")
+ } else {
t.Error(errormsg)
}
+ default:
+ t.Error(errormsg)
}
}
}
-// Use TempDir (via newDir) to make sure we're on a local file system,
-// so that timings are not distorted by latency and caching.
-// On NFS, timings can be off due to caching of meta-data on
-// NFS servers (Issue 848).
func TestChtimesDir(t *testing.T) {
t.Parallel()
- name := newDir("TestChtimes", t)
- defer RemoveAll(name)
-
- testChtimes(t, name)
+ testChtimes(t, t.TempDir())
}
func testChtimes(t *testing.T, name string) {
@@ -1550,6 +1522,7 @@
pat := Atime(postStat)
pmt := postStat.ModTime()
if !pat.Before(at) {
+ errormsg := fmt.Sprintf("AccessTime didn't go backwards; was=%v, after=%v", at, pat)
switch runtime.GOOS {
case "plan9":
// Mtime is the time of the last change of
@@ -1557,14 +1530,14 @@ // content. Similarly, atime is set whenever
// the contents are accessed; also, it is set
// whenever mtime is set.
case "netbsd":
- mounts, _ := ReadFile("/proc/mounts")
- if strings.Contains(string(mounts), "noatime") {
- t.Logf("AccessTime didn't go backwards, but see a filesystem mounted noatime; ignoring. Issue 19293.")
+ if hasNoatime() {
+ t.Log(errormsg)
+ t.Log("Known NetBSD issue (atime not changed on fs mounted with noatime); ignoring.")
} else {
- t.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring on NetBSD, assuming noatime, Issue 19293)", at, pat)
+ t.Errorf(errormsg)
}
default:
- t.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at, pat)
+ t.Errorf(errormsg)
}
}
@@ -1574,9 +1547,8 @@ }
}
func TestChtimesToUnixZero(t *testing.T) {
- file := newFile("chtimes-to-unix-zero", t)
+ file := newFile(t)
fn := file.Name()
- defer Remove(fn)
if _, err := file.Write([]byte("hi")); err != nil {
t.Fatal(err)
}
@@ -1796,9 +1768,7 @@
func TestSeek(t *testing.T) {
t.Parallel()
- f := newFile("TestSeek", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
const data = "hello, world\n"
io.WriteString(f, data)
@@ -2040,9 +2010,7 @@
func TestReadAt(t *testing.T) {
t.Parallel()
- f := newFile("TestReadAt", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
const data = "hello, world\n"
io.WriteString(f, data)
@@ -2064,9 +2032,7 @@ // calling pread on a file.
func TestReadAtOffset(t *testing.T) {
t.Parallel()
- f := newFile("TestReadAtOffset", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
const data = "hello, world\n"
io.WriteString(f, data)
@@ -2095,9 +2061,7 @@ // Verify that ReadAt doesn't allow negative offset.
func TestReadAtNegativeOffset(t *testing.T) {
t.Parallel()
- f := newFile("TestReadAtNegativeOffset", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
const data = "hello, world\n"
io.WriteString(f, data)
@@ -2116,9 +2080,7 @@
func TestWriteAt(t *testing.T) {
t.Parallel()
- f := newFile("TestWriteAt", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
const data = "hello, world\n"
io.WriteString(f, data)
@@ -2141,9 +2103,7 @@ // Verify that WriteAt doesn't allow negative offset.
func TestWriteAtNegativeOffset(t *testing.T) {
t.Parallel()
- f := newFile("TestWriteAtNegativeOffset", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
n, err := f.WriteAt([]byte("WORLD"), -10)
@@ -2477,9 +2437,7 @@
func TestReadAtEOF(t *testing.T) {
t.Parallel()
- f := newFile("TestReadAtEOF", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
_, err := f.ReadAt(make([]byte, 10), 0)
switch err {
@@ -2495,12 +2453,7 @@
func TestLongPath(t *testing.T) {
t.Parallel()
- tmpdir := newDir("TestLongPath", t)
- defer func(d string) {
- if err := RemoveAll(d); err != nil {
- t.Fatalf("RemoveAll failed: %v", err)
- }
- }(tmpdir)
+ tmpdir := t.TempDir()
// Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted).
sizes := []int{247, 248, 249, 400}
diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go
index 98e436fae6640a027d72eafd9c54823d1785afd8..fcc75e5ee613605e38ba13c60b8743cd2eba9e06 100644
--- a/src/os/os_unix_test.go
+++ b/src/os/os_unix_test.go
@@ -45,13 +45,7 @@ t.Skip("file ownership not supported on " + runtime.GOOS)
}
t.Parallel()
- // Use TempDir() to make sure we're on a local file system,
- // so that the group ids returned by Getgroups will be allowed
- // on the file. On NFS, the Getgroups groups are
- // basically useless.
- f := newFile("TestChown", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
dir, err := f.Stat()
if err != nil {
t.Fatalf("stat %s: %s", f.Name(), err)
@@ -99,13 +93,7 @@ t.Skip("file ownership not supported on " + runtime.GOOS)
}
t.Parallel()
- // Use TempDir() to make sure we're on a local file system,
- // so that the group ids returned by Getgroups will be allowed
- // on the file. On NFS, the Getgroups groups are
- // basically useless.
- f := newFile("TestFileChown", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
dir, err := f.Stat()
if err != nil {
t.Fatalf("stat %s: %s", f.Name(), err)
@@ -151,13 +139,7 @@ func TestLchown(t *testing.T) {
testenv.MustHaveSymlink(t)
t.Parallel()
- // Use TempDir() to make sure we're on a local file system,
- // so that the group ids returned by Getgroups will be allowed
- // on the file. On NFS, the Getgroups groups are
- // basically useless.
- f := newFile("TestLchown", t)
- defer Remove(f.Name())
- defer f.Close()
+ f := newFile(t)
dir, err := f.Stat()
if err != nil {
t.Fatalf("stat %s: %s", f.Name(), err)
@@ -223,8 +205,7 @@ return nil, ErrNotExist
}
return oldStat(name)
}
- dir := newDir("TestReaddirRemoveRace", t)
- defer RemoveAll(dir)
+ dir := t.TempDir()
if err := WriteFile(filepath.Join(dir, "some-file"), []byte("hello"), 0644); err != nil {
t.Fatal(err)
}
@@ -255,8 +236,7 @@ }
t.Parallel()
const umask = 0077
- dir := newDir("TestMkdirStickyUmask", t)
- defer RemoveAll(dir)
+ dir := t.TempDir()
oldUmask := syscall.Umask(umask)
defer syscall.Umask(oldUmask)
@@ -396,14 +376,14 @@ defer chtmpdir(t)()
want := "hello gopher"
- a, err := CreateTemp("", "a")
+ a, err := CreateTemp(".", "a")
if err != nil {
t.Fatal(err)
}
a.WriteString(want[:5])
a.Close()
- b, err := CreateTemp("", "b")
+ b, err := CreateTemp(".", "b")
if err != nil {
t.Fatal(err)
}
diff --git a/src/runtime/arena.go b/src/runtime/arena.go
index 47b131466c80c8d2d690f4c8a2b11b2e33a277cb..cd9a9dfae10abc240ccbd7783344cd1acdbaafb1 100644
--- a/src/runtime/arena.go
+++ b/src/runtime/arena.go
@@ -232,7 +232,7 @@ return userArenaChunkBytes/goarch.PtrSize/8 + unsafe.Sizeof(_type{})
}
type userArena struct {
- // full is a list of full chunks that have not enough free memory left, and
+ // fullList is a list of full chunks that have not enough free memory left, and
// that we'll free once this user arena is freed.
//
// Can't use mSpanList here because it's not-in-heap.
diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go
index b8be9f8272ba76e9e2bbbc0b37d3e83c40b51312..da3d956d480bebbc037154003be638becc8b0411 100644
--- a/src/runtime/metrics/doc.go
+++ b/src/runtime/metrics/doc.go
@@ -230,6 +230,10 @@
/gc/stack/starting-size:bytes
The stack size of new goroutines.
+ /godebug/non-default-behavior/asynctimerchan:events
+ The number of non-default behaviors executed by the time package
+ due to a non-default GODEBUG=asynctimerchan=... setting.
+
/godebug/non-default-behavior/execerrdot:events
The number of non-default behaviors executed by the os/exec
package due to a non-default GODEBUG=execerrdot=... setting.
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index b51a1ad3ce3d16ffb24d115ed78e09d3dd8b24dc..e5620aec11dfd013b45256c57007cf24df1cd411 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -9,6 +9,7 @@ package runtime
import (
"internal/abi"
+ "internal/goarch"
"internal/profilerecord"
"internal/runtime/atomic"
"runtime/internal/sys"
@@ -542,16 +543,14 @@ }
gp := getg()
mp := acquirem() // we must not be preempted while accessing profstack
- nstk := 1
+ var nstk int
if tracefpunwindoff() || gp.m.hasCgoOnStack() {
- mp.profStack[0] = logicalStackSentinel
if gp.m.curg == nil || gp.m.curg == gp {
- nstk = callers(skip, mp.profStack[1:])
+ nstk = callers(skip, mp.profStack)
} else {
- nstk = gcallers(gp.m.curg, skip, mp.profStack[1:])
+ nstk = gcallers(gp.m.curg, skip, mp.profStack)
}
} else {
- mp.profStack[0] = uintptr(skip)
if gp.m.curg == nil || gp.m.curg == gp {
if skip > 0 {
// We skip one fewer frame than the provided value for frame
@@ -559,12 +558,12 @@ // pointer unwinding because the skip value includes the current
// frame, whereas the saved frame pointer will give us the
// caller's return address first (so, not including
// saveblockevent)
- mp.profStack[0] -= 1
+ skip -= 1
}
- nstk += fpTracebackPCs(unsafe.Pointer(getfp()), mp.profStack[1:])
+ nstk = fpTracebackPartialExpand(skip, unsafe.Pointer(getfp()), mp.profStack)
} else {
- mp.profStack[1] = gp.m.curg.sched.pc
- nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.m.curg.sched.bp), mp.profStack[2:])
+ mp.profStack[0] = gp.m.curg.sched.pc
+ nstk = 1 + fpTracebackPartialExpand(skip, unsafe.Pointer(gp.m.curg.sched.bp), mp.profStack[1:])
}
}
@@ -572,6 +571,52 @@ saveBlockEventStack(cycles, rate, mp.profStack[:nstk], which)
releasem(mp)
}
+// fpTracebackPartialExpand records a call stack obtained starting from fp.
+// This function will skip the given number of frames, properly accounting for
+// inlining, and save remaining frames as "physical" return addresses. The
+// consumer should later use CallersFrames or similar to expand inline frames.
+func fpTracebackPartialExpand(skip int, fp unsafe.Pointer, pcBuf []uintptr) int {
+ var n int
+ lastFuncID := abi.FuncIDNormal
+ skipOrAdd := func(retPC uintptr) bool {
+ if skip > 0 {
+ skip--
+ } else if n < len(pcBuf) {
+ pcBuf[n] = retPC
+ n++
+ }
+ return n < len(pcBuf)
+ }
+ for n < len(pcBuf) && fp != nil {
+ // return addr sits one word above the frame pointer
+ pc := *(*uintptr)(unsafe.Pointer(uintptr(fp) + goarch.PtrSize))
+
+ if skip > 0 {
+ callPC := pc - 1
+ fi := findfunc(callPC)
+ u, uf := newInlineUnwinder(fi, callPC)
+ for ; uf.valid(); uf = u.next(uf) {
+ sf := u.srcFunc(uf)
+ if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) {
+ // ignore wrappers
+ } else if more := skipOrAdd(uf.pc + 1); !more {
+ return n
+ }
+ lastFuncID = sf.funcID
+ }
+ } else {
+ // We've skipped the desired number of frames, so no need
+ // to perform further inline expansion now.
+ pcBuf[n] = pc
+ n++
+ }
+
+ // follow the frame pointer to the next one
+ fp = unsafe.Pointer(*(*uintptr)(fp))
+ }
+ return n
+}
+
// lockTimer assists with profiling contention on runtime-internal locks.
//
// There are several steps between the time that an M experiences contention and
@@ -892,9 +937,10 @@ // possible in the execution of the program (for example,
// at the beginning of main).
var MemProfileRate int = 512 * 1024
-// disableMemoryProfiling is set by the linker if runtime.MemProfile
+// disableMemoryProfiling is set by the linker if memory profiling
// is not used and the link type guarantees nobody else could use it
// elsewhere.
+// We check if the runtime.memProfileInternal symbol is present.
var disableMemoryProfiling bool
// A MemProfileRecord describes the live objects allocated
@@ -955,6 +1001,13 @@
// memProfileInternal returns the number of records n in the profile. If there
// are less than size records, copyFn is invoked for each record, and ok returns
// true.
+//
+// The linker set disableMemoryProfiling to true to disable memory profiling
+// if this function is not reachable. Mark it noinline to ensure the symbol exists.
+// (This function is big and normally not inlined anyway.)
+// See also disableMemoryProfiling above and cmd/link/internal/ld/lib.go:linksetup.
+//
+//go:noinline
func memProfileInternal(size int, inuseZero bool, copyFn func(profilerecord.MemProfileRecord)) (n int, ok bool) {
cycle := mProfCycle.read()
// If we're between mProf_NextCycle and mProf_Flush, take care
@@ -1067,10 +1120,34 @@ // Most clients should use the [runtime/pprof] package or
// the [testing] package's -test.blockprofile flag instead
// of calling BlockProfile directly.
func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
- return blockProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) {
+ n, ok = blockProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) {
copyBlockProfileRecord(&p[0], r)
p = p[1:]
})
+ if !ok {
+ return
+ }
+ expandFrames(p[:n])
+ return
+}
+
+func expandFrames(p []BlockProfileRecord) {
+ expandedStack := makeProfStack()
+ for i := range p {
+ cf := CallersFrames(p[i].Stack())
+ j := 0
+ for ; j < len(expandedStack); j++ {
+ f, more := cf.Next()
+ // f.PC is a "call PC", but later consumers will expect
+ // "return PCs"
+ expandedStack[i] = f.PC + 1
+ if !more {
+ break
+ }
+ }
+ k := copy(p[i].Stack0[:], expandedStack[:j])
+ clear(p[i].Stack0[k:])
+ }
}
// blockProfileInternal returns the number of records n in the profile. If there
@@ -1103,6 +1180,9 @@ unlock(&profBlockLock)
return
}
+// copyBlockProfileRecord copies the sample values and call stack from src to dst.
+// The call stack is copied as-is. The caller is responsible for handling inline
+// expansion, needed when the call stack was collected with frame pointer unwinding.
func copyBlockProfileRecord(dst *BlockProfileRecord, src profilerecord.BlockProfileRecord) {
dst.Count = src.Count
dst.Cycles = src.Cycles
@@ -1115,7 +1195,11 @@ }
if asanenabled {
asanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0))
}
- i := fpunwindExpand(dst.Stack0[:], src.Stack)
+ // We just copy the stack here without inline expansion
+ // (needed if frame pointer unwinding is used)
+ // since this function is called under the profile lock,
+ // and doing something that might allocate can violate lock ordering.
+ i := copy(dst.Stack0[:], src.Stack)
clear(dst.Stack0[i:])
}
@@ -1134,10 +1218,15 @@ //
// Most clients should use the [runtime/pprof] package
// instead of calling MutexProfile directly.
func MutexProfile(p []BlockProfileRecord) (n int, ok bool) {
- return mutexProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) {
+ n, ok = mutexProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) {
copyBlockProfileRecord(&p[0], r)
p = p[1:]
})
+ if !ok {
+ return
+ }
+ expandFrames(p[:n])
+ return
}
// mutexProfileInternal returns the number of records n in the profile. If there
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index be17e598754de1eaf7fddc876dfdd5180e5dfedf..4b7a9f63c6500608b0262e730ad6bf4a0facb3e3 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -404,6 +404,25 @@ Stack(i int) []uintptr
Label(i int) *labelMap
}
+// expandInlinedFrames copies the call stack from pcs into dst, expanding any
+// PCs corresponding to inlined calls into the corresponding PCs for the inlined
+// functions. Returns the number of frames copied to dst.
+func expandInlinedFrames(dst, pcs []uintptr) int {
+ cf := runtime.CallersFrames(pcs)
+ var n int
+ for n < len(dst) {
+ f, more := cf.Next()
+ // f.PC is a "call PC", but later consumers will expect
+ // "return PCs"
+ dst[n] = f.PC + 1
+ n++
+ if !more {
+ break
+ }
+ }
+ return n
+}
+
// printCountCycleProfile outputs block profile records (for block or mutex profiles)
// as the pprof-proto format output. Translations from cycle count to time duration
// are done because The proto expects count and time (nanoseconds) instead of count
@@ -426,7 +445,7 @@ values[0] = r.Count
values[1] = int64(float64(r.Cycles) / cpuGHz)
// For count profiles, all stack addresses are
// return PCs, which is what appendLocsForStack expects.
- n := pprof_fpunwindExpand(expandedStack[:], r.Stack)
+ n := expandInlinedFrames(expandedStack, r.Stack)
locs = b.appendLocsForStack(locs[:0], expandedStack[:n])
b.pbSample(values, locs, nil)
}
@@ -586,7 +605,8 @@ memStats = new(runtime.MemStats)
runtime.ReadMemStats(memStats)
}
- // Find out how many records there are (MemProfile(nil, true)),
+ // Find out how many records there are (the call
+ // pprof_memProfileInternal(nil, true) below),
// allocate that many records, and get the data.
// There's a race—more records might be added between
// the two calls—so allocate a few extra records for safety
@@ -934,7 +954,7 @@ expandedStack := pprof_makeProfStack()
for i := range p {
r := &p[i]
fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count)
- n := pprof_fpunwindExpand(expandedStack, r.Stack)
+ n := expandInlinedFrames(expandedStack, r.Stack)
stack := expandedStack[:n]
for _, pc := range stack {
fmt.Fprintf(w, " %#x", pc)
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 09abbb31ae6ccd02a31df2e62edc250da8ec62db..bd11914544fbc007ad89ac7111f621aa9406ea44 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -2578,3 +2578,81 @@ memSink = nil
runtime.GC()
goroutineDeep(t, depth-4) // -4 for produceProfileEvents, **, chanrecv1, chanrev, gopark
}
+
+func TestMutexBlockFullAggregation(t *testing.T) {
+ // This regression test is adapted from
+ // https://github.com/grafana/pyroscope-go/issues/103,
+ // authored by Tolya Korniltsev
+
+ var m sync.Mutex
+
+ prev := runtime.SetMutexProfileFraction(-1)
+ defer runtime.SetMutexProfileFraction(prev)
+
+ const fraction = 1
+ const iters = 100
+ const workers = 2
+
+ runtime.SetMutexProfileFraction(fraction)
+ runtime.SetBlockProfileRate(1)
+ defer runtime.SetBlockProfileRate(0)
+
+ wg := sync.WaitGroup{}
+ wg.Add(workers)
+ for j := 0; j < workers; j++ {
+ go func() {
+ for i := 0; i < iters; i++ {
+ m.Lock()
+ // Wait at least 1 millisecond to pass the
+ // starvation threshold for the mutex
+ time.Sleep(time.Millisecond)
+ m.Unlock()
+ }
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+
+ assertNoDuplicates := func(name string, collect func([]runtime.BlockProfileRecord) (int, bool)) {
+ var p []runtime.BlockProfileRecord
+ n, ok := collect(nil)
+ for {
+ p = make([]runtime.BlockProfileRecord, n+50)
+ n, ok = collect(p)
+ if ok {
+ p = p[:n]
+ break
+ }
+ }
+ seen := make(map[string]struct{})
+ for _, r := range p {
+ cf := runtime.CallersFrames(r.Stack())
+ var stack strings.Builder
+ for {
+ f, more := cf.Next()
+ stack.WriteString(f.Func.Name())
+ if !more {
+ break
+ }
+ stack.WriteByte('\n')
+ }
+ s := stack.String()
+ if !strings.Contains(s, "TestMutexBlockFullAggregation") {
+ continue
+ }
+ if _, ok := seen[s]; ok {
+ t.Errorf("saw duplicate entry in %s profile with stack:\n%s", name, s)
+ }
+ seen[s] = struct{}{}
+ }
+ if len(seen) == 0 {
+ t.Errorf("did not see any samples in %s profile for this test", name)
+ }
+ }
+ t.Run("mutex", func(t *testing.T) {
+ assertNoDuplicates("mutex", runtime.MutexProfile)
+ })
+ t.Run("block", func(t *testing.T) {
+ assertNoDuplicates("block", runtime.BlockProfile)
+ })
+}
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index 67eadeac9ee0f359c5e6094897f79891fe9f39f7..a930ea707f12ccd3601e2c53af53ddf2631d57e6 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -200,7 +200,7 @@ // Don't use 127.0.0.1 for every case, it won't work on IPv6-only systems.
laddr = "127.0.0.1:0"
}
ln, err := net.Listen("tcp", laddr)
- if err != nil {
+ if err == nil {
defer ln.Close() // yup, defer in a loop
}
}
diff --git a/src/slices/iter.go b/src/slices/iter.go
index 131cece3a06ff4f556bbbcb70a2c1e2a06a1c04d..cd8f308ca08ece84536cd86e6e1e24ff50397062 100644
--- a/src/slices/iter.go
+++ b/src/slices/iter.go
@@ -9,8 +9,8 @@ "cmp"
"iter"
)
-// All returns an iterator over index-value pairs in the slice.
-// The indexes range in the usual order, from 0 through len(s)-1.
+// All returns an iterator over index-value pairs in the slice
+// in the usual order.
func All[Slice ~[]E, E any](s Slice) iter.Seq2[int, E] {
return func(yield func(int, E) bool) {
for i, v := range s {
@@ -22,7 +22,7 @@ }
}
// Backward returns an iterator over index-value pairs in the slice,
-// traversing it backward. The indexes range from len(s)-1 down to 0.
+// traversing it backward with descending indices.
func Backward[Slice ~[]E, E any](s Slice) iter.Seq2[int, E] {
return func(yield func(int, E) bool) {
for i := len(s) - 1; i >= 0; i-- {
@@ -33,8 +33,7 @@ }
}
}
-// Values returns an iterator over the slice elements,
-// starting with s[0].
+// Values returns an iterator that yields the slice elements in order.
func Values[Slice ~[]E, E any](s Slice) iter.Seq[E] {
return func(yield func(E) bool) {
for _, v := range s {
diff --git a/src/strings/builder.go b/src/strings/builder.go
index e6df08c6f479ad5c13efec91c3646b49335b48f4..3b37888cbf6dbae87d570a314d34cb3c5c6e5d14 100644
--- a/src/strings/builder.go
+++ b/src/strings/builder.go
@@ -23,6 +23,18 @@ // data between len(buf) and cap(buf) might be uninitialized.
buf []byte
}
+// This is just a wrapper around abi.NoEscape.
+//
+// This wrapper is necessary because internal/abi is a runtime package,
+// so it can not be built with -d=checkptr, causing incorrect inlining
+// decision when building with checkptr enabled, see issue #68415.
+//
+//go:nosplit
+//go:nocheckptr
+func noescape(p unsafe.Pointer) unsafe.Pointer {
+ return abi.NoEscape(p)
+}
+
func (b *Builder) copyCheck() {
if b.addr == nil {
// This hack works around a failing of Go's escape analysis
@@ -30,7 +42,7 @@ // that was causing b to escape and be heap allocated.
// See issue 23382.
// TODO: once issue 7921 is fixed, this should be reverted to
// just "b.addr = b".
- b.addr = (*Builder)(abi.NoEscape(unsafe.Pointer(b)))
+ b.addr = (*Builder)(noescape(unsafe.Pointer(b)))
} else if b.addr != b {
panic("strings: illegal use of non-zero Builder copied by value")
}
diff --git a/src/strings/compare.go b/src/strings/compare.go
index b3c01fddc15493c1bf9f09a57dea7c6ec8d65ca5..dcf442471af63f43f118d6c877183b4c283496d6 100644
--- a/src/strings/compare.go
+++ b/src/strings/compare.go
@@ -10,7 +10,7 @@ // Compare returns an integer comparing two strings lexicographically.
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
//
// Use Compare when you need to perform a three-way comparison (with
-// slices.SortFunc, for example). It is usually clearer and always faster
+// [slices.SortFunc], for example). It is usually clearer and always faster
// to use the built-in string comparison operators ==, <, >, and so on.
func Compare(a, b string) int {
return bytealg.CompareString(a, b)
diff --git a/src/strings/replace.go b/src/strings/replace.go
index 3b17a55b915d7de1b665dca45378f413325a25cf..ae127288003dbc83f042388ba666096405be140c 100644
--- a/src/strings/replace.go
+++ b/src/strings/replace.go
@@ -299,7 +299,7 @@ }
type appendSliceWriter []byte
-// Write writes to the buffer to satisfy io.Writer.
+// Write writes to the buffer to satisfy [io.Writer].
func (w *appendSliceWriter) Write(p []byte) (int, error) {
*w = append(*w, p...)
return len(p), nil
diff --git a/src/strings/strings.go b/src/strings/strings.go
index 95180828f6b032c33b7cd5d1cd6c4f216dbba836..fba303c12a72070d9a409e60abac1d01b7fdcf95 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -121,7 +121,7 @@ }
// IndexRune returns the index of the first instance of the Unicode code point
// r, or -1 if rune is not present in s.
-// If r is utf8.RuneError, it returns the first instance of any
+// If r is [utf8.RuneError], it returns the first instance of any
// invalid UTF-8 byte sequence.
func IndexRune(s string, r rune) int {
switch {
@@ -275,7 +275,7 @@ //
// Edge cases for s and sep (for example, empty strings) are handled
// as described in the documentation for [Split].
//
-// To split around the first instance of a separator, see Cut.
+// To split around the first instance of a separator, see [Cut].
func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
// SplitAfterN slices s into substrings after each instance of sep and
@@ -304,7 +304,7 @@ // and sep are empty, Split returns an empty slice.
//
// It is equivalent to [SplitN] with a count of -1.
//
-// To split around the first instance of a separator, see Cut.
+// To split around the first instance of a separator, see [Cut].
func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
// SplitAfter slices s into all substrings after each instance of sep and
@@ -324,7 +324,7 @@
var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
// Fields splits the string s around each instance of one or more consecutive white space
-// characters, as defined by unicode.IsSpace, returning a slice of substrings of s or an
+// characters, as defined by [unicode.IsSpace], returning a slice of substrings of s or an
// empty slice if s contains only white space.
func Fields(s string) []string {
// First count the fields.
diff --git a/src/sync/atomic/type.go b/src/sync/atomic/type.go
index 7d2b6805bca85d959e63fe32725877a07b94aa49..f487cb9c5f7eaaf35ee0b5b6d02636f2b9831779 100644
--- a/src/sync/atomic/type.go
+++ b/src/sync/atomic/type.go
@@ -156,7 +156,7 @@ func (x *Uint32) And(mask uint32) (old uint32) { return AndUint32(&x.v, mask) }
// Or atomically performs a bitwise OR operation on x using the bitmask
// provided as mask and returns the old value.
-func (x *Uint32) Or(mask uint32) (new uint32) { return OrUint32(&x.v, mask) }
+func (x *Uint32) Or(mask uint32) (old uint32) { return OrUint32(&x.v, mask) }
// A Uint64 is an atomic uint64. The zero value is zero.
type Uint64 struct {
@@ -188,7 +188,7 @@ func (x *Uint64) And(mask uint64) (old uint64) { return AndUint64(&x.v, mask) }
// Or atomically performs a bitwise OR operation on x using the bitmask
// provided as mask and returns the old value.
-func (x *Uint64) Or(mask uint64) (new uint64) { return OrUint64(&x.v, mask) }
+func (x *Uint64) Or(mask uint64) (old uint64) { return OrUint64(&x.v, mask) }
// A Uintptr is an atomic uintptr. The zero value is zero.
type Uintptr struct {
diff --git a/src/sync/export_test.go b/src/sync/export_test.go
index b55cecd987dd07436accfaa4866d210cd0ef001f..ddde30e018a5a0b0e7bc08eb9d0bfb5d2d44c027 100644
--- a/src/sync/export_test.go
+++ b/src/sync/export_test.go
@@ -10,7 +10,7 @@ var Runtime_Semrelease = runtime_Semrelease
var Runtime_procPin = runtime_procPin
var Runtime_procUnpin = runtime_procUnpin
-// poolDequeue testing.
+// PoolDequeue exports an interface for pollDequeue testing.
type PoolDequeue interface {
PushHead(val any) bool
PopHead() (any, bool)
diff --git a/src/sync/rwmutex.go b/src/sync/rwmutex.go
index 66cb93c44efe7ce3268fbb9dedda62d5669a6ae8..1d5b8fde4a8c627a5c6c7840741e46ee9ffcc173 100644
--- a/src/sync/rwmutex.go
+++ b/src/sync/rwmutex.go
@@ -234,7 +234,7 @@ return r < 0 && r+rwmutexMaxReaders > 0
}
// RLocker returns a [Locker] interface that implements
-// the [RWMutex.Lock] and [RWMutex.Unlock] methods by calling rw.RLock and rw.RUnlock.
+// the [Locker.Lock] and [Locker.Unlock] methods by calling rw.RLock and rw.RUnlock.
func (rw *RWMutex) RLocker() Locker {
return (*rlocker)(rw)
}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 200fa659b8669733a5ae725b047048c9f884af62..526cba39f8fc92563f425c0cdf92d147563d9322 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -362,7 +362,7 @@ // A simple implementation of TestMain is:
//
// func TestMain(m *testing.M) {
// // call flag.Parse() here if TestMain uses flags
-// os.Exit(m.Run())
+// m.Run()
// }
//
// TestMain is a low-level primitive and should not be necessary for casual
diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go
index 23ba9aec2be8412d196ea74ebe117ca74129580e..a31309874d9da319961c80ded9edd6e21809ea59 100644
--- a/src/text/template/parse/node.go
+++ b/src/text/template/parse/node.go
@@ -217,7 +217,11 @@ sb.WriteString(", ")
}
v.writeTo(sb)
}
- sb.WriteString(" := ")
+ if p.IsAssign {
+ sb.WriteString(" = ")
+ } else {
+ sb.WriteString(" := ")
+ }
}
for i, c := range p.Cmds {
if i > 0 {
diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go
index faf226d1c3cac26a7ceb4dd8b1d167d38c0d3a96..26aff330fe8a2716f0f08f8ef66ee48a63f85f3b 100644
--- a/src/text/template/parse/parse_test.go
+++ b/src/text/template/parse/parse_test.go
@@ -306,6 +306,9 @@ // Another bug: variable read must ignore following punctuation.
{"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""}, // ! is just illegal here.
{"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""}, // $x+2 should not parse as ($x) (+2).
{"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
+ // Check the range handles assignment vs. declaration properly.
+ {"bug2a", "{{range $x := 0}}{{$x}}{{end}}", noError, "{{range $x := 0}}{{$x}}{{end}}"},
+ {"bug2b", "{{range $x = 0}}{{$x}}{{end}}", noError, "{{range $x = 0}}{{$x}}{{end}}"},
// dot following a literal value
{"dot after integer", "{{1.E}}", hasError, ""},
{"dot after float", "{{0.1.E}}", hasError, ""},
diff --git a/src/time/format.go b/src/time/format.go
index 6488ec8abaa13cc4a52506e459930ba70c0d2340..c9e68b3eb25417710aea1bc46d5dbd29ec9e3774 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -1203,12 +1203,14 @@ amSet = true
default:
err = errBad
}
- case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
- if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' {
+ case stdISO8601TZ, stdISO8601ShortTZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ:
+ if len(value) >= 1 && value[0] == 'Z' {
value = value[1:]
z = UTC
break
}
+ fallthrough
+ case stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
var sign, hour, min, seconds string
if std == stdISO8601ColonTZ || std == stdNumColonTZ {
if len(value) < 6 {
diff --git a/src/time/format_test.go b/src/time/format_test.go
index 4b598f6bdf80e95b47d66a1777b2f607a048b659..2537c765968ee2b3532daa3cdbd540a6d0783d44 100644
--- a/src/time/format_test.go
+++ b/src/time/format_test.go
@@ -336,6 +336,23 @@ {"", "2006-01 002 15:04:05", "2010-02 035 21:00:57", false, false, 1, 0},
{"", "2006-002 15:04:05", "2010-035 21:00:57", false, false, 1, 0},
{"", "200600201 15:04:05", "201003502 21:00:57", false, false, 1, 0},
{"", "200600204 15:04:05", "201003504 21:00:57", false, false, 1, 0},
+
+ // Time zone offsets
+ {"", "2006-01-02T15:04:05Z07", "2010-02-04T21:00:57Z", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z07", "2010-02-04T21:00:57+08", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z07", "2010-02-04T21:00:57-08", true, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z0700", "2010-02-04T21:00:57Z", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z0700", "2010-02-04T21:00:57+0800", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z0700", "2010-02-04T21:00:57-0800", true, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z07:00", "2010-02-04T21:00:57Z", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z07:00", "2010-02-04T21:00:57+08:00", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z07:00", "2010-02-04T21:00:57-08:00", true, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z070000", "2010-02-04T21:00:57Z", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z070000", "2010-02-04T21:00:57+080000", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z070000", "2010-02-04T21:00:57-080000", true, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z07:00:00", "2010-02-04T21:00:57Z", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z07:00:00", "2010-02-04T21:00:57+08:00:00", false, false, 1, 0},
+ {"", "2006-01-02T15:04:05Z07:00:00", "2010-02-04T21:00:57-08:00:00", true, false, 1, 0},
}
func TestParse(t *testing.T) {
diff --git a/src/time/sleep.go b/src/time/sleep.go
index 2c6495d93a704d75357519afadb49066aa73d0ed..7e2fa0c20af46e2132aa9f4ea017987fd6eca212 100644
--- a/src/time/sleep.go
+++ b/src/time/sleep.go
@@ -23,6 +23,7 @@ func syncTimer(c chan Time) unsafe.Pointer {
// If asynctimerchan=1, we don't even tell the runtime
// about channel timers, so that we get the pre-Go 1.23 code paths.
if asynctimerchan.Value() == "1" {
+ asynctimerchan.IncNonDefault()
return nil
}
diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go
index 8d6cacb8b559b97f8fd76b6f9b1450a4b86d63a7..de9421bab563a70d3e85906e8288aeaba6d626c6 100644
--- a/src/unsafe/unsafe.go
+++ b/src/unsafe/unsafe.go
@@ -110,7 +110,7 @@ // // INVALID: conversion of nil pointer
// u := unsafe.Pointer(nil)
// p := unsafe.Pointer(uintptr(u) + offset)
//
-// (4) Conversion of a Pointer to a uintptr when calling [syscall.Syscall].
+// (4) Conversion of a Pointer to a uintptr when calling functions like [syscall.Syscall].
//
// The Syscall functions in package syscall pass their uintptr arguments directly
// to the operating system, which then may, depending on the details of the call,
@@ -260,7 +260,7 @@ // At run time, if len is negative, or if ptr is nil and len is not zero,
// a run-time panic occurs.
//
// Since Go strings are immutable, the bytes passed to String
-// must not be modified afterwards.
+// must not be modified as long as the returned string value exists.
func String(ptr *byte, len IntegerType) string
// StringData returns a pointer to the underlying bytes of str.
diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt
index 2868749b894fb20304d47a636cdb555fba22f5b3..b8a0b84a282a32ac7fcb283037d033d9436ec85f 100644
--- a/src/vendor/modules.txt
+++ b/src/vendor/modules.txt
@@ -18,7 +18,7 @@ golang.org/x/net/idna
golang.org/x/net/lif
golang.org/x/net/nettest
golang.org/x/net/route
-# golang.org/x/sys v0.21.0
+# golang.org/x/sys v0.22.0
## explicit; go 1.18
golang.org/x/sys/cpu
# golang.org/x/text v0.16.0
diff --git a/test/fixedbugs/issue54542.go b/test/fixedbugs/issue54542.go
new file mode 100644
index 0000000000000000000000000000000000000000..165bcc582edd8314c9a5801f9c699bb642b2649c
--- /dev/null
+++ b/test/fixedbugs/issue54542.go
@@ -0,0 +1,67 @@
+// run
+
+//go:build !js && !wasip1
+
+// 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
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+)
+
+const aSrc = `package a
+
+func A() { println("a") }
+`
+
+const mainSrc = `package main
+
+import "a"
+
+func main() { a.A() }
+`
+
+var srcs = map[string]string{
+ "a.go": aSrc,
+ "main.go": mainSrc,
+}
+
+func main() {
+ dir, err := os.MkdirTemp("", "issue54542")
+ if err != nil {
+ panic(err)
+ }
+ defer os.RemoveAll(dir)
+
+ for fn, src := range srcs {
+ if err := os.WriteFile(filepath.Join(dir, fn), []byte(src), 0644); err != nil {
+ panic(err)
+ }
+ }
+
+ if _, err := runInDir(dir, "tool", "compile", "-p=lie", "a.go"); err != nil {
+ panic(err)
+ }
+
+ out, err := runInDir(dir, "tool", "compile", "-I=.", "-p=main", "main.go")
+ if err == nil {
+ panic("compiling succeed unexpectedly")
+ }
+
+ if bytes.Contains(out, []byte("internal compiler error:")) {
+ panic(fmt.Sprintf("unexpected ICE:\n%s", string(out)))
+ }
+}
+
+func runInDir(dir string, args ...string) ([]byte, error) {
+ cmd := exec.Command("go", args...)
+ cmd.Dir = dir
+ return cmd.CombinedOutput()
+}
diff --git a/test/fixedbugs/issue67190.go b/test/fixedbugs/issue67190.go
new file mode 100644
index 0000000000000000000000000000000000000000..c19b248b51c64ebdf2da56c4d9dad78a43f2fa6f
--- /dev/null
+++ b/test/fixedbugs/issue67190.go
@@ -0,0 +1,24 @@
+// 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
+
+func main() {
+ ch1 := make(chan struct{})
+ var ch2 <-chan struct{} = ch1
+
+ switch ch1 {
+ case ch2:
+ default:
+ panic("bad narrow case")
+ }
+
+ switch ch2 {
+ case ch1:
+ default:
+ panic("bad narrow switch")
+ }
+}
diff --git a/test/fixedbugs/issue68227.go b/test/fixedbugs/issue68227.go
new file mode 100644
index 0000000000000000000000000000000000000000..615d2824e42ea723a078fc3dcd24199cc1a51f8d
--- /dev/null
+++ b/test/fixedbugs/issue68227.go
@@ -0,0 +1,43 @@
+// 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
+
+import (
+ "fmt"
+)
+
+type someType []uint64
+
+func (s *someType) push(v uint64) {
+ *s = append(*s, v)
+}
+
+func (s *someType) problematicFn(x1Lo, x1Hi, x2Lo, x2Hi uint64) {
+ r1 := int32(int16(x1Lo>>0)) * int32(int16(x2Lo>>0))
+ g()
+ r3 := int32(int16(x1Lo>>32)) * int32(int16(x2Lo>>32))
+ r4 := int32(int16(x1Lo>>48)) * int32(int16(x2Lo>>48))
+ r5 := int32(int16(x1Hi>>0)) * int32(int16(x2Hi>>0))
+ r7 := int32(int16(x1Hi>>32)) * int32(int16(x2Hi>>32))
+ r8 := int32(int16(x1Hi>>48)) * int32(int16(x2Hi>>48))
+ s.push(uint64(uint32(r1)) | (uint64(uint32(r3+r4)) << 32))
+ s.push(uint64(uint32(r5)) | (uint64(uint32(r7+r8)) << 32))
+}
+
+//go:noinline
+func g() {
+}
+
+func main() {
+ s := &someType{}
+ s.problematicFn(0x1000100010001, 0x1000100010001, 0xffffffffffffffff, 0xffffffffffffffff)
+ for i := 0; i < 2; i++ {
+ if got, want := (*s)[i], uint64(0xfffffffeffffffff); got != want {
+ fmt.Printf("s[%d]=%x, want %x\n", i, got, want)
+ }
+ }
+}
diff --git a/test/fixedbugs/issue68264.go b/test/fixedbugs/issue68264.go
new file mode 100644
index 0000000000000000000000000000000000000000..7d67e55f6e46ff88f2aa37c2395c22e64e27d515
--- /dev/null
+++ b/test/fixedbugs/issue68264.go
@@ -0,0 +1,15 @@
+// compile
+
+// 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 p
+
+type nat []int
+
+var a, b nat = y()
+
+func y() (nat, []int) {
+ return nat{0}, nat{1}
+}
diff --git a/test/fixedbugs/issue68322.go b/test/fixedbugs/issue68322.go
new file mode 100644
index 0000000000000000000000000000000000000000..9b3e713d59575ee43c47c32f526e8d33d0b563ca
--- /dev/null
+++ b/test/fixedbugs/issue68322.go
@@ -0,0 +1,17 @@
+// 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
+
+import "math"
+
+var doNotFold = 18446744073709549568.0
+
+func main() {
+ if math.Trunc(doNotFold) != doNotFold {
+ panic("big (over 2**63-1) math.Trunc is incorrect")
+ }
+}
diff --git a/test/fixedbugs/issue68415.go b/test/fixedbugs/issue68415.go
new file mode 100644
index 0000000000000000000000000000000000000000..cf278ac60359b16890cb81a7799cd09c6a2d3902
--- /dev/null
+++ b/test/fixedbugs/issue68415.go
@@ -0,0 +1,15 @@
+// run -gcflags=all=-d=checkptr
+
+// 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
+
+import "regexp"
+
+var dataFileRegexp = regexp.MustCompile(`^data\.\d+\.bin$`)
+
+func main() {
+ _ = dataFileRegexp
+}