Compare commits

...

39 Commits

Author SHA1 Message Date
Gopher Robot
ed07b321ae [release-branch.go1.23] go1.23.2
Change-Id: I904d2e951796dd4142d6e9de4a55af07852bca51
Reviewed-on: https://go-review.googlesource.com/c/go/+/617019
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2024-10-01 17:24:29 +00:00
Ian Lance Taylor
3b2e846e11 [release-branch.go1.23] runtime: if stop/reset races with running timer, return correct result
The timer code is careful to ensure that if stop/reset is called
while a timer is being run, we cancel the run. However, the code
failed to ensure that in that case stop/reset returned true,
meaning that the timer had been stopped. In the racing case
stop/reset could see that t.when had been set to zero,
and return false, even though the timer had not and never would fire.

Fix this by tracking whether a timer run is in progress,
and using that to reliably detect that the run was cancelled,
meaning that stop/reset should return true.

For #69312
Fixes #69333

Change-Id: I78e870063eb96650638f12c056e32c931417c84a
Reviewed-on: https://go-review.googlesource.com/c/go/+/611496
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
(cherry picked from commit 2ebaff4890596ed6064e2dcbbe5e68bc93bed882)
Reviewed-on: https://go-review.googlesource.com/c/go/+/616096
Reviewed-by: Ian Lance Taylor <iant@google.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
2024-09-27 18:23:47 +00:00
Cuong Manh Le
fbddfae62f [release-branch.go1.23] cmd/compile: fix wrong esacpe analysis for rangefunc
CL 584596 "-range<N>" suffix to the name of closure generated for a
rangefunc loop body. However, this breaks the condition that escape
analysis uses for checking whether a closure contains within function,
which is "F.funcN" for outer function "F" and closure "funcN".

Fixing this by adding new "-rangeN" to the condition.

Updates #69434
Fixes #69511

Change-Id: I411de8f63b69a6514a9e9504d49d62e00ce4115d
Reviewed-on: https://go-review.googlesource.com/c/go/+/614096
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/614195
2024-09-25 16:22:40 +00:00
Ian Lance Taylor
c8c6f9abfb [release-branch.go1.23] syscall: on exec failure, close pidfd
For #69284
Fixes #69402

Change-Id: I6350209302778ba5e44fa03d0b9e680d2b4ec192
Reviewed-on: https://go-review.googlesource.com/c/go/+/611495
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: roger peppe <rogpeppe@gmail.com>
Reviewed-by: Tim King <taking@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
(cherry picked from commit 8926ca9c5ec3ea0b51e413e87f737aeb1422ea48)
Reviewed-on: https://go-review.googlesource.com/c/go/+/613616
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
2024-09-18 19:41:05 +00:00
Michael Anthony Knyszek
a74951c5af [release-branch.go1.23] unique: don't retain uncloned input as key
Currently the unique package tries to clone strings that get stored in
its internal map to avoid retaining large strings.

However, this falls over entirely due to the fact that the original
string is *still* stored in the map as a key. Whoops. Fix this by
storing the cloned value in the map instead.

This change also adds a test which fails without this change.

For #69370.
Fixes #69383.

Change-Id: I1a6bb68ed79b869ea12ab6be061a5ae4b4377ddb
Reviewed-on: https://go-review.googlesource.com/c/go/+/610738
Reviewed-by: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
(cherry picked from commit 21ac23a96f204dfb558a8d3071380c1d105a93ba)
Reviewed-on: https://go-review.googlesource.com/c/go/+/612295
Auto-Submit: Tim King <taking@google.com>
2024-09-11 18:11:20 +00:00
Wei Fu
e6598e7baa [release-branch.go1.23] os: dup pidfd if caller sets PidFD manually
For #68984.
Fixes #69119.

Change-Id: I16d25777cb38a337cd4204a8147eaf866c3df9e1
Reviewed-on: https://go-review.googlesource.com/c/go/+/607695
Reviewed-by: Kirill Kolyshkin <kolyshkin@gmail.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Commit-Queue: Ian Lance Taylor <iant@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
(cherry picked from commit 239666cd7343d46c40a5b929c8bec8b532dbe83f)
Reviewed-on: https://go-review.googlesource.com/c/go/+/611415
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Bypass: Dmitri Shuralyov <dmitshur@golang.org>
2024-09-06 16:06:09 +00:00
Michael Anthony Knyszek
82575f76b8 [release-branch.go1.23] internal/weak: shade pointer in weak-to-strong conversion
There's a bug in the weak-to-strong conversion in that creating the
*only* strong pointer to some weakly-held object during the mark phase
may result in that object not being properly marked.

The exact mechanism for this is that the new strong pointer will always
point to a white object (because it was only weakly referenced up until
this point) and it can then be stored in a blackened stack, hiding it
from the garbage collector.

This "hide a white pointer in the stack" problem is pretty much exactly
what the Yuasa part of the hybrid write barrier is trying to catch, so
we need to do the same thing the write barrier would do: shade the
pointer.

Added a test and confirmed that it fails with high probability if the
pointer shading is missing.

For #69210.
Fixes #69240.

Change-Id: Iaae64ae95ea7e975c2f2c3d4d1960e74e1bd1c3f
Reviewed-on: https://go-review.googlesource.com/c/go/+/610396
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
(cherry picked from commit 79fd633632cdbaf9ca38f7559e5abb5c07fbbd9d)
Reviewed-on: https://go-review.googlesource.com/c/go/+/610696
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
2024-09-06 14:34:16 +00:00
Keith Randall
a886959aa2 [release-branch.go1.23] runtime: size maps.Clone destination bucket array safely
In rare situations, like during same-sized grows, the source map for
maps.Clone may be overloaded (has more than 6.5 entries per
bucket). This causes the runtime to allocate a larger bucket array for
the destination map than for the source map. The maps.Clone code
walks off the end of the source array if it is smaller than the
destination array.

This is a pretty simple fix, ensuring that the destination bucket
array is never longer than the source bucket array. Maybe a better fix
is to make the Clone code handle shorter source arrays correctly, but
this fix is deliberately simple to reduce the risk of backporting this
fix.

Fixes #69156

Change-Id: I824c93d1db690999f25a3c43b2816fc28ace7509
Reviewed-on: https://go-review.googlesource.com/c/go/+/610377
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Keith Randall <khr@google.com>
2024-09-06 14:32:57 +00:00
Ian Lance Taylor
80ff7cd35a [release-branch.go1.23] cmd/cgo: correct padding required by alignment
If the aligned offset isn't sufficient for the field offset,
we were padding based on the aligned offset. We need to pad
based on the original offset instead.

Also set the Go alignment correctly for int128. We were defaulting
to the maximum alignment, but since we translate int128 into an
array of uint8 the correct Go alignment is 1.

For #69086
Fixes #69219

Change-Id: I23ce583335c81beac2ac51f7f9336ac97ccebf09
Reviewed-on: https://go-review.googlesource.com/c/go/+/608815
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
(cherry picked from commit c2098929056481d0dc09f5f42b8959f4db8878f2)
Reviewed-on: https://go-review.googlesource.com/c/go/+/611296
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
2024-09-05 21:57:44 +00:00
Gopher Robot
69234ded30 [release-branch.go1.23] go1.23.1
Change-Id: I1f2dab5560d3214c8934074a53f7750d8d431936
Reviewed-on: https://go-review.googlesource.com/c/go/+/611196
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Commit-Queue: Gopher Robot <gobot@golang.org>
TryBot-Bypass: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
2024-09-05 15:20:23 +00:00
Roland Shoemaker
032ac075c2 [release-branch.go1.23] go/build/constraint: add parsing limits
Limit the size of build constraints that we will parse. This prevents a
number of stack exhaustions that can be hit when parsing overly complex
constraints. The imposed limits are unlikely to ever be hit in real
world usage.

Updates #69141
Fixes #69149
Fixes CVE-2024-34158

Change-Id: I38b614bf04caa36eefc6a4350d848588c4cef3c4
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1540
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Russ Cox <rsc@google.com>
(cherry picked from commit 0c74dc9e0da0cf1e12494b514d822b5bebbc9f04)
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1562
Commit-Queue: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/611177
Reviewed-by: Michael Pratt <mpratt@google.com>
TryBot-Bypass: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
2024-09-05 14:55:17 +00:00
Roland Shoemaker
fa8ff1a46d [release-branch.go1.23] encoding/gob: cover missed cases when checking ignore depth
This change makes sure that we are properly checking the ignored field
recursion depth in decIgnoreOpFor consistently. This prevents stack
exhaustion when attempting to decode a message that contains an
extremely deeply nested struct which is ignored.

Thanks to Md Sakib Anwar of The Ohio State University (anwar.40@osu.edu)
for reporting this issue.

Updates #69139
Fixes #69145
Fixes CVE-2024-34156

Change-Id: Iacce06be95a5892b3064f1c40fcba2e2567862d6
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1440
Reviewed-by: Russ Cox <rsc@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
(cherry picked from commit 9f2ea73c5f2a7056b7da5d579a485a7216f4b20a)
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1581
Commit-Queue: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/611176
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
TryBot-Bypass: Dmitri Shuralyov <dmitshur@google.com>
2024-09-05 14:55:14 +00:00
Roland Shoemaker
53487e5477 [release-branch.go1.23] go/parser: track depth in nested element lists
Prevents stack exhaustion with extremely deeply nested literal values,
i.e. field values in structs.

Updates #69138
Fixes #69143
Fixes CVE-2024-34155

Change-Id: I2e8e33b44105cc169d7ed1ae83fb56df0c10f1ee
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1520
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Russ Cox <rsc@google.com>
(cherry picked from commit eb1b038c0d01761694e7a735ef87ac9164c6568e)
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1560
Commit-Queue: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/611175
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Bypass: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-09-05 14:55:11 +00:00
Michael Pratt
3d1f1f27cf [release-branch.go1.23] cmd: vendor golang.org/x/telemetry@internal-branch.go1.23-vendor
Update x/telemetry to fix #68976 and #68946.

Commands run:
  go get golang.org/x/telemetry@internal-branch.go1.23-vendor
  go mod tidy
  go mod vendor

Fixes #68994.
Fixes #68995.

Change-Id: I63b892ad4c313aa92f21fbd4f519a0b19d725849
Reviewed-on: https://go-review.googlesource.com/c/go/+/609355
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
2024-08-29 00:09:27 +00:00
Nic Klaassen
6de5a7180c [release-branch.go1.23] database/sql: fix panic with concurrent Conn and Close
The current implementation has a panic when the database is closed
concurrently with a new connection attempt.

connRequestSet.CloseAndRemoveAll sets connRequestSet.s to a nil slice.
If this happens between calls to connRequestSet.Add and
connRequestSet.Delete, there is a panic when trying to write to the nil
slice. This is sequence is likely to occur in DB.conn, where the mutex
is released between calls to db.connRequests.Add and
db.connRequests.Delete

This change updates connRequestSet.CloseAndRemoveAll to set the curIdx
to -1 for all pending requests before setting its internal slice to nil.
CloseAndRemoveAll already iterates the full slice to close all the request
channels. It seems appropriate to set curIdx to -1 before deleting the
slice for 3 reasons:
1. connRequestSet.deleteIndex also sets curIdx to -1
2. curIdx will not be relevant to anything after the slice is set to nil
3. connRequestSet.Delete already checks for negative indices

For #68949
Fixes #69041

Change-Id: I6b7ebc5a71b67322908271d13865fa12f2469b87
GitHub-Last-Rev: 7d2669155b24043dd9d276f915689511572f2e49
GitHub-Pull-Request: golang/go#68953
Reviewed-on: https://go-review.googlesource.com/c/go/+/607238
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Commit-Queue: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
(cherry picked from commit 08707d66c350927560faa11b0c195d37d281ab89)
Reviewed-on: https://go-review.googlesource.com/c/go/+/609255
2024-08-28 18:37:00 +00:00
Tim King
9625a7faae [release-branch.go1.23] go/types, types2: unalias tilde terms in underIs
Unalias the ~T terms during underIs. Before, if T was an alias
of U, it may pass T to the iteration function. The iterator
function expects an underlying type, under(U), to be passed.
This caused several bugs where underIs is used without
eventually taking the underlying type.

Fixes #68905

Change-Id: Ie8691d8dddaea00e1dcba94d17c0f1b021fc49a2
Reviewed-on: https://go-review.googlesource.com/c/go/+/606075
Reviewed-by: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
(cherry picked from commit 1a90dcdaaf46d9dd0ee61781dcb9b6e05b80d926)
Reviewed-on: https://go-review.googlesource.com/c/go/+/607635
2024-08-28 18:10:23 +00:00
Michael Anthony Knyszek
9c939a1e60 [release-branch.go1.23] runtime: store bp on cgocallback as unsafe.Pointer
As of CL 580255, the runtime tracks the frame pointer (or base pointer,
bp) when entering syscalls, so that we can use fpTracebackPCs on
goroutines that are sitting in syscalls. That CL mostly got things
right, but missed one very subtle detail.

When calling from Go->C->Go, the goroutine stack performing the calls
when returning to Go is free to move around in memory due to growth,
shrinking, etc. But upon returning back to C, it needs to restore
gp.syscall*, including gp.syscallsp and gp.syscallbp. The way syscallsp
currently gets updated is automagically: it's stored as an
unsafe.Pointer on the stack so that it shows up in a stack map. If the
stack ever moves, it'll get updated correctly. But gp.syscallbp isn't
saved to the stack as an unsafe.Pointer, but rather as a uintptr, so it
never gets updated! As a result, in rare circumstances, fpTracebackPCs
can correctly try to use gp.syscallbp as the starting point for the
traceback, but the value is stale.

This change fixes the problem by just storing gp.syscallbp to the stack
on cgocallback as an unsafe.Pointer, like gp.syscallsp. It also adds a
comment documenting this subtlety; the lack of explanation for the
unsafe.Pointer type on syscallsp meant this detail was missed -- let's
not miss it again in the future.

Now, we have a fix, what about a test? Unfortunately, testing this is
going to be incredibly annoying because the circumstances under which
gp.syscallbp are actually used for traceback are non-deterministic and
hard to arrange, especially from within testprogcgo where we don't have
export_test.go and can't reach into the runtime.

So, instead, add a gp.syscallbp check to reentersyscall and
entersyscallblock that mirrors the gp.syscallbp consistency check. This
probably causes some miniscule slowdown to the syscall path, but it'll
catch the issue without having to actually perform a traceback.

For #69085.
Fixes #69087.

Change-Id: Iaf771758f1666024b854f5fbe2b2c63cbe35b201
Reviewed-on: https://go-review.googlesource.com/c/go/+/608775
Reviewed-by: Nick Ripley <nick.ripley@datadoghq.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
(cherry picked from commit 54fe0fd43fcf8609666c16ae6d15ed92873b1564)
Reviewed-on: https://go-review.googlesource.com/c/go/+/608835
2024-08-28 17:42:20 +00:00
Michael Matloob
7afe17bbdb [release-branch.go1.23] go/types, types2: use max(fileVersion, go1.21) if fileVersion present
Change the rules for how //go:build "file versions" are applied: instead
of considering whether a file version is an upgrade or downgrade from
the -lang version, always use max(fileVersion, go1.21). This prevents
file versions from downgrading the version below go1.21.  Before Go 1.21
the //go:build version did not have the meaning of setting the file's
langage version.

This fixes an issue that was appearing in GOPATH builds: Go 1.23.0
started providing -lang versions to the compiler in GOPATH mode (among
other places) which it wasn't doing before, and it set -lang to the
toolchain version (1.23). Because the -lang version was greater than
go1.21, language version used to compile the file would be set to the
//go:build file version. //go:build file versions below 1.21 could cause
files that could previously build to stop building.

For example, take a Go file with a //go:build line specifying go1.10.
If that file used a 1.18 feature, that use would compile fine with a Go
1.22 toolchain. But it would produce an error when compiling with the
1.23.0 toolchain because it set the language version to 1.10 and
disallowed the 1.18 feature. This breaks backwards compatibility: when
the build tag was added, it did not have the meaning of restricting the
language version.

For #68658
Fixes #69094

Change-Id: I6cedda81a55bcccffaa3501eef9e2be6541b6ece
Reviewed-on: https://go-review.googlesource.com/c/go/+/607955
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
(cherry picked from commit aeac0b6cbfb42bc9c9301913a191bb09454d316a)
Reviewed-on: https://go-review.googlesource.com/c/go/+/608935
2024-08-28 15:43:17 +00:00
Paul E. Murphy
8002845759 [release-branch.go1.23] runtime: on AIX, fix call to _cgo_sys_thread_create in _rt0_ppc64_aix_lib
The AIX ABI requires allocating parameter save space when calling
a function, even if the arguments are passed via registers.

gcc sometimes uses this space. In the case of the cgo c-archive
tests, it clobbered the storage space of argc/argv which prevented
the test program from running the expected test.

Fixes #68973

Change-Id: I8a267b463b1abb2b37ac85231f6c328f406b7515
Reviewed-on: https://go-review.googlesource.com/c/go/+/606895
Reviewed-by: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Paul Murphy <murp@ibm.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/607195
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2024-08-21 20:26:47 +00:00
Robert Griesemer
9166d2feec [release-branch.go1.23] go/types, types2: Named.cleanup must also handle *Alias types
Named.cleanup is called at the end of type-checking to ensure that
a named type is fully set up; specifically that it's underlying
field is not (still) a Named type. Now it can also be an *Alias
type. Add this case to the respective type switch.

Fixes #68894.

Change-Id: I29bc0024ac9d8b0152a3d97c82dd28d09d5dbd66
Reviewed-on: https://go-review.googlesource.com/c/go/+/605977
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/606656
2024-08-21 17:42:47 +00:00
Michael Anthony Knyszek
76346b3543 [release-branch.go1.23] unique: use TypeFor instead of TypeOf to get type in Make
Currently the first thing Make does it get the abi.Type of its argument,
and uses abi.TypeOf to do it. However, this has a problem for interface
types, since the type of the value stored in the interface value will
bleed through. This is a classic reflection mistake.

Fix this by implementing and using a generic TypeFor which matches
reflect.TypeFor. This gets the type of the type parameter, which is far
less ambiguous and error-prone.

For #68990.
Fixes #68992.

Change-Id: Idd8d9a1095ef017e9cd7c7779314f7d4034f01a7
Reviewed-on: https://go-review.googlesource.com/c/go/+/607355
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
(cherry picked from commit 755c18ecdfe64df060be91fb669ca1a68527830b)
Reviewed-on: https://go-review.googlesource.com/c/go/+/607435
Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-08-21 17:42:03 +00:00
Andy Pan
3c9340557c [release-branch.go1.23] os: use O_EXCL instead of O_TRUNC in CopyFS to disallow rewriting existing files does not exist
On Linux, a call to creat() is equivalent to calling open() with flags
equal to O_CREAT|O_WRONLY|O_TRUNC, which applies to other platforms
as well in a similar manner. Thus, to force CopyFS's behavior to
comply with the function comment, we need to replace O_TRUNC with O_EXCL.

Fixes #68907

Change-Id: I3e2ab153609d3c8cf20ce5969d6f3ef593833cd1
Reviewed-on: https://go-review.googlesource.com/c/go/+/606095
Auto-Submit: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
(cherry picked from commit aa5d672a00f5bf64865d0e821623ed29bc416405)
Reviewed-on: https://go-review.googlesource.com/c/go/+/606415
2024-08-21 17:05:16 +00:00
Kir Kolyshkin
dbecb416d1 [release-branch.go1.23] os: fix Chtimes test flakes
It appears that some builders (notably, linux-arm) have some additional
security software installed, which apparently reads the files created by
tests. As a result, test file atime is changed, making the test fail
like these:

=== RUN   TestChtimesOmit
    ...
    os_test.go:1475: atime mismatch, got: "2024-07-30 18:42:03.450932494 +0000 UTC", want: "2024-07-30 18:42:02.450932494 +0000 UTC"

=== RUN   TestChtimes
    ...
    os_test.go:1539: AccessTime didn't go backwards; was=2024-07-31 20:45:53.390326147 +0000 UTC, after=2024-07-31 20:45:53.394326118 +0000 UTC

According to inode(7), atime is changed when more than 0 bytes are read
from the file. So, one possible solution to these flakes is to make the
test files empty, so no one can read more than 0 bytes from them.

For #68687
For #68663
Fixes #68812

Change-Id: Ib9234567883ef7b16ff8811e3360cd26c2d6bdab
Reviewed-on: https://go-review.googlesource.com/c/go/+/604315
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Kirill Kolyshkin <kolyshkin@gmail.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
(cherry picked from commit 84266e1469cfa6fa8e1b41518528a96950db7562)
Reviewed-on: https://go-review.googlesource.com/c/go/+/604196
2024-08-14 17:44:07 +00:00
Gopher Robot
6885bad7dd [release-branch.go1.23] go1.23.0
Change-Id: I2b0514157b85ca61f9f6b8931df6ac874598a045
Reviewed-on: https://go-review.googlesource.com/c/go/+/605215
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Gopher Robot <gobot@golang.org>
Auto-Submit: Carlos Amedee <carlos@golang.org>
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-08-13 16:16:34 +00:00
Carlos Amedee
ec7d6094e6 [release-branch.go1.23] revert "go/types, types2: only use fileVersion if 1.21 or greater"
This reverts commit CL 604935.

Reason for revert: The team has decided that this change will be added to a point release.

Change-Id: I1c1032b881c3a98312a4753b9767cb7c8eed9e09
Reviewed-on: https://go-review.googlesource.com/c/go/+/605096
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
2024-08-13 14:45:01 +00:00
Michael Matloob
63b0f805cd [release-branch.go1.23] go/types, types2: only use fileVersion if 1.21 or greater
Only honor //go:build language version downgrades if the version
specified is 1.21 or greater. Before 1.21 the version in //go:build
lines didn't have the meaning of setting the file's language version.

This fixes an issue that was appearing in GOPATH builds: Go 1.23 started
providing -lang versions to the compiler in GOPATH mode (among other
places) which it wasn't doing before.

For example, take a go file with a //go:build line specifying go1.10.
If that file used a 1.18 feature, that use would compile fine with a Go
1.22 toolchain. But, before this change, it would produce an error when
compiling with the 1.23 toolchain because it set the language version to
1.10 and disallowed the 1.18 feature. This breaks backwards
compatibility: when the build tag was added, it did not have the meaning
of restricting the language version.

Fixes #68658

Change-Id: I4ac2b45a981cd019183d52ba324ba8f0fed93a8e
Reviewed-on: https://go-review.googlesource.com/c/go/+/603895
Reviewed-by: Robert Griesemer <gri@google.com>
Commit-Queue: Michael Matloob <matloob@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/604935
2024-08-12 20:21:53 +00:00
Filippo Valsorda
7adb012205 [release-branch.go1.23] crypto/tls: fix testHandshake close flakes
The flakes were introduced by me in CL 586655. It's unclear why only
FreeBSD seems affected, maybe other TCP stacks handle sending on a
half-closed connection differently, or aren't as quick to propagate the
RST over localhost.

Updates #68155

Change-Id: I32a1b474a7d6531dbab93910c23568b867629e8c
Reviewed-on: https://go-review.googlesource.com/c/go/+/602635
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2024-08-02 19:55:18 +00:00
Cuong Manh Le
c9940fe2a9 [release-branch.go1.23] types2, go/types: fix instantiation of named type with generic alias
The typechecker is assuming that alias instances cannot be reached from
a named type. However, when type parameters on aliases are permited, it
can happen.

This CL changes the typechecker to propagate the correct named instance
is being expanded.

Updates #46477
Fixes #68580

Change-Id: Id0879021f4640c0fefe277701d5096c649413811
Reviewed-on: https://go-review.googlesource.com/c/go/+/601115
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/601116
2024-07-26 16:35:29 +00:00
Robert Griesemer
3509415eca [release-branch.go1.23] cmd/compile: more informative panic when importing generic type alias
When GOEXPERIMENT=aliastypeparams is set, type aliases may have type
parameters. The compiler export data doesn't export that type parameter
information yet, which leads to an index-out-of-bounds panic when a
client package imports a package with a general type alias and then
refers to one of the missing type parameters.

This CL detects this specific case and panics with a more informative
panic message explaining the shortcoming. The change is only in effect
if the respective GOEXPERIMENT is enabled.

Manually tested. No test addded since this is just a temporary fix
(Go 1.24 will have a complete implementation), and because the existing
testing framework doesn't easily support testing that a compilation
panics.

Together with @taking and input from @rfindley.

For #68526.

Change-Id: I24737b153a7e2f9b705cd29a5b70b2b9e808dffc
Reviewed-on: https://go-review.googlesource.com/c/go/+/601035
Reviewed-by: Tim King <taking@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
2024-07-26 03:55:54 +00:00
Damien Neil
559c77592f [release-branch.go1.23] os: document CopyFS behavior for symlinks in destination
Also clarify the permissions of created files,
and note that CopyFS will not overwrite files.

Update a few places in documentation to use 0oXXX for octal consts.

For #62484

Change-Id: I208ed2bde250304bc7fac2b93963ba57037e791e
Reviewed-on: https://go-review.googlesource.com/c/go/+/600775
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
(cherry picked from commit 910e6b5fae7cbf84e4a3fcfa6739e20239080bcd)
Reviewed-on: https://go-review.googlesource.com/c/go/+/600815
Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-07-24 18:55:12 +00:00
Dmitri Shuralyov
f5e4e45ef7 [release-branch.go1.23] all: merge master (5e8a731) into release-branch.go1.23
Merge List:

+ 2024-07-22 5e8a731665 README: fix CC BY license name
+ 2024-07-22 a799fa5189 slices: explicitly document nil and empty slice equality
+ 2024-07-22 f0de94ff12 cmd/compile: don't inline runtime functions in -d=checkptr build
+ 2024-07-19 3959d54c0b runtime: mark lockWithRankMayAcquire as nosplit
+ 2024-07-17 70491a8111 maps: document handling of non-reflexive keys
+ 2024-07-17 7321aa91c6 cmd: vendor golang.org/x/telemetry@0b706e1
+ 2024-07-17 420037b16d os: don't try to signal PID -1 on Unix
+ 2024-07-17 87abb4afb6 runtime: avoid multiple records with identical stacks from MutexProfile
+ 2024-07-17 8c88f0c736 cmd/cgo/internal/testcarchive: remove 1-minute timeout
+ 2024-07-17 fc51e5023e math/big: fix comment typo in natdiv.go
+ 2024-07-17 90c6558b6a internal/bytealg: extend memchr result correctly on wasm
+ 2024-07-16 355711821e cmd/internal/cov: close counter data files eagerly
+ 2024-07-16 f2bcab5fb3 regexp: more cross-references in docstrings
+ 2024-07-16 9915b87059 bytes: more cross-references in docstrings
+ 2024-07-16 97ccc224f1 math/big: use lists in docstrings
+ 2024-07-16 66e940b6f8 math/big: more cross-references in docstrings
+ 2024-07-16 0dae393a26 encoding/binary: use list format in docstrings
+ 2024-07-16 451a284d80 strings,bytes,regexp: use lists in Split* docstrings
+ 2024-07-16 b4a92f56ff crypto/tls: add exclude tls flags to bogo_shim_test
+ 2024-07-16 3bfbfa821f encoding/json: document compact json output in Encoder.Encode
+ 2024-07-16 d5479e197d net: document ParseIP always returns IPv6 addresses
+ 2024-07-16 5c7f541386 archive/zip: document handling of duplicate names in Writer.Create
+ 2024-07-16 6b97448132 sort: add example for Find
+ 2024-07-16 8b48290895 cmd/compile: fix recursive generic interface instantiation
+ 2024-07-15 959b3fd426 flag: add FlagSet example

Change-Id: I0e7cac2f1cef42ccf3d392c57dad793ca3b08b11
2024-07-22 14:12:36 -04:00
Gopher Robot
30b6fd60a6 [release-branch.go1.23] go1.23rc2
Change-Id: I73a3f2e680a84aa698c6f64b1e924bb1b9a85a89
Reviewed-on: https://go-review.googlesource.com/c/go/+/598555
TryBot-Bypass: Carlos Amedee <carlos@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Carlos Amedee <carlos@golang.org>
Auto-Submit: Gopher Robot <gobot@golang.org>
2024-07-16 15:33:13 +00:00
Cherry Mui
7e4d6c2bcb [release-branch.go1.23] all: merge master (6948b4d) into release-branch.go1.23
Merge List:

+ 2024-07-15 6948b4df8c Revert "runtime: avoid multiple records with identical stacks from MutexProfile"

Change-Id: I94d1f445b0304eb4355ef6e91bf9f8585abfe0f8
2024-07-15 16:40:36 -04:00
Cherry Mui
8bd4ed6cbb [release-branch.go1.23] all: merge master (8f1ec59) into release-branch.go1.23
Merge List:

+ 2024-07-15 8f1ec59bdb strings: re-introduce noescape wrapper
+ 2024-07-15 5d36bc18d5 net/http: document io.Seeker requirement for fs.FS arguments
+ 2024-07-12 071b8d51c1 cmd: vendor golang.org/x/telemetry@268b4a8ec2d7
+ 2024-07-12 4e77872d16 go/types: fix assertion failure when range over int is not permitted
+ 2024-07-12 8bc32ab6b1 os: clean up after TestIssue60181
+ 2024-07-11 b31e9a63a4 unsafe: say "functions like syscall.Syscall", not only Syscall
+ 2024-07-11 a71bb570d0 all: make struct comments match struct names
+ 2024-07-11 611f18c4e9 strings: more cross-references in docstrings
+ 2024-07-11 08a6e080ca database/sql/driver: fix name in comment
+ 2024-07-11 dfaaa91f05 os: clarify that IsNotExist, IsExist, IsPermission and IsTimeout work with nil errors
+ 2024-07-10 5881d857c5 crypto/tls: add support for -expect-no-hrr to bogo_shim_test
+ 2024-07-10 b3040679ad math: remove riscv64 assembly implementations of rounding
+ 2024-07-10 70e453b436 context: handle nil values for valueCtx.String()
+ 2024-07-09 183a40db6d runtime: avoid multiple records with identical stacks from MutexProfile
+ 2024-07-09 e89e880eac crypto/tls: add support for -reject-alpn and -decline-alpn flags to bogo_shim_test
+ 2024-07-09 73186ba002 crypto/internal/cryptotest: add common tests for the hash.Hash interface
+ 2024-07-08 87ec2c959c testing: remove call to os.Exit in documentation for TestMain
+ 2024-07-08 6d89b38ed8 unsafe: clarify when String bytes can be modified
+ 2024-07-07 5565462a86 cmd/dist: remove iter,slices,maps test on GOEXPERIMENT=rangefunc
+ 2024-07-07 b43d6c57de io: add test for Pipe constructor allocations
+ 2024-07-07 d0146bd85b os/exec: only use cachedLookExtensions if Cmd.Path is unmodified
+ 2024-07-05 ad77cefeb2 cmd/compile: correct RewriteMultiValueCall fatal message
+ 2024-07-05 be152920b9 cmd/compile: fix ICE when compiling global a, b = f()
+ 2024-07-03 82c14346d8 cmd/link: don't disable memory profiling when pprof.WriteHeapProfile is used
+ 2024-07-03 7d19d508a9 cmd/cgo: read CGO_LDFLAGS environment variable
+ 2024-07-03 5f50b1e3bf cmd/compile: fix mis-compilation when switching over channels
+ 2024-07-03 71f9dbb1e4 cmd/compile: emit error message on mismatch import path
+ 2024-07-03 148755a27b cmd/link: document -checklinkname option
+ 2024-07-02 f12ac5be70 time: fix time zone parsing when format includes time zone seconds
+ 2024-07-02 09aeb6e33a os: add TODO about removing test exception
+ 2024-07-01 94982a0782 cmd/go/internal/workcmd: remove a potentially confusing statement
+ 2024-07-01 f71c00b616 cmd/link: align .reloc block starts by 32 bits for PE target
+ 2024-07-01 d3c93f2f00 cmd/go: update go clean help message
+ 2024-07-01 cdbf5f2f7e sync: refer to Locker interface methods in RWMutex.RLocker doc
+ 2024-07-01 c33144c47c runtime: fix nil pointer in TestGoroutineParallelism2 when offline
+ 2024-06-28 82c371a307 cmd/compile: drop internal range-over-func vars from DWARF output
+ 2024-06-28 773767def0 net/http: avoid appending an existing trailing slash to path again
+ 2024-06-28 7f90b960a9 cmd/compile: don't elide zero extension on top of signed values
+ 2024-06-27 ea537cca31 cmd/go/internal/help: add documentation for language version downgrading
+ 2024-06-27 b0927fdd49 slices: update docs for All, Backward, Values
+ 2024-06-26 5a18e79687 cmd/link: don't skip code sign even if dsymutil didn't generate a file
+ 2024-06-26 5f319b7507 cmd/link: don't let dsymutil delete our temp directory
+ 2024-06-26 a2e90be996 os: rewrite TestChtimesWithZeroTimes
+ 2024-06-25 90bcc552c0 crypto/tls: apply QUIC session event flag to QUICResumeSession events
+ 2024-06-25 b1fd047508 cmd/internal/obj/arm64: fix return with register
+ 2024-06-25 b3b4556c24 cmd/compile: update README to reflect dead code elimination changes
+ 2024-06-24 68315bc8ce cmd: run go mod tidy after CL 593684
+ 2024-06-24 f214a76075 cmd/vendor: vendor x/telemetry@38a4430
+ 2024-06-24 29b1a6765f net/http: document that Request.Clone does not deep copy Body
+ 2024-06-24 cf54a3d114 crypto/tls: replay test recordings without network
+ 2024-06-24 b98803e8e5 os: TestChtimes: separate hasNoatime
+ 2024-06-24 0def9d5c02 cmd/internal/obj/arm64: Enable arm64 assembler tests for cross-compiler builds
+ 2024-06-24 085cf0fcdc net/netip: add test that Compare and reflect.DeepEqual match
+ 2024-06-24 740043f516 net/netip: unexport fields of addrDetail
+ 2024-06-23 e8ee1dc4f9 cmd/link/internal/ld: handle "\r" in MinGW "--print-prog-name" output
+ 2024-06-22 44f1870666 cmd/link: handle dynamic import variables on Darwin in plugin mode
+ 2024-06-21 0af2148fdc cmd: vendor golang.org/x/telemetry@a740542
+ 2024-06-21 cb3b34349b doc/next: delete
+ 2024-06-21 d79c350916 cmd/internal: separate counter package from telemetry package
+ 2024-06-21 52ce25b44e cmd/vendor: pull in golang.org/x/telemetry@b4de734
+ 2024-06-21 fed2c11d67 iter: minor doc comment updates
+ 2024-06-21 d73a8a206a cmd/cgo: fail on v, err := C.fn when fn is a builtin function
+ 2024-06-21 1b4f1dc95d os: improve newFile, rm newDir
+ 2024-06-21 72e2220b50 encoding/json: clarify the map's key type for Unmarshal
+ 2024-06-21 e9a306e004 types2, go/types: correct NewTypeParam documentation
+ 2024-06-21 6fea409424 text/template/parse: fix handling of assignment/declaration in PipeNode.String
+ 2024-06-21 d67839f58a crypto/tls: add support for -expect-version to bogo_shim_test
+ 2024-06-21 201129414f sync/atomic: correct result names for Or methods
+ 2024-06-21 20b79fd577 time: provide non-default metric for asynctimerchan
+ 2024-06-20 9d33956503 internal/godebugs: fix old value for httpservecontentkeepheaders
+ 2024-06-20 477ad7dd51 cmd/compile: support generic alias type
+ 2024-06-18 4f77a83589 internal/syscall/unix: fix UTIME_OMIT for dragonfly

Change-Id: I3864b03b8c377e8fe82014eee96dc7b77aea64e2
2024-07-15 13:23:34 -04:00
Gopher Robot
7dff7439dc [release-branch.go1.23] go1.23rc1
Change-Id: Ied4bb63f49d13bd7d421cf9cb269220974641b89
Reviewed-on: https://go-review.googlesource.com/c/go/+/593897
Auto-Submit: David Chase <drchase@google.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
2024-06-21 16:32:19 +00:00
Damien Neil
62c3a6350b [release-branch.go1.23] internal/godebugs: fix old value for httpservecontentkeepheaders
The pre-Go 1.23 behavior is httpservecontentkeepheaders=1.

For #66343

Change-Id: If6f92853b38522f19a8908ff11ac49b12f3dc3e0
Reviewed-on: https://go-review.googlesource.com/c/go/+/593775
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/593795
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-06-20 19:14:07 +00:00
Cuong Manh Le
eba9e08766 [release-branch.go1.23] cmd/compile: support generic alias type
Type parameters on aliases are now allowed after #46477 accepted.

Updates #46477
Fixes #68054

Change-Id: Ic2e3b6f960a898163f47666e3a6bfe43b8cc22e2
Reviewed-on: https://go-review.googlesource.com/c/go/+/593715
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/593797
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-06-20 19:13:52 +00:00
Kir Kolyshkin
f3bdcda88a [release-branch.go1.23] internal/syscall/unix: fix UTIME_OMIT for dragonfly
CL 219638 added UTIME_OMIT values for various systems. The value for
DragonFly BSD appears to be incorrect.

The correct value is -2 (see references below), while -1 is used for
UTIME_NOW. As a result, timestamp is changed to the current time instead
of not touching. This should have been caught by the accompanying test
case, TestChtimesWithZeroTimes, but its failures are essentially skipped
on dragonfly (this is being fixed separately in a followup CL 591535).

Improve formatting while at it.

References:
 - https://github.com/DragonFlyBSD/DragonFlyBSD/blob/965b380e9609/sys/sys/stat.h#L284
 - https://go.googlesource.com/sys/+/refs/tags/v0.20.0/unix/zerrors_dragonfly_amd64.go#1421

Change-Id: I432360ca982c84b7cd70d0cf01d860af9ff985fa
Reviewed-on: https://go-review.googlesource.com/c/go/+/589496
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Commit-Queue: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/593796
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-06-20 19:13:34 +00:00
David Chase
362f22d2d2 [release-branch.go1.23] update codereview.cfg for release-branch.go1.23
Change-Id: Ib335bc903e2b8d5b7be6a158a6debe5db48e79a4
Reviewed-on: https://go-review.googlesource.com/c/go/+/593535
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: David Chase <drchase@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-06-18 21:25:28 +00:00
79 changed files with 1505 additions and 287 deletions

2
VERSION Normal file
View File

@ -0,0 +1,2 @@
go1.23.2
time 2024-09-28T01:34:15Z

View File

@ -1 +1,2 @@
branch: master
branch: release-branch.go1.23
parent-branch: master

View File

@ -2579,6 +2579,11 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
if dt.BitSize > 0 {
fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
switch t.Size {
default:
fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
@ -2595,9 +2600,8 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
Len: c.intExpr(t.Size),
Elt: c.uint8,
}
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
// t.Align is the alignment of the Go type.
t.Align = 1
}
case *dwarf.PtrType:
@ -2826,6 +2830,11 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
if dt.BitSize > 0 {
fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
switch t.Size {
default:
fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
@ -2842,9 +2851,8 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
Len: c.intExpr(t.Size),
Elt: c.uint8,
}
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
// t.Align is the alignment of the Go type.
t.Align = 1
}
case *dwarf.VoidType:
@ -3110,10 +3118,11 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
}
// Round off up to talign, assumed to be a power of 2.
origOff := off
off = (off + talign - 1) &^ (talign - 1)
if f.ByteOffset > off {
fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
fld, sizes = c.pad(fld, sizes, f.ByteOffset-origOff)
off = f.ByteOffset
}
if f.ByteOffset < off {

View File

@ -70,6 +70,7 @@ func Test31891(t *testing.T) { test31891(t) }
func Test42018(t *testing.T) { test42018(t) }
func Test45451(t *testing.T) { test45451(t) }
func Test49633(t *testing.T) { test49633(t) }
func Test69086(t *testing.T) { test69086(t) }
func TestAlign(t *testing.T) { testAlign(t) }
func TestAtol(t *testing.T) { testAtol(t) }
func TestBlocking(t *testing.T) { testBlocking(t) }

View File

@ -940,6 +940,19 @@ typedef struct {
} issue67517struct;
static void issue67517(issue67517struct* p) {}
// Issue 69086.
// GCC added the __int128 type in GCC 4.6, released in 2011.
typedef struct {
int a;
#ifdef __SIZEOF_INT128__
unsigned __int128 b;
#else
uint64_t b;
#endif
unsigned char c;
} issue69086struct;
static int issue690861(issue69086struct* p) { p->b = 1234; return p->c; }
static int issue690862(unsigned long ul1, unsigned long ul2, unsigned int u, issue69086struct s) { return (int)(s.b); }
*/
import "C"
@ -2349,3 +2362,24 @@ func issue67517() {
b: nil,
})
}
// Issue 69086.
func test69086(t *testing.T) {
var s C.issue69086struct
typ := reflect.TypeOf(s)
for i := 0; i < typ.NumField(); i++ {
f := typ.Field(i)
t.Logf("field %d: name %s size %d align %d offset %d", i, f.Name, f.Type.Size(), f.Type.Align(), f.Offset)
}
s.c = 1
got := C.issue690861(&s)
if got != 1 {
t.Errorf("field: got %d, want 1", got)
}
got = C.issue690862(1, 2, 3, s)
if got != 1234 {
t.Errorf("call: got %d, want 1234", got)
}
}

View File

@ -318,9 +318,9 @@ func containsClosure(f, c *ir.Func) bool {
return false
}
// Closures within function Foo are named like "Foo.funcN..."
// Closures within function Foo are named like "Foo.funcN..." or "Foo-rangeN".
// TODO(mdempsky): Better way to recognize this.
fn := f.Sym().Name
cn := c.Sym().Name
return len(cn) > len(fn) && cn[:len(fn)] == fn && cn[len(fn)] == '.'
return len(cn) > len(fn) && cn[:len(fn)] == fn && (cn[len(fn)] == '.' || cn[len(fn)] == '-')
}

View File

@ -9,6 +9,7 @@ import (
"cmd/compile/internal/syntax"
"cmd/compile/internal/types2"
"cmd/internal/src"
"internal/buildcfg"
"internal/pkgbits"
)
@ -411,6 +412,14 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types2.Package, string) {
panic("weird")
case pkgbits.ObjAlias:
if buildcfg.Experiment.AliasTypeParams && len(r.dict.bounds) > 0 {
// Temporary work-around for issue #68526: rather than panicking
// with an non-descriptive index-out-of-bounds panic when trying
// to access a missing type parameter, instead panic with a more
// descriptive error. Only needed for Go 1.23; Go 1.24 will have
// the correct implementation.
panic("importing generic type aliases is not supported in Go 1.23 (see issue #68526)")
}
pos := r.pos()
typ := r.typ()
return newAliasTypeName(pr.enableAlias, pos, objPkg, objName, typ)

View File

@ -134,10 +134,10 @@ func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
// newAliasInstance creates a new alias instance for the given origin and type
// arguments, recording pos as the position of its synthetic object (for error
// reporting).
func (check *Checker) newAliasInstance(pos syntax.Pos, orig *Alias, targs []Type, ctxt *Context) *Alias {
func (check *Checker) newAliasInstance(pos syntax.Pos, orig *Alias, targs []Type, expanding *Named, ctxt *Context) *Alias {
assert(len(targs) > 0)
obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil)
rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), nil, ctxt)
rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), expanding, ctxt)
res := check.newAlias(obj, rhs)
res.orig = orig
res.tparams = orig.tparams

View File

@ -2898,22 +2898,48 @@ func TestFileVersions(t *testing.T) {
fileVersion string
wantVersion string
}{
{"", "", ""}, // no versions specified
{"go1.19", "", "go1.19"}, // module version specified
{"", "go1.20", ""}, // file upgrade ignored
{"go1.19", "go1.20", "go1.20"}, // file upgrade permitted
{"go1.20", "go1.19", "go1.20"}, // file downgrade not permitted
{"go1.21", "go1.19", "go1.19"}, // file downgrade permitted (module version is >= go1.21)
{"", "", ""}, // no versions specified
{"go1.19", "", "go1.19"}, // module version specified
{"", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1", "", "go1"}, // no file version specified
{"go1", "goo1.22", "go1"}, // invalid file version specified
{"go1", "go1.19", "go1.21"}, // file version specified below minimum of 1.21
{"go1", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1", "go1.22", "go1.22"}, // file version specified above 1.21
{"go1.19", "", "go1.19"}, // no file version specified
{"go1.19", "goo1.22", "go1.19"}, // invalid file version specified
{"go1.19", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1.19", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1.19", "go1.22", "go1.22"}, // file version specified above 1.21
{"go1.20", "", "go1.20"}, // no file version specified
{"go1.20", "goo1.22", "go1.20"}, // invalid file version specified
{"go1.20", "go1.19", "go1.21"}, // file version specified below minimum of 1.21
{"go1.20", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1.20", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1.20", "go1.22", "go1.22"}, // file version specified above 1.21
{"go1.21", "", "go1.21"}, // no file version specified
{"go1.21", "goo1.22", "go1.21"}, // invalid file version specified
{"go1.21", "go1.19", "go1.21"}, // file version specified below minimum of 1.21
{"go1.21", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1.21", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1.21", "go1.22", "go1.22"}, // file version specified above 1.21
{"go1.22", "", "go1.22"}, // no file version specified
{"go1.22", "goo1.22", "go1.22"}, // invalid file version specified
{"go1.22", "go1.19", "go1.21"}, // file version specified below minimum of 1.21
{"go1.22", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1.22", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1.22", "go1.22", "go1.22"}, // file version specified above 1.21
// versions containing release numbers
// (file versions containing release numbers are considered invalid)
{"go1.19.0", "", "go1.19.0"}, // no file version specified
{"go1.20", "go1.20.1", "go1.20"}, // file upgrade ignored
{"go1.20.1", "go1.20", "go1.20.1"}, // file upgrade ignored
{"go1.20.1", "go1.21", "go1.21"}, // file upgrade permitted
{"go1.20.1", "go1.19", "go1.20.1"}, // file downgrade not permitted
{"go1.21.1", "go1.19.1", "go1.21.1"}, // file downgrade not permitted (invalid file version)
{"go1.21.1", "go1.19", "go1.19"}, // file downgrade permitted (module version is >= go1.21)
{"go1.20.1", "go1.19.1", "go1.20.1"}, // invalid file version
{"go1.20.1", "go1.21.1", "go1.20.1"}, // invalid file version
{"go1.21.1", "go1.19.1", "go1.21.1"}, // invalid file version
{"go1.21.1", "go1.21.1", "go1.21.1"}, // invalid file version
{"go1.22.1", "go1.19.1", "go1.22.1"}, // invalid file version
{"go1.22.1", "go1.21.1", "go1.22.1"}, // invalid file version
} {
var src string
if test.fileVersion != "" {

View File

@ -327,7 +327,6 @@ func (check *Checker) initFiles(files []*syntax.File) {
check.errorf(files[0], TooNew, "package requires newer Go version %v (application built with %v)",
check.version, go_current)
}
downgradeOk := check.version.cmp(go1_21) >= 0
// determine Go version for each file
for _, file := range check.files {
@ -336,33 +335,18 @@ func (check *Checker) initFiles(files []*syntax.File) {
// unlike file versions which are Go language versions only, if valid.)
v := check.conf.GoVersion
fileVersion := asGoVersion(file.GoVersion)
if fileVersion.isValid() {
// use the file version, if applicable
// (file versions are either the empty string or of the form go1.dd)
if pkgVersionOk {
cmp := fileVersion.cmp(check.version)
// Go 1.21 introduced the feature of setting the go.mod
// go line to an early version of Go and allowing //go:build lines
// to “upgrade” (cmp > 0) the Go version in a given file.
// We can do that backwards compatibly.
//
// Go 1.21 also introduced the feature of allowing //go:build lines
// to “downgrade” (cmp < 0) the Go version in a given file.
// That can't be done compatibly in general, since before the
// build lines were ignored and code got the module's Go version.
// To work around this, downgrades are only allowed when the
// module's Go version is Go 1.21 or later.
//
// If there is no valid check.version, then we don't really know what
// Go version to apply.
// Legacy tools may do this, and they historically have accepted everything.
// Preserve that behavior by ignoring //go:build constraints entirely in that
// case (!pkgVersionOk).
if cmp > 0 || cmp < 0 && downgradeOk {
v = file.GoVersion
}
}
// If the file specifies a version, use max(fileVersion, go1.21).
if fileVersion := asGoVersion(file.GoVersion); fileVersion.isValid() {
// Go 1.21 introduced the feature of allowing //go:build lines
// to sometimes set the Go version in a given file. Versions Go 1.21 and later
// can be set backwards compatibly as that was the first version
// files with go1.21 or later build tags could be built with.
//
// Set the version to max(fileVersion, go1.21): That will allow a
// downgrade to a version before go1.22, where the for loop semantics
// change was made, while being backwards compatible with versions of
// go before the new //go:build semantics were introduced.
v = string(versionMax(fileVersion, go1_21))
// Report a specific error for each tagged file that's too new.
// (Normally the build system will have filtered files by version,
@ -377,6 +361,13 @@ func (check *Checker) initFiles(files []*syntax.File) {
}
}
func versionMax(a, b goVersion) goVersion {
if a.cmp(b) > 0 {
return a
}
return b
}
// A bailout panic is used for early termination.
type bailout struct{}

View File

@ -11,6 +11,7 @@ import (
"cmd/compile/internal/syntax"
"errors"
"fmt"
"internal/buildcfg"
. "internal/types/errors"
)
@ -126,8 +127,9 @@ func (check *Checker) instance(pos syntax.Pos, orig genericType, targs []Type, e
res = check.newNamedInstance(pos, orig, targs, expanding) // substituted lazily
case *Alias:
// TODO(gri) is this correct?
assert(expanding == nil) // Alias instances cannot be reached from Named types
if !buildcfg.Experiment.AliasTypeParams {
assert(expanding == nil) // Alias instances cannot be reached from Named types
}
tparams := orig.TypeParams()
// TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here)
@ -138,7 +140,7 @@ func (check *Checker) instance(pos syntax.Pos, orig genericType, targs []Type, e
return orig // nothing to do (minor optimization)
}
return check.newAliasInstance(pos, orig, targs, ctxt)
return check.newAliasInstance(pos, orig, targs, expanding, ctxt)
case *Signature:
assert(expanding == nil) // function instances cannot be reached from Named types

View File

@ -1121,3 +1121,23 @@ func f(x int) {
t.Errorf("got: %s want: %s", got, want)
}
}
func TestIssue68877(t *testing.T) {
const src = `
package p
type (
S struct{}
A = S
T A
)`
conf := Config{EnableAlias: true}
pkg := mustTypecheck(src, &conf, nil)
T := pkg.Scope().Lookup("T").(*TypeName)
got := T.String() // this must not panic (was issue)
const want = "type p.T struct{}"
if got != want {
t.Errorf("got %s, want %s", got, want)
}
}

View File

@ -282,7 +282,7 @@ func (t *Named) cleanup() {
if t.TypeArgs().Len() == 0 {
panic("nil underlying")
}
case *Named:
case *Named, *Alias:
t.under() // t.under may add entries to check.cleaners
}
t.check = nil

View File

@ -115,7 +115,7 @@ func (subst *subster) typ(typ Type) Type {
// that has a type argument for it.
targs, updated := subst.typeList(t.TypeArgs().list())
if updated {
return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.ctxt)
return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.expanding, subst.ctxt)
}
case *Array:

View File

@ -131,8 +131,8 @@ func (s *_TypeSet) underIs(f func(Type) bool) bool {
}
for _, t := range s.terms {
assert(t.typ != nil)
// x == under(x) for ~x terms
u := t.typ
// Unalias(x) == under(x) for ~x terms
u := Unalias(t.typ)
if !t.tilde {
u = under(u)
}

View File

@ -9,7 +9,7 @@ require (
golang.org/x/mod v0.19.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.22.0
golang.org/x/telemetry v0.0.0-20240717194752-0b706e19b701
golang.org/x/telemetry v0.0.0-20240828213427-40b6b7fe7147
golang.org/x/term v0.20.0
golang.org/x/tools v0.22.1-0.20240618181713-f2d2ebe43e72
)

View File

@ -16,8 +16,8 @@ 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.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-20240717194752-0b706e19b701 h1:+bltxAtk8YFEQ61B/lcYQM8e+7XjLwSDbpspVaVYkz8=
golang.org/x/telemetry v0.0.0-20240717194752-0b706e19b701/go.mod h1:amNmu/SBSm2GAF3X+9U2C0epLocdh+r5Z+7oMYO5cLM=
golang.org/x/telemetry v0.0.0-20240828213427-40b6b7fe7147 h1:Lj8KbuZmoFUbI6pQ28G3Diz/5bRYD2UY5vfAmhrLZWo=
golang.org/x/telemetry v0.0.0-20240828213427-40b6b7fe7147/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=

View File

@ -16,6 +16,7 @@ import (
"os"
"os/exec"
"path/filepath"
"sync/atomic"
"golang.org/x/telemetry/internal/telemetry"
)
@ -29,12 +30,22 @@ const (
// creation flag.
var needNoConsole = func(cmd *exec.Cmd) {}
var downloads int64
// Downloads reports, for testing purposes, the number of times [Download] has
// been called.
func Downloads() int64 {
return atomic.LoadInt64(&downloads)
}
// Download fetches the requested telemetry UploadConfig using "go mod
// download". If envOverlay is provided, it is appended to the environment used
// for invoking the go command.
//
// The second result is the canonical version of the requested configuration.
func Download(version string, envOverlay []string) (*telemetry.UploadConfig, string, error) {
atomic.AddInt64(&downloads, 1)
if version == "" {
version = "latest"
}

View File

@ -21,12 +21,12 @@ import (
"golang.org/x/telemetry/internal/counter"
)
// Supported reports whether the runtime supports [runtime.SetCrashOutput].
// Supported reports whether the runtime supports [runtime/debug.SetCrashOutput].
//
// TODO(adonovan): eliminate once go1.23+ is assured.
func Supported() bool { return setCrashOutput != nil }
var setCrashOutput func(*os.File) error // = runtime.SetCrashOutput on go1.23+
var setCrashOutput func(*os.File) error // = runtime/debug.SetCrashOutput on go1.23+
// Parent sets up the parent side of the crashmonitor. It requires
// exclusive use of a writable pipe connected to the child process's stdin.

View File

@ -112,9 +112,24 @@ func newUploader(rcfg RunConfig) (*uploader, error) {
logger := log.New(logWriter, "", log.Ltime|log.Lmicroseconds|log.Lshortfile)
// Fetch the upload config, if it is not provided.
config, configVersion, err := configstore.Download("latest", rcfg.Env)
if err != nil {
return nil, err
var (
config *telemetry.UploadConfig
configVersion string
)
if mode, _ := dir.Mode(); mode == "on" {
// golang/go#68946: only download the upload config if it will be used.
//
// TODO(rfindley): This is a narrow change aimed at minimally fixing the
// associated bug. In the future, we should read the mode only once during
// the upload process.
config, configVersion, err = configstore.Download("latest", rcfg.Env)
if err != nil {
return nil, err
}
} else {
config = &telemetry.UploadConfig{}
configVersion = "v0.0.0-0"
}
// Set the start time, if it is not provided.

View File

@ -206,7 +206,8 @@ func startChild(reportCrashes, upload bool, result *StartResult) {
fd, err := os.Stat(telemetry.Default.DebugDir())
if err != nil {
if !os.IsNotExist(err) {
log.Fatalf("failed to stat debug directory: %v", err)
log.Printf("failed to stat debug directory: %v", err)
return
}
} else if fd.IsDir() {
// local/debug exists and is a directory. Set stderr to a log file path
@ -214,23 +215,31 @@ func startChild(reportCrashes, upload bool, result *StartResult) {
childLogPath := filepath.Join(telemetry.Default.DebugDir(), "sidecar.log")
childLog, err := os.OpenFile(childLogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
log.Fatalf("opening sidecar log file for child: %v", err)
log.Printf("opening sidecar log file for child: %v", err)
return
}
defer childLog.Close()
cmd.Stderr = childLog
}
var crashOutputFile *os.File
if reportCrashes {
pipe, err := cmd.StdinPipe()
if err != nil {
log.Fatalf("StdinPipe: %v", err)
log.Printf("StdinPipe: %v", err)
return
}
crashmonitor.Parent(pipe.(*os.File)) // (this conversion is safe)
crashOutputFile = pipe.(*os.File) // (this conversion is safe)
}
if err := cmd.Start(); err != nil {
log.Fatalf("can't start telemetry child process: %v", err)
// The child couldn't be started. Log the failure.
log.Printf("can't start telemetry child process: %v", err)
return
}
if reportCrashes {
crashmonitor.Parent(crashOutputFile)
}
result.wg.Add(1)
go func() {

View File

@ -45,7 +45,7 @@ golang.org/x/sync/semaphore
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
# golang.org/x/telemetry v0.0.0-20240717194752-0b706e19b701
# golang.org/x/telemetry v0.0.0-20240828213427-40b6b7fe7147
## explicit; go 1.20
golang.org/x/telemetry
golang.org/x/telemetry/counter

View File

@ -491,9 +491,10 @@ func testHandshake(t *testing.T, clientConfig, serverConfig *Config) (serverStat
if got := string(buf); got != sentinel {
t.Errorf("read %q from TLS connection, but expected %q", got, sentinel)
}
if err := cli.Close(); err != nil {
t.Errorf("failed to call cli.Close: %v", err)
}
// We discard the error because after ReadAll returns the server must
// have already closed the connection. Sending data (the closeNotify
// alert) can cause a reset, that will make Close return an error.
cli.Close()
}()
server := Server(s, serverConfig)
err = server.Handshake()

View File

@ -1368,8 +1368,8 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
db.waitDuration.Add(int64(time.Since(waitStart)))
// If we failed to delete it, that means something else
// grabbed it and is about to send on it.
// If we failed to delete it, that means either the DB was closed or
// something else grabbed it and is about to send on it.
if !deleted {
// TODO(bradfitz): rather than this best effort select, we
// should probably start a goroutine to read from req. This best
@ -3594,6 +3594,7 @@ type connRequestAndIndex struct {
// and clears the set.
func (s *connRequestSet) CloseAndRemoveAll() {
for _, v := range s.s {
*v.curIdx = -1
close(v.req)
}
s.s = nil

View File

@ -4920,6 +4920,17 @@ func TestConnRequestSet(t *testing.T) {
t.Error("wasn't random")
}
})
t.Run("close-delete", func(t *testing.T) {
reset()
ch := make(chan connRequest)
dh := s.Add(ch)
wantLen(1)
s.CloseAndRemoveAll()
wantLen(0)
if s.Delete(dh) {
t.Error("unexpected delete after CloseAndRemoveAll")
}
})
}
func BenchmarkConnRequestSet(b *testing.B) {

View File

@ -911,8 +911,11 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
var maxIgnoreNestingDepth = 10000
// decIgnoreOpFor returns the decoding op for a field that has no destination.
func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp, depth int) *decOp {
if depth > maxIgnoreNestingDepth {
func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp {
// Track how deep we've recursed trying to skip nested ignored fields.
dec.ignoreDepth++
defer func() { dec.ignoreDepth-- }()
if dec.ignoreDepth > maxIgnoreNestingDepth {
error_(errors.New("invalid nesting depth"))
}
// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
@ -938,7 +941,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp,
errorf("bad data: undefined type %s", wireId.string())
case wire.ArrayT != nil:
elemId := wire.ArrayT.Elem
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len)
}
@ -946,15 +949,15 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp,
case wire.MapT != nil:
keyId := dec.wireType[wireId].MapT.Key
elemId := dec.wireType[wireId].MapT.Elem
keyOp := dec.decIgnoreOpFor(keyId, inProgress, depth+1)
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
keyOp := dec.decIgnoreOpFor(keyId, inProgress)
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreMap(state, *keyOp, *elemOp)
}
case wire.SliceT != nil:
elemId := wire.SliceT.Elem
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreSlice(state, *elemOp)
}
@ -1115,7 +1118,7 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
func (dec *Decoder) compileIgnoreSingle(remoteId typeId) *decEngine {
engine := new(decEngine)
engine.instr = make([]decInstr, 1) // one item
op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp), 0)
op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp))
ovfl := overflow(dec.typeString(remoteId))
engine.instr[0] = decInstr{*op, 0, nil, ovfl}
engine.numInstr = 1
@ -1160,7 +1163,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
localField, present := srt.FieldByName(wireField.Name)
// TODO(r): anonymous names
if !present || !isExported(wireField.Name) {
op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp), 0)
op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp))
engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl}
continue
}

View File

@ -35,6 +35,8 @@ type Decoder struct {
freeList *decoderState // list of free decoderStates; avoids reallocation
countBuf []byte // used for decoding integers while parsing messages
err error
// ignoreDepth tracks the depth of recursively parsed ignored fields
ignoreDepth int
}
// NewDecoder returns a new decoder that reads from the [io.Reader].

View File

@ -806,6 +806,8 @@ func TestIgnoreDepthLimit(t *testing.T) {
defer func() { maxIgnoreNestingDepth = oldNestingDepth }()
b := new(bytes.Buffer)
enc := NewEncoder(b)
// Nested slice
typ := reflect.TypeFor[int]()
nested := reflect.ArrayOf(1, typ)
for i := 0; i < 100; i++ {
@ -819,4 +821,16 @@ func TestIgnoreDepthLimit(t *testing.T) {
if err := dec.Decode(&output); err == nil || err.Error() != expectedErr {
t.Errorf("Decode didn't fail with depth limit of 100: want %q, got %q", expectedErr, err)
}
// Nested struct
nested = reflect.StructOf([]reflect.StructField{{Name: "F", Type: typ}})
for i := 0; i < 100; i++ {
nested = reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}})
}
badStruct = reflect.New(reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}}))
enc.Encode(badStruct.Interface())
dec = NewDecoder(b)
if err := dec.Decode(&output); err == nil || err.Error() != expectedErr {
t.Errorf("Decode didn't fail with depth limit of 100: want %q, got %q", expectedErr, err)
}
}

View File

@ -16,6 +16,10 @@ import (
"unicode/utf8"
)
// maxSize is a limit used to control the complexity of expressions, in order
// to prevent stack exhaustion issues due to recursion.
const maxSize = 1000
// An Expr is a build tag constraint expression.
// The underlying concrete type is *[AndExpr], *[OrExpr], *[NotExpr], or *[TagExpr].
type Expr interface {
@ -151,7 +155,7 @@ func Parse(line string) (Expr, error) {
return parseExpr(text)
}
if text, ok := splitPlusBuild(line); ok {
return parsePlusBuildExpr(text), nil
return parsePlusBuildExpr(text)
}
return nil, errNotConstraint
}
@ -201,6 +205,8 @@ type exprParser struct {
tok string // last token read
isTag bool
pos int // position (start) of last token
size int
}
// parseExpr parses a boolean build tag expression.
@ -249,6 +255,10 @@ func (p *exprParser) and() Expr {
// On entry, the next input token has not yet been lexed.
// On exit, the next input token has been lexed and is in p.tok.
func (p *exprParser) not() Expr {
p.size++
if p.size > maxSize {
panic(&SyntaxError{Offset: p.pos, Err: "build expression too large"})
}
p.lex()
if p.tok == "!" {
p.lex()
@ -388,7 +398,13 @@ func splitPlusBuild(line string) (expr string, ok bool) {
}
// parsePlusBuildExpr parses a legacy build tag expression (as used with “// +build”).
func parsePlusBuildExpr(text string) Expr {
func parsePlusBuildExpr(text string) (Expr, error) {
// Only allow up to 100 AND/OR operators for "old" syntax.
// This is much less than the limit for "new" syntax,
// but uses of old syntax were always very simple.
const maxOldSize = 100
size := 0
var x Expr
for _, clause := range strings.Fields(text) {
var y Expr
@ -414,19 +430,25 @@ func parsePlusBuildExpr(text string) Expr {
if y == nil {
y = z
} else {
if size++; size > maxOldSize {
return nil, errComplex
}
y = and(y, z)
}
}
if x == nil {
x = y
} else {
if size++; size > maxOldSize {
return nil, errComplex
}
x = or(x, y)
}
}
if x == nil {
x = tag("ignore")
}
return x
return x, nil
}
// isValidTag reports whether the word is a valid build tag.

View File

@ -222,7 +222,7 @@ var parsePlusBuildExprTests = []struct {
func TestParsePlusBuildExpr(t *testing.T) {
for i, tt := range parsePlusBuildExprTests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
x := parsePlusBuildExpr(tt.in)
x, _ := parsePlusBuildExpr(tt.in)
if x.String() != tt.x.String() {
t.Errorf("parsePlusBuildExpr(%q):\nhave %v\nwant %v", tt.in, x, tt.x)
}
@ -319,3 +319,66 @@ func TestPlusBuildLines(t *testing.T) {
})
}
}
func TestSizeLimits(t *testing.T) {
for _, tc := range []struct {
name string
expr string
}{
{
name: "go:build or limit",
expr: "//go:build " + strings.Repeat("a || ", maxSize+2),
},
{
name: "go:build and limit",
expr: "//go:build " + strings.Repeat("a && ", maxSize+2),
},
{
name: "go:build and depth limit",
expr: "//go:build " + strings.Repeat("(a &&", maxSize+2),
},
{
name: "go:build or depth limit",
expr: "//go:build " + strings.Repeat("(a ||", maxSize+2),
},
} {
t.Run(tc.name, func(t *testing.T) {
_, err := Parse(tc.expr)
if err == nil {
t.Error("expression did not trigger limit")
} else if syntaxErr, ok := err.(*SyntaxError); !ok || syntaxErr.Err != "build expression too large" {
if !ok {
t.Errorf("unexpected error: %v", err)
} else {
t.Errorf("unexpected syntax error: %s", syntaxErr.Err)
}
}
})
}
}
func TestPlusSizeLimits(t *testing.T) {
maxOldSize := 100
for _, tc := range []struct {
name string
expr string
}{
{
name: "+build or limit",
expr: "// +build " + strings.Repeat("a ", maxOldSize+2),
},
{
name: "+build and limit",
expr: "// +build " + strings.Repeat("a,", maxOldSize+2),
},
} {
t.Run(tc.name, func(t *testing.T) {
_, err := Parse(tc.expr)
if err == nil {
t.Error("expression did not trigger limit")
} else if err != errComplex {
t.Errorf("unexpected error: got %q, want %q", err, errComplex)
}
})
}
}

View File

@ -1676,6 +1676,8 @@ func (p *parser) parseElementList() (list []ast.Expr) {
}
func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
defer decNestLev(incNestLev(p))
if p.trace {
defer un(trace(p, "LiteralValue"))
}

View File

@ -598,10 +598,11 @@ var parseDepthTests = []struct {
{name: "chan2", format: "package main; var x «<-chan »int"},
{name: "interface", format: "package main; var x «interface { M() «int» }»", scope: true, scopeMultiplier: 2}, // Scopes: InterfaceType, FuncType
{name: "map", format: "package main; var x «map[int]»int"},
{name: "slicelit", format: "package main; var x = «[]any{«»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit
{name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit
{name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit
{name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 2}, // Parser nodes: CompositeLit, KeyValueExpr
{name: "slicelit", format: "package main; var x = []any{«[]any{«»}»}", parseMultiplier: 3}, // Parser nodes: UnaryExpr, CompositeLit
{name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 3}, // Parser nodes: UnaryExpr, CompositeLit
{name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 3}, // Parser nodes: UnaryExpr, CompositeLit
{name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 3}, // Parser nodes: CompositeLit, KeyValueExpr
{name: "element", format: "package main; var x = struct{x any}{x: «{«»}»}"},
{name: "dot", format: "package main; var x = «x.»x"},
{name: "index", format: "package main; var x = x«[1]»"},
{name: "slice", format: "package main; var x = x«[1:2]»"},

View File

@ -137,10 +137,10 @@ func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
// newAliasInstance creates a new alias instance for the given origin and type
// arguments, recording pos as the position of its synthetic object (for error
// reporting).
func (check *Checker) newAliasInstance(pos token.Pos, orig *Alias, targs []Type, ctxt *Context) *Alias {
func (check *Checker) newAliasInstance(pos token.Pos, orig *Alias, targs []Type, expanding *Named, ctxt *Context) *Alias {
assert(len(targs) > 0)
obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil)
rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), nil, ctxt)
rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), expanding, ctxt)
res := check.newAlias(obj, rhs)
res.orig = orig
res.tparams = orig.tparams

View File

@ -2904,22 +2904,48 @@ func TestFileVersions(t *testing.T) {
fileVersion string
wantVersion string
}{
{"", "", ""}, // no versions specified
{"go1.19", "", "go1.19"}, // module version specified
{"", "go1.20", ""}, // file upgrade ignored
{"go1.19", "go1.20", "go1.20"}, // file upgrade permitted
{"go1.20", "go1.19", "go1.20"}, // file downgrade not permitted
{"go1.21", "go1.19", "go1.19"}, // file downgrade permitted (module version is >= go1.21)
{"", "", ""}, // no versions specified
{"go1.19", "", "go1.19"}, // module version specified
{"", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1", "", "go1"}, // no file version specified
{"go1", "goo1.22", "go1"}, // invalid file version specified
{"go1", "go1.19", "go1.21"}, // file version specified below minimum of 1.21
{"go1", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1", "go1.22", "go1.22"}, // file version specified above 1.21
{"go1.19", "", "go1.19"}, // no file version specified
{"go1.19", "goo1.22", "go1.19"}, // invalid file version specified
{"go1.19", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1.19", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1.19", "go1.22", "go1.22"}, // file version specified above 1.21
{"go1.20", "", "go1.20"}, // no file version specified
{"go1.20", "goo1.22", "go1.20"}, // invalid file version specified
{"go1.20", "go1.19", "go1.21"}, // file version specified below minimum of 1.21
{"go1.20", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1.20", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1.20", "go1.22", "go1.22"}, // file version specified above 1.21
{"go1.21", "", "go1.21"}, // no file version specified
{"go1.21", "goo1.22", "go1.21"}, // invalid file version specified
{"go1.21", "go1.19", "go1.21"}, // file version specified below minimum of 1.21
{"go1.21", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1.21", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1.21", "go1.22", "go1.22"}, // file version specified above 1.21
{"go1.22", "", "go1.22"}, // no file version specified
{"go1.22", "goo1.22", "go1.22"}, // invalid file version specified
{"go1.22", "go1.19", "go1.21"}, // file version specified below minimum of 1.21
{"go1.22", "go1.20", "go1.21"}, // file version specified below minimum of 1.21
{"go1.22", "go1.21", "go1.21"}, // file version specified at 1.21
{"go1.22", "go1.22", "go1.22"}, // file version specified above 1.21
// versions containing release numbers
// (file versions containing release numbers are considered invalid)
{"go1.19.0", "", "go1.19.0"}, // no file version specified
{"go1.20", "go1.20.1", "go1.20"}, // file upgrade ignored
{"go1.20.1", "go1.20", "go1.20.1"}, // file upgrade ignored
{"go1.20.1", "go1.21", "go1.21"}, // file upgrade permitted
{"go1.20.1", "go1.19", "go1.20.1"}, // file downgrade not permitted
{"go1.21.1", "go1.19.1", "go1.21.1"}, // file downgrade not permitted (invalid file version)
{"go1.21.1", "go1.19", "go1.19"}, // file downgrade permitted (module version is >= go1.21)
{"go1.20.1", "go1.19.1", "go1.20.1"}, // invalid file version
{"go1.20.1", "go1.21.1", "go1.20.1"}, // invalid file version
{"go1.21.1", "go1.19.1", "go1.21.1"}, // invalid file version
{"go1.21.1", "go1.21.1", "go1.21.1"}, // invalid file version
{"go1.22.1", "go1.19.1", "go1.22.1"}, // invalid file version
{"go1.22.1", "go1.21.1", "go1.22.1"}, // invalid file version
} {
var src string
if test.fileVersion != "" {

View File

@ -349,7 +349,6 @@ func (check *Checker) initFiles(files []*ast.File) {
check.errorf(files[0], TooNew, "package requires newer Go version %v (application built with %v)",
check.version, go_current)
}
downgradeOk := check.version.cmp(go1_21) >= 0
// determine Go version for each file
for _, file := range check.files {
@ -358,33 +357,19 @@ func (check *Checker) initFiles(files []*ast.File) {
// unlike file versions which are Go language versions only, if valid.)
v := check.conf.GoVersion
fileVersion := asGoVersion(file.GoVersion)
if fileVersion.isValid() {
// use the file version, if applicable
// (file versions are either the empty string or of the form go1.dd)
if pkgVersionOk {
cmp := fileVersion.cmp(check.version)
// Go 1.21 introduced the feature of setting the go.mod
// go line to an early version of Go and allowing //go:build lines
// to “upgrade” (cmp > 0) the Go version in a given file.
// We can do that backwards compatibly.
//
// Go 1.21 also introduced the feature of allowing //go:build lines
// to “downgrade” (cmp < 0) the Go version in a given file.
// That can't be done compatibly in general, since before the
// build lines were ignored and code got the module's Go version.
// To work around this, downgrades are only allowed when the
// module's Go version is Go 1.21 or later.
//
// If there is no valid check.version, then we don't really know what
// Go version to apply.
// Legacy tools may do this, and they historically have accepted everything.
// Preserve that behavior by ignoring //go:build constraints entirely in that
// case (!pkgVersionOk).
if cmp > 0 || cmp < 0 && downgradeOk {
v = file.GoVersion
}
}
// If the file specifies a version, use max(fileVersion, go1.21).
if fileVersion := asGoVersion(file.GoVersion); fileVersion.isValid() {
// Go 1.21 introduced the feature of setting the go.mod
// go line to an early version of Go and allowing //go:build lines
// to set the Go version in a given file. Versions Go 1.21 and later
// can be set backwards compatibly as that was the first version
// files with go1.21 or later build tags could be built with.
//
// Set the version to max(fileVersion, go1.21): That will allow a
// downgrade to a version before go1.22, where the for loop semantics
// change was made, while being backwards compatible with versions of
// go before the new //go:build semantics were introduced.
v = string(versionMax(fileVersion, go1_21))
// Report a specific error for each tagged file that's too new.
// (Normally the build system will have filtered files by version,
@ -399,6 +384,13 @@ func (check *Checker) initFiles(files []*ast.File) {
}
}
func versionMax(a, b goVersion) goVersion {
if a.cmp(b) < 0 {
return b
}
return a
}
// A bailout panic is used for early termination.
type bailout struct{}

View File

@ -14,6 +14,7 @@ import (
"errors"
"fmt"
"go/token"
"internal/buildcfg"
. "internal/types/errors"
)
@ -129,8 +130,9 @@ func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, ex
res = check.newNamedInstance(pos, orig, targs, expanding) // substituted lazily
case *Alias:
// TODO(gri) is this correct?
assert(expanding == nil) // Alias instances cannot be reached from Named types
if !buildcfg.Experiment.AliasTypeParams {
assert(expanding == nil) // Alias instances cannot be reached from Named types
}
tparams := orig.TypeParams()
// TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here)
@ -141,7 +143,7 @@ func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, ex
return orig // nothing to do (minor optimization)
}
return check.newAliasInstance(pos, orig, targs, ctxt)
return check.newAliasInstance(pos, orig, targs, expanding, ctxt)
case *Signature:
assert(expanding == nil) // function instances cannot be reached from Named types

View File

@ -1131,3 +1131,23 @@ func f(x int) {
t.Errorf("got: %s want: %s", got, want)
}
}
func TestIssue68877(t *testing.T) {
const src = `
package p
type (
S struct{}
A = S
T A
)`
t.Setenv("GODEBUG", "gotypesalias=1")
pkg := mustTypecheck(src, nil, nil)
T := pkg.Scope().Lookup("T").(*TypeName)
got := T.String() // this must not panic (was issue)
const want = "type p.T struct{}"
if got != want {
t.Errorf("got %s, want %s", got, want)
}
}

View File

@ -285,7 +285,7 @@ func (t *Named) cleanup() {
if t.TypeArgs().Len() == 0 {
panic("nil underlying")
}
case *Named:
case *Named, *Alias:
t.under() // t.under may add entries to check.cleaners
}
t.check = nil

View File

@ -118,7 +118,7 @@ func (subst *subster) typ(typ Type) Type {
// that has a type argument for it.
targs, updated := subst.typeList(t.TypeArgs().list())
if updated {
return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.ctxt)
return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.expanding, subst.ctxt)
}
case *Array:

View File

@ -134,8 +134,8 @@ func (s *_TypeSet) underIs(f func(Type) bool) bool {
}
for _, t := range s.terms {
assert(t.typ != nil)
// x == under(x) for ~x terms
u := t.typ
// Unalias(x) == under(x) for ~x terms
u := Unalias(t.typ)
if !t.tilde {
u = under(u)
}

View File

@ -177,6 +177,15 @@ func TypeOf(a any) *Type {
return (*Type)(NoEscape(unsafe.Pointer(eface.Type)))
}
// TypeFor returns the abi.Type for a type parameter.
func TypeFor[T any]() *Type {
var v T
if t := TypeOf(v); t != nil {
return t // optimize for T being a non-interface kind
}
return TypeOf((*T)(nil)).Elem() // only for an interface kind
}
func (t *Type) Kind() Kind { return t.Kind_ & KindMask }
func (t *Type) HasName() bool {

View File

@ -14,4 +14,4 @@ type Slice []byte
type Array [8]byte
var s Slice
var p = (Array)(s /* ok because Go 1.20 ignored the //go:build go1.19 */)
var p = (Array)(s /* ok because file versions below go1.21 set the langage version to go1.21 */)

View File

@ -14,4 +14,4 @@ type Slice []byte
type Array [8]byte
var s Slice
var p = (Array)(s /* ERROR "requires go1.20 or later" */)
var p = (Array)(s /* ok because file versions below go1.21 set the langage version to go1.21 */)

View File

@ -0,0 +1,16 @@
// -lang=go1.21
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Check Go language version-specific errors.
//go:build go1.22
package p
func f() {
for _ = range /* ok because of upgrade to 1.22 */ 10 {
}
}

View File

@ -0,0 +1,16 @@
// -lang=go1.22
// 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.
// Check Go language version-specific errors.
//go:build go1.21
package p
func f() {
for _ = range 10 /* ERROR "requires go1.22 or later" */ {
}
}

View File

@ -1,14 +1,9 @@
// -lang=go1.21
// -lang=go1.13
// 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.
// Note: Downgrading to go1.13 requires at least go1.21,
// hence the need for -lang=go1.21 at the top.
//go:build go1.13
package p
import "io"

View File

@ -0,0 +1,24 @@
// 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 A = [4]int
type B = map[string]interface{}
func _[T ~A](x T) {
_ = len(x)
}
func _[U ~A](x U) {
_ = cap(x)
}
func _[V ~A]() {
_ = V{}
}
func _[W ~B](a interface{}) {
_ = a.(W)["key"]
}

View File

@ -0,0 +1,26 @@
// 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 A = struct {
F string
G int
}
func Make[T ~A]() T {
return T{
F: "blah",
G: 1234,
}
}
type N struct {
F string
G int
}
func _() {
_ = Make[N]()
}

View File

@ -5,9 +5,12 @@
package weak_test
import (
"context"
"internal/weak"
"runtime"
"sync"
"testing"
"time"
)
type T struct {
@ -128,3 +131,82 @@ func TestPointerFinalizer(t *testing.T) {
t.Errorf("weak pointer is non-nil even after finalization: %v", wt)
}
}
// Regression test for issue 69210.
//
// Weak-to-strong conversions must shade the new strong pointer, otherwise
// that might be creating the only strong pointer to a white object which
// is hidden in a blackened stack.
//
// Never fails if correct, fails with some high probability if incorrect.
func TestIssue69210(t *testing.T) {
if testing.Short() {
t.Skip("this is a stress test that takes seconds to run on its own")
}
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
// What we're trying to do is manufacture the conditions under which this
// bug happens. Specifically, we want:
//
// 1. To create a whole bunch of objects that are only weakly-pointed-to,
// 2. To call Strong while the GC is in the mark phase,
// 3. The new strong pointer to be missed by the GC,
// 4. The following GC cycle to mark a free object.
//
// Unfortunately, (2) and (3) are hard to control, but we can increase
// the likelihood by having several goroutines do (1) at once while
// another goroutine constantly keeps us in the GC with runtime.GC.
// Like throwing darts at a dart board until they land just right.
// We can increase the likelihood of (4) by adding some delay after
// creating the strong pointer, but only if it's non-nil. If it's nil,
// that means it was already collected in which case there's no chance
// of triggering the bug, so we want to retry as fast as possible.
// Our heap here is tiny, so the GCs will go by fast.
//
// As of 2024-09-03, removing the line that shades pointers during
// the weak-to-strong conversion causes this test to fail about 50%
// of the time.
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for {
runtime.GC()
select {
case <-ctx.Done():
return
default:
}
}
}()
for range max(runtime.GOMAXPROCS(-1)-1, 1) {
wg.Add(1)
go func() {
defer wg.Done()
for {
for range 5 {
bt := new(T)
wt := weak.Make(bt)
bt = nil
time.Sleep(1 * time.Millisecond)
bt = wt.Strong()
if bt != nil {
time.Sleep(4 * time.Millisecond)
bt.t = bt
bt.a = 12
}
runtime.KeepAlive(bt)
}
select {
case <-ctx.Done():
return
default:
}
}
}()
}
wg.Wait()
}

View File

@ -132,15 +132,18 @@ func ReadDir(name string) ([]DirEntry, error) {
// CopyFS copies the file system fsys into the directory dir,
// creating dir if necessary.
//
// Newly created directories and files have their default modes
// where any bits from the file in fsys that are not part of the
// standard read, write, and execute permissions will be zeroed
// out, and standard read and write permissions are set for owner,
// group, and others while retaining any existing execute bits from
// the file in fsys.
// Files are created with mode 0o666 plus any execute permissions
// from the source, and directories are created with mode 0o777
// (before umask).
//
// Symbolic links in fsys are not supported, a *PathError with Err set
// to ErrInvalid is returned on symlink.
// CopyFS will not overwrite existing files. If a file name in fsys
// already exists in the destination, CopyFS will return an error
// such that errors.Is(err, fs.ErrExist) will be true.
//
// Symbolic links in fsys are not supported. A *PathError with Err set
// to ErrInvalid is returned when copying from a symbolic link.
//
// Symbolic links in dir are followed.
//
// Copying stops at and returns the first error encountered.
func CopyFS(dir string, fsys fs.FS) error {
@ -174,7 +177,7 @@ func CopyFS(dir string, fsys fs.FS) error {
if err != nil {
return err
}
w, err := OpenFile(newPath, O_CREATE|O_TRUNC|O_WRONLY, 0666|info.Mode()&0777)
w, err := OpenFile(newPath, O_CREATE|O_EXCL|O_WRONLY, 0666|info.Mode()&0777)
if err != nil {
return err
}

View File

@ -61,7 +61,7 @@ func ExampleFileMode() {
log.Fatal(err)
}
fmt.Printf("permissions: %#o\n", fi.Mode().Perm()) // 0400, 0777, etc.
fmt.Printf("permissions: %#o\n", fi.Mode().Perm()) // 0o400, 0o777, etc.
switch mode := fi.Mode(); {
case mode.IsRegular():
fmt.Println("regular file")

View File

@ -35,10 +35,11 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
}
}
attrSys, shouldDupPidfd := ensurePidfd(attr.Sys)
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
Sys: ensurePidfd(attr.Sys),
Sys: attrSys,
}
if sysattr.Env == nil {
sysattr.Env, err = execenv.Default(sysattr.Sys)
@ -63,7 +64,7 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
// For Windows, syscall.StartProcess above already returned a process handle.
if runtime.GOOS != "windows" {
var ok bool
h, ok = getPidfd(sysattr.Sys)
h, ok = getPidfd(sysattr.Sys, shouldDupPidfd)
if !ok {
return newPIDProcess(pid), nil
}

View File

@ -366,7 +366,7 @@ func Open(name string) (*File, error) {
}
// Create creates or truncates the named file. If the file already exists,
// it is truncated. If the file does not exist, it is created with mode 0666
// it is truncated. If the file does not exist, it is created with mode 0o666
// (before umask). If successful, methods on the returned File can
// be used for I/O; the associated file descriptor has mode O_RDWR.
// If there is an error, it will be of type *PathError.
@ -602,11 +602,11 @@ func UserHomeDir() (string, error) {
// On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and
// ModeSticky are used.
//
// On Windows, only the 0200 bit (owner writable) of mode is used; it
// On Windows, only the 0o200 bit (owner writable) of mode is used; it
// controls whether the file's read-only attribute is set or cleared.
// The other bits are currently unused. For compatibility with Go 1.12
// and earlier, use a non-zero mode. Use mode 0400 for a read-only
// file and 0600 for a readable+writable file.
// and earlier, use a non-zero mode. Use mode 0o400 for a read-only
// file and 0o600 for a readable+writable file.
//
// On Plan 9, the mode's permission bits, ModeAppend, ModeExclusive,
// and ModeTemporary are used.

View File

@ -1376,8 +1376,7 @@ func TestChtimes(t *testing.T) {
t.Parallel()
f := newFile(t)
f.Write([]byte("hello, world\n"))
// This should be an empty file (see #68687, #68663).
f.Close()
testChtimes(t, f.Name())
@ -1395,12 +1394,9 @@ func TestChtimesOmit(t *testing.T) {
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.Fatal(err)
}
// This should be an empty file (see #68687, #68663).
name := file.Name()
err = file.Close()
err := file.Close()
if err != nil {
t.Error(err)
}
@ -3358,6 +3354,14 @@ func TestCopyFS(t *testing.T) {
t.Fatal("comparing two directories:", err)
}
// Test whether CopyFS disallows copying for disk filesystem when there is any
// existing file in the destination directory.
if err := CopyFS(tmpDir, fsys); !errors.Is(err, fs.ErrExist) {
t.Errorf("CopyFS should have failed and returned error when there is"+
"any existing file in the destination directory (in disk filesystem), "+
"got: %v, expected any error that indicates <file exists>", err)
}
// Test with memory filesystem.
fsys = fstest.MapFS{
"william": {Data: []byte("Shakespeare\n")},
@ -3395,6 +3399,14 @@ func TestCopyFS(t *testing.T) {
}); err != nil {
t.Fatal("comparing two directories:", err)
}
// Test whether CopyFS disallows copying for memory filesystem when there is any
// existing file in the destination directory.
if err := CopyFS(tmpDir, fsys); !errors.Is(err, fs.ErrExist) {
t.Errorf("CopyFS should have failed and returned error when there is"+
"any existing file in the destination directory (in memory filesystem), "+
"got: %v, expected any error that indicates <file exists>", err)
}
}
func TestCopyFSWithSymlinks(t *testing.T) {

View File

@ -19,9 +19,12 @@ import (
"unsafe"
)
func ensurePidfd(sysAttr *syscall.SysProcAttr) *syscall.SysProcAttr {
// ensurePidfd initializes the PidFD field in sysAttr if it is not already set.
// It returns the original or modified SysProcAttr struct and a flag indicating
// whether the PidFD should be duplicated before using.
func ensurePidfd(sysAttr *syscall.SysProcAttr) (*syscall.SysProcAttr, bool) {
if !pidfdWorks() {
return sysAttr
return sysAttr, false
}
var pidfd int
@ -29,23 +32,33 @@ func ensurePidfd(sysAttr *syscall.SysProcAttr) *syscall.SysProcAttr {
if sysAttr == nil {
return &syscall.SysProcAttr{
PidFD: &pidfd,
}
}, false
}
if sysAttr.PidFD == nil {
newSys := *sysAttr // copy
newSys.PidFD = &pidfd
return &newSys
return &newSys, false
}
return sysAttr
return sysAttr, true
}
func getPidfd(sysAttr *syscall.SysProcAttr) (uintptr, bool) {
// getPidfd returns the value of sysAttr.PidFD (or its duplicate if needDup is
// set) and a flag indicating whether the value can be used.
func getPidfd(sysAttr *syscall.SysProcAttr, needDup bool) (uintptr, bool) {
if !pidfdWorks() {
return 0, false
}
return uintptr(*sysAttr.PidFD), true
h := *sysAttr.PidFD
if needDup {
dupH, e := unix.Fcntl(h, syscall.F_DUPFD_CLOEXEC, 0)
if e != nil {
return 0, false
}
h = dupH
}
return uintptr(h), true
}
func pidfdFind(pid int) (uintptr, error) {

View File

@ -6,8 +6,10 @@ package os_test
import (
"errors"
"internal/syscall/unix"
"internal/testenv"
"os"
"os/exec"
"syscall"
"testing"
)
@ -57,3 +59,93 @@ func TestFindProcessViaPidfd(t *testing.T) {
t.Fatalf("Release: got %v, want <nil>", err)
}
}
func TestStartProcessWithPidfd(t *testing.T) {
testenv.MustHaveGoBuild(t)
t.Parallel()
if err := os.CheckPidfdOnce(); err != nil {
// Non-pidfd code paths tested in exec_unix_test.go.
t.Skipf("skipping: pidfd not available: %v", err)
}
var pidfd int
p, err := os.StartProcess(testenv.GoToolPath(t), []string{"go"}, &os.ProcAttr{
Sys: &syscall.SysProcAttr{
PidFD: &pidfd,
},
})
if err != nil {
t.Fatalf("starting test process: %v", err)
}
defer syscall.Close(pidfd)
if _, err := p.Wait(); err != nil {
t.Fatalf("Wait: got %v, want <nil>", err)
}
// Check the pidfd is still valid
err = unix.PidFDSendSignal(uintptr(pidfd), syscall.Signal(0))
if !errors.Is(err, syscall.ESRCH) {
t.Errorf("SendSignal: got %v, want %v", err, syscall.ESRCH)
}
}
// Issue #69284
func TestPidfdLeak(t *testing.T) {
testenv.MustHaveExec(t)
exe, err := os.Executable()
if err != nil {
t.Fatal(err)
}
// Find the next 10 descriptors.
// We need to get more than one descriptor in practice;
// the pidfd winds up not being the next descriptor.
const count = 10
want := make([]int, count)
for i := range count {
var err error
want[i], err = syscall.Open(exe, syscall.O_RDONLY, 0)
if err != nil {
t.Fatal(err)
}
}
// Close the descriptors.
for _, d := range want {
syscall.Close(d)
}
// Start a process 10 times.
for range 10 {
// For testing purposes this has to be an absolute path.
// Otherwise we will fail finding the executable
// and won't start a process at all.
cmd := exec.Command("/noSuchExecutable")
cmd.Run()
}
// Open the next 10 descriptors again.
got := make([]int, count)
for i := range count {
var err error
got[i], err = syscall.Open(exe, syscall.O_RDONLY, 0)
if err != nil {
t.Fatal(err)
}
}
// Close the descriptors
for _, d := range got {
syscall.Close(d)
}
t.Logf("got %v", got)
t.Logf("want %v", want)
// Allow some slack for runtime epoll descriptors and the like.
if got[count-1] > want[count-1]+5 {
t.Errorf("got descriptor %d, want %d", got[count-1], want[count-1])
}
}

View File

@ -8,11 +8,11 @@ package os
import "syscall"
func ensurePidfd(sysAttr *syscall.SysProcAttr) *syscall.SysProcAttr {
return sysAttr
func ensurePidfd(sysAttr *syscall.SysProcAttr) (*syscall.SysProcAttr, bool) {
return sysAttr, false
}
func getPidfd(_ *syscall.SysProcAttr) (uintptr, bool) {
func getPidfd(_ *syscall.SysProcAttr, _ bool) (uintptr, bool) {
return 0, false
}

View File

@ -338,9 +338,14 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) {
// stack. However, since we're returning to an earlier stack frame and
// need to pair with the entersyscall() call made by cgocall, we must
// save syscall* and let reentersyscall restore them.
//
// Note: savedsp and savedbp MUST be held in locals as an unsafe.Pointer.
// When we call into Go, the stack is free to be moved. If these locals
// aren't visible in the stack maps, they won't get updated properly,
// and will end up being stale when restored by reentersyscall.
savedsp := unsafe.Pointer(gp.syscallsp)
savedpc := gp.syscallpc
savedbp := gp.syscallbp
savedbp := unsafe.Pointer(gp.syscallbp)
exitsyscall() // coming out of cgo call
gp.m.incgo = false
if gp.m.isextra {
@ -372,7 +377,7 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) {
osPreemptExtEnter(gp.m)
// going back to cgo call
reentersyscall(savedpc, uintptr(savedsp), savedbp)
reentersyscall(savedpc, uintptr(savedsp), uintptr(savedbp))
gp.m.winsyscall = winsyscall
}

View File

@ -1209,6 +1209,11 @@ func (h *hmap) sameSizeGrow() bool {
return h.flags&sameSizeGrow != 0
}
//go:linkname sameSizeGrowForIssue69110Test
func sameSizeGrowForIssue69110Test(h *hmap) bool {
return h.sameSizeGrow()
}
// noldbuckets calculates the number of buckets prior to the current map growth.
func (h *hmap) noldbuckets() uintptr {
oldB := h.B
@ -1668,7 +1673,16 @@ func moveToBmap(t *maptype, h *hmap, dst *bmap, pos int, src *bmap) (*bmap, int)
}
func mapclone2(t *maptype, src *hmap) *hmap {
dst := makemap(t, src.count, nil)
hint := src.count
if overLoadFactor(hint, src.B) {
// Note: in rare cases (e.g. during a same-sized grow) the map
// can be overloaded. Make sure we don't allocate a destination
// bucket array larger than the source bucket array.
// This will cause the cloned map to be overloaded also,
// but that's better than crashing. See issue 69110.
hint = int(loadFactorNum * (bucketShift(src.B) / loadFactorDen))
}
dst := makemap(t, hint, nil)
dst.hash0 = src.hash0
dst.nevacuate = 0
// flags do not need to be copied here, just like a new map has no flags.

View File

@ -2073,7 +2073,22 @@ func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer {
// Even if we just swept some random span that doesn't contain this object, because
// this object is long dead and its memory has since been reused, we'll just observe nil.
ptr := unsafe.Pointer(handle.Load())
// This is responsible for maintaining the same GC-related
// invariants as the Yuasa part of the write barrier. During
// the mark phase, it's possible that we just created the only
// valid pointer to the object pointed to by ptr. If it's only
// ever referenced from our stack, and our stack is blackened
// already, we could fail to mark it. So, mark it now.
if gcphase != _GCoff {
shade(uintptr(ptr))
}
releasem(mp)
// Explicitly keep ptr alive. This seems unnecessary since we return ptr,
// but let's be explicit since it's important we keep ptr alive across the
// call to shade.
KeepAlive(ptr)
return ptr
}
@ -2081,6 +2096,9 @@ func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer {
func getOrAddWeakHandle(p unsafe.Pointer) *atomic.Uintptr {
// First try to retrieve without allocating.
if handle := getWeakHandle(p); handle != nil {
// Keep p alive for the duration of the function to ensure
// that it cannot die while we're trying to do this.
KeepAlive(p)
return handle
}
@ -2105,6 +2123,10 @@ func getOrAddWeakHandle(p unsafe.Pointer) *atomic.Uintptr {
scanblock(uintptr(unsafe.Pointer(&s.handle)), goarch.PtrSize, &oneptrmask[0], gcw, nil)
releasem(mp)
}
// Keep p alive for the duration of the function to ensure
// that it cannot die while we're trying to do this.
KeepAlive(p)
return s.handle
}
@ -2124,7 +2146,7 @@ func getOrAddWeakHandle(p unsafe.Pointer) *atomic.Uintptr {
}
// Keep p alive for the duration of the function to ensure
// that it cannot die while we're trying to this.
// that it cannot die while we're trying to do this.
KeepAlive(p)
return handle
}
@ -2154,6 +2176,9 @@ func getWeakHandle(p unsafe.Pointer) *atomic.Uintptr {
unlock(&span.speciallock)
releasem(mp)
// Keep p alive for the duration of the function to ensure
// that it cannot die while we're trying to do this.
KeepAlive(p)
return handle
}

View File

@ -4415,7 +4415,13 @@ func reentersyscall(pc, sp, bp uintptr) {
}
if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
systemstack(func() {
print("entersyscall inconsistent ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
print("entersyscall inconsistent sp ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
throw("entersyscall")
})
}
if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp {
systemstack(func() {
print("entersyscall inconsistent bp ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
throw("entersyscall")
})
}
@ -4553,14 +4559,20 @@ func entersyscallblock() {
sp2 := gp.sched.sp
sp3 := gp.syscallsp
systemstack(func() {
print("entersyscallblock inconsistent ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
print("entersyscallblock inconsistent sp ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
throw("entersyscallblock")
})
}
casgstatus(gp, _Grunning, _Gsyscall)
if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
systemstack(func() {
print("entersyscallblock inconsistent ", hex(sp), " ", hex(gp.sched.sp), " ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
print("entersyscallblock inconsistent sp ", hex(sp), " ", hex(gp.sched.sp), " ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
throw("entersyscallblock")
})
}
if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp {
systemstack(func() {
print("entersyscallblock inconsistent bp ", hex(bp), " ", hex(gp.sched.bp), " ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
throw("entersyscallblock")
})
}

View File

@ -41,6 +41,8 @@ TEXT _main(SB),NOSPLIT,$-8
MOVD R12, CTR
BR (CTR)
// Paramater save space required to cross-call into _cgo_sys_thread_create
#define PARAM_SPACE 16
TEXT _rt0_ppc64_aix_lib(SB),NOSPLIT,$-8
// Start with standard C stack frame layout and linkage.
@ -49,45 +51,45 @@ TEXT _rt0_ppc64_aix_lib(SB),NOSPLIT,$-8
MOVW CR, R0 // Save CR in caller's frame
MOVD R0, 8(R1)
MOVDU R1, -344(R1) // Allocate frame.
MOVDU R1, -344-PARAM_SPACE(R1) // Allocate frame.
// Preserve callee-save registers.
MOVD R14, 48(R1)
MOVD R15, 56(R1)
MOVD R16, 64(R1)
MOVD R17, 72(R1)
MOVD R18, 80(R1)
MOVD R19, 88(R1)
MOVD R20, 96(R1)
MOVD R21,104(R1)
MOVD R22, 112(R1)
MOVD R23, 120(R1)
MOVD R24, 128(R1)
MOVD R25, 136(R1)
MOVD R26, 144(R1)
MOVD R27, 152(R1)
MOVD R28, 160(R1)
MOVD R29, 168(R1)
MOVD g, 176(R1) // R30
MOVD R31, 184(R1)
FMOVD F14, 192(R1)
FMOVD F15, 200(R1)
FMOVD F16, 208(R1)
FMOVD F17, 216(R1)
FMOVD F18, 224(R1)
FMOVD F19, 232(R1)
FMOVD F20, 240(R1)
FMOVD F21, 248(R1)
FMOVD F22, 256(R1)
FMOVD F23, 264(R1)
FMOVD F24, 272(R1)
FMOVD F25, 280(R1)
FMOVD F26, 288(R1)
FMOVD F27, 296(R1)
FMOVD F28, 304(R1)
FMOVD F29, 312(R1)
FMOVD F30, 320(R1)
FMOVD F31, 328(R1)
MOVD R14, 48+PARAM_SPACE(R1)
MOVD R15, 56+PARAM_SPACE(R1)
MOVD R16, 64+PARAM_SPACE(R1)
MOVD R17, 72+PARAM_SPACE(R1)
MOVD R18, 80+PARAM_SPACE(R1)
MOVD R19, 88+PARAM_SPACE(R1)
MOVD R20, 96+PARAM_SPACE(R1)
MOVD R21,104+PARAM_SPACE(R1)
MOVD R22, 112+PARAM_SPACE(R1)
MOVD R23, 120+PARAM_SPACE(R1)
MOVD R24, 128+PARAM_SPACE(R1)
MOVD R25, 136+PARAM_SPACE(R1)
MOVD R26, 144+PARAM_SPACE(R1)
MOVD R27, 152+PARAM_SPACE(R1)
MOVD R28, 160+PARAM_SPACE(R1)
MOVD R29, 168+PARAM_SPACE(R1)
MOVD g, 176+PARAM_SPACE(R1) // R30
MOVD R31, 184+PARAM_SPACE(R1)
FMOVD F14, 192+PARAM_SPACE(R1)
FMOVD F15, 200+PARAM_SPACE(R1)
FMOVD F16, 208+PARAM_SPACE(R1)
FMOVD F17, 216+PARAM_SPACE(R1)
FMOVD F18, 224+PARAM_SPACE(R1)
FMOVD F19, 232+PARAM_SPACE(R1)
FMOVD F20, 240+PARAM_SPACE(R1)
FMOVD F21, 248+PARAM_SPACE(R1)
FMOVD F22, 256+PARAM_SPACE(R1)
FMOVD F23, 264+PARAM_SPACE(R1)
FMOVD F24, 272+PARAM_SPACE(R1)
FMOVD F25, 280+PARAM_SPACE(R1)
FMOVD F26, 288+PARAM_SPACE(R1)
FMOVD F27, 296+PARAM_SPACE(R1)
FMOVD F28, 304+PARAM_SPACE(R1)
FMOVD F29, 312+PARAM_SPACE(R1)
FMOVD F30, 320+PARAM_SPACE(R1)
FMOVD F31, 328+PARAM_SPACE(R1)
// Synchronous initialization.
MOVD $runtime·reginit(SB), R12
@ -130,44 +132,44 @@ nocgo:
done:
// Restore saved registers.
MOVD 48(R1), R14
MOVD 56(R1), R15
MOVD 64(R1), R16
MOVD 72(R1), R17
MOVD 80(R1), R18
MOVD 88(R1), R19
MOVD 96(R1), R20
MOVD 104(R1), R21
MOVD 112(R1), R22
MOVD 120(R1), R23
MOVD 128(R1), R24
MOVD 136(R1), R25
MOVD 144(R1), R26
MOVD 152(R1), R27
MOVD 160(R1), R28
MOVD 168(R1), R29
MOVD 176(R1), g // R30
MOVD 184(R1), R31
FMOVD 196(R1), F14
FMOVD 200(R1), F15
FMOVD 208(R1), F16
FMOVD 216(R1), F17
FMOVD 224(R1), F18
FMOVD 232(R1), F19
FMOVD 240(R1), F20
FMOVD 248(R1), F21
FMOVD 256(R1), F22
FMOVD 264(R1), F23
FMOVD 272(R1), F24
FMOVD 280(R1), F25
FMOVD 288(R1), F26
FMOVD 296(R1), F27
FMOVD 304(R1), F28
FMOVD 312(R1), F29
FMOVD 320(R1), F30
FMOVD 328(R1), F31
MOVD 48+PARAM_SPACE(R1), R14
MOVD 56+PARAM_SPACE(R1), R15
MOVD 64+PARAM_SPACE(R1), R16
MOVD 72+PARAM_SPACE(R1), R17
MOVD 80+PARAM_SPACE(R1), R18
MOVD 88+PARAM_SPACE(R1), R19
MOVD 96+PARAM_SPACE(R1), R20
MOVD 104+PARAM_SPACE(R1), R21
MOVD 112+PARAM_SPACE(R1), R22
MOVD 120+PARAM_SPACE(R1), R23
MOVD 128+PARAM_SPACE(R1), R24
MOVD 136+PARAM_SPACE(R1), R25
MOVD 144+PARAM_SPACE(R1), R26
MOVD 152+PARAM_SPACE(R1), R27
MOVD 160+PARAM_SPACE(R1), R28
MOVD 168+PARAM_SPACE(R1), R29
MOVD 176+PARAM_SPACE(R1), g // R30
MOVD 184+PARAM_SPACE(R1), R31
FMOVD 196+PARAM_SPACE(R1), F14
FMOVD 200+PARAM_SPACE(R1), F15
FMOVD 208+PARAM_SPACE(R1), F16
FMOVD 216+PARAM_SPACE(R1), F17
FMOVD 224+PARAM_SPACE(R1), F18
FMOVD 232+PARAM_SPACE(R1), F19
FMOVD 240+PARAM_SPACE(R1), F20
FMOVD 248+PARAM_SPACE(R1), F21
FMOVD 256+PARAM_SPACE(R1), F22
FMOVD 264+PARAM_SPACE(R1), F23
FMOVD 272+PARAM_SPACE(R1), F24
FMOVD 280+PARAM_SPACE(R1), F25
FMOVD 288+PARAM_SPACE(R1), F26
FMOVD 296+PARAM_SPACE(R1), F27
FMOVD 304+PARAM_SPACE(R1), F28
FMOVD 312+PARAM_SPACE(R1), F29
FMOVD 320+PARAM_SPACE(R1), F30
FMOVD 328+PARAM_SPACE(R1), F31
ADD $344, R1
ADD $344+PARAM_SPACE, R1
MOVD 8(R1), R0
MOVFL R0, $0xff

View File

@ -26,10 +26,40 @@ type timer struct {
// mu protects reads and writes to all fields, with exceptions noted below.
mu mutex
astate atomic.Uint8 // atomic copy of state bits at last unlock
state uint8 // state bits
isChan bool // timer has a channel; immutable; can be read without lock
blocked uint32 // number of goroutines blocked on timer's channel
astate atomic.Uint8 // atomic copy of state bits at last unlock
state uint8 // state bits
isChan bool // timer has a channel; immutable; can be read without lock
// isSending is used to handle races between running a
// channel timer and stopping or resetting the timer.
// It is used only for channel timers (t.isChan == true).
// The lowest zero bit is set when about to send a value on the channel,
// and cleared after sending the value.
// The stop/reset code uses this to detect whether it
// stopped the channel send.
//
// An isSending bit is set only when t.mu is held.
// An isSending bit is cleared only when t.sendLock is held.
// isSending is read only when both t.mu and t.sendLock are held.
//
// Setting and clearing Uint8 bits handles the case of
// a timer that is reset concurrently with unlockAndRun.
// If the reset timer runs immediately, we can wind up with
// concurrent calls to unlockAndRun for the same timer.
// Using matched bit set and clear in unlockAndRun
// ensures that the value doesn't get temporarily out of sync.
//
// We use a uint8 to keep the timer struct small.
// This means that we can only support up to 8 concurrent
// runs of a timer, where a concurrent run can only occur if
// we start a run, unlock the timer, the timer is reset to a new
// value (or the ticker fires again), it is ready to run,
// and it is actually run, all before the first run completes.
// Since completing a run is fast, even 2 concurrent timer runs are
// nearly impossible, so this should be safe in practice.
isSending atomic.Uint8
blocked uint32 // number of goroutines blocked on timer's channel
// Timer wakes up at when, and then at when+period, ... (period > 0 only)
// each time calling f(arg, seq, delay) in the timer goroutine, so f must be
@ -431,6 +461,15 @@ func (t *timer) stop() bool {
// Stop any future sends with stale values.
// See timer.unlockAndRun.
t.seq++
// If there is currently a send in progress,
// incrementing seq is going to prevent that
// send from actually happening. That means
// that we should return true: the timer was
// stopped, even though t.when may be zero.
if t.isSending.Load() > 0 {
pending = true
}
}
t.unlock()
if !async && t.isChan {
@ -525,6 +564,15 @@ func (t *timer) modify(when, period int64, f func(arg any, seq uintptr, delay in
// Stop any future sends with stale values.
// See timer.unlockAndRun.
t.seq++
// If there is currently a send in progress,
// incrementing seq is going to prevent that
// send from actually happening. That means
// that we should return true: the timer was
// stopped, even though t.when may be zero.
if t.isSending.Load() > 0 {
pending = true
}
}
t.unlock()
if !async && t.isChan {
@ -1013,6 +1061,24 @@ func (t *timer) unlockAndRun(now int64) {
}
t.updateHeap()
}
async := debug.asynctimerchan.Load() != 0
var isSendingClear uint8
if !async && t.isChan {
// Tell Stop/Reset that we are sending a value.
// Set the lowest zero bit.
// We do this awkward step because atomic.Uint8
// doesn't support Add or CompareAndSwap.
// We only set bits with t locked.
v := t.isSending.Load()
i := sys.TrailingZeros8(^v)
if i == 8 {
throw("too many concurrent timer firings")
}
isSendingClear = 1 << i
t.isSending.Or(isSendingClear)
}
t.unlock()
if raceenabled {
@ -1028,7 +1094,6 @@ func (t *timer) unlockAndRun(now int64) {
ts.unlock()
}
async := debug.asynctimerchan.Load() != 0
if !async && t.isChan {
// For a timer channel, we want to make sure that no stale sends
// happen after a t.stop or t.modify, but we cannot hold t.mu
@ -1044,6 +1109,10 @@ func (t *timer) unlockAndRun(now int64) {
// and double-check that t.seq is still the seq value we saw above.
// If not, the timer has been updated and we should skip the send.
// We skip the send by reassigning f to a no-op function.
//
// The isSending field tells t.stop or t.modify that we have
// started to send the value. That lets them correctly return
// true meaning that no value was sent.
lock(&t.sendLock)
if t.seq != seq {
f = func(any, uintptr, int64) {}
@ -1053,6 +1122,9 @@ func (t *timer) unlockAndRun(now int64) {
f(arg, seq, delay)
if !async && t.isChan {
// We are no longer sending a value.
t.isSending.And(^isSendingClear)
unlock(&t.sendLock)
}

View File

@ -293,3 +293,8 @@ childerror:
RawSyscall(SYS_EXIT, 253, 0, 0)
}
}
// forkAndExecFailureCleanup cleans up after an exec failure.
func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) {
// Nothing to do.
}

View File

@ -317,3 +317,8 @@ childerror:
RawSyscall(SYS_EXIT, 253, 0, 0)
}
}
// forkAndExecFailureCleanup cleans up after an exec failure.
func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) {
// Nothing to do.
}

View File

@ -314,6 +314,11 @@ childerror:
}
}
// forkAndExecFailureCleanup cleans up after an exec failure.
func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) {
// Nothing to do.
}
func ioctlPtr(fd, req uintptr, arg unsafe.Pointer) (err Errno) {
return ioctl(fd, req, uintptr(arg))
}

View File

@ -289,3 +289,8 @@ childerror:
rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), 253, 0, 0)
}
}
// forkAndExecFailureCleanup cleans up after an exec failure.
func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) {
// Nothing to do.
}

View File

@ -735,3 +735,11 @@ func writeUidGidMappings(pid int, sys *SysProcAttr) error {
return nil
}
// forkAndExecFailureCleanup cleans up after an exec failure.
func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) {
if sys.PidFD != nil && *sys.PidFD != -1 {
Close(*sys.PidFD)
*sys.PidFD = -1
}
}

View File

@ -237,6 +237,10 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
for err1 == EINTR {
_, err1 = Wait4(pid, &wstatus, 0, nil)
}
// OS-specific cleanup on failure.
forkAndExecFailureCleanup(attr, sys)
return 0, err
}

View File

@ -785,6 +785,68 @@ func TestAdjustTimers(t *testing.T) {
}
}
func TestStopResult(t *testing.T) {
testStopResetResult(t, true)
}
func TestResetResult(t *testing.T) {
testStopResetResult(t, false)
}
// Test that when racing between running a timer and stopping a timer Stop
// consistently indicates whether a value can be read from the channel.
// Issue #69312.
func testStopResetResult(t *testing.T, testStop bool) {
for _, name := range []string{"0", "1", "2"} {
t.Run("asynctimerchan="+name, func(t *testing.T) {
testStopResetResultGODEBUG(t, testStop, name)
})
}
}
func testStopResetResultGODEBUG(t *testing.T, testStop bool, godebug string) {
t.Setenv("GODEBUG", "asynctimerchan="+godebug)
stopOrReset := func(timer *Timer) bool {
if testStop {
return timer.Stop()
} else {
return timer.Reset(1 * Hour)
}
}
start := make(chan struct{})
var wg sync.WaitGroup
const N = 1000
wg.Add(N)
for range N {
go func() {
defer wg.Done()
<-start
for j := 0; j < 100; j++ {
timer1 := NewTimer(1 * Millisecond)
timer2 := NewTimer(1 * Millisecond)
select {
case <-timer1.C:
if !stopOrReset(timer2) {
// The test fails if this
// channel read times out.
<-timer2.C
}
case <-timer2.C:
if !stopOrReset(timer1) {
// The test fails if this
// channel read times out.
<-timer1.C
}
}
}
}()
}
close(start)
wg.Wait()
}
// Benchmark timer latency when the thread that creates the timer is busy with
// other work and the timers must be serviced by other threads.
// https://golang.org/issue/38860

View File

@ -27,7 +27,7 @@ func cSeq(stringOffsets ...uintptr) cloneSeq {
func testCloneSeq[T any](t *testing.T, want cloneSeq) {
typName := reflect.TypeFor[T]().Name()
typ := abi.TypeOf(*new(T))
typ := abi.TypeFor[T]()
t.Run(typName, func(t *testing.T) {
got := makeCloneSeq(typ)
if !reflect.DeepEqual(got, want) {

View File

@ -31,7 +31,7 @@ func (h Handle[T]) Value() T {
// are equal if and only if the values used to produce them are equal.
func Make[T comparable](value T) Handle[T] {
// Find the map for type T.
typ := abi.TypeOf(value)
typ := abi.TypeFor[T]()
ma, ok := uniqueMaps.Load(typ)
if !ok {
// This is a good time to initialize cleanup, since we must go through
@ -50,13 +50,13 @@ func Make[T comparable](value T) Handle[T] {
toInsert *T // Keep this around to keep it alive.
toInsertWeak weak.Pointer[T]
)
newValue := func() weak.Pointer[T] {
newValue := func() (T, weak.Pointer[T]) {
if toInsert == nil {
toInsert = new(T)
*toInsert = clone(value, &m.cloneSeq)
toInsertWeak = weak.Make(toInsert)
}
return toInsertWeak
return *toInsert, toInsertWeak
}
var ptr *T
for {
@ -64,7 +64,8 @@ func Make[T comparable](value T) Handle[T] {
wp, ok := m.Load(value)
if !ok {
// Try to insert a new value into the map.
wp, _ = m.LoadOrStore(value, newValue())
k, v := newValue()
wp, _ = m.LoadOrStore(k, v)
}
// Now that we're sure there's a value in the map, let's
// try to get the pointer we need out of it.

View File

@ -9,7 +9,10 @@ import (
"internal/abi"
"reflect"
"runtime"
"strings"
"testing"
"time"
"unsafe"
)
// Set up special types. Because the internal maps are sharded by type,
@ -41,6 +44,7 @@ func TestHandle(t *testing.T) {
s: [2]testStringStruct{testStringStruct{"y"}, testStringStruct{"z"}},
})
testHandle[testStruct](t, testStruct{0.5, "184"})
testHandle[testEface](t, testEface("hello"))
}
func testHandle[T comparable](t *testing.T, value T) {
@ -93,7 +97,7 @@ func drainMaps(t *testing.T) {
func checkMapsFor[T comparable](t *testing.T, value T) {
// Manually load the value out of the map.
typ := abi.TypeOf(value)
typ := abi.TypeFor[T]()
a, ok := uniqueMaps.Load(typ)
if !ok {
return
@ -109,3 +113,22 @@ func checkMapsFor[T comparable](t *testing.T, value T) {
}
t.Errorf("failed to drain internal maps of %v", value)
}
func TestMakeClonesStrings(t *testing.T) {
s := strings.Clone("abcdefghijklmnopqrstuvwxyz") // N.B. Must be big enough to not be tiny-allocated.
ran := make(chan bool)
runtime.SetFinalizer(unsafe.StringData(s), func(_ *byte) {
ran <- true
})
h := Make(s)
// Clean up s (hopefully) and run the finalizer.
runtime.GC()
select {
case <-time.After(1 * time.Second):
t.Fatal("string was improperly retained")
case <-ran:
}
runtime.KeepAlive(h)
}

View File

@ -1,16 +1,20 @@
// errorcheck -lang=go1.21
// errorcheck -lang=go1.22
// 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.
//go:build go1.4
// This file has been changed from its original version as
// //go:build file versions below 1.21 set the language version to 1.21.
// The original tested a -lang version of 1.21 with a file version of
// go1.4 while this new version tests a -lang version of go1.22
// with a file version of go1.21.
//go:build go1.21
package p
const c = 0o123 // ERROR "file declares //go:build go1.4"
// ERROR "file declares //go:build go1.4"
//line issue63489a.go:13:1
const d = 0o124
func f() {
for _ = range 10 { // ERROR "file declares //go:build go1.21"
}
}

View File

@ -1,11 +1,20 @@
// errorcheck -lang=go1.4
// errorcheck -lang=go1.21
// 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.
//go:build go1.4
// This file has been changed from its original version as
// //go:build file versions below 1.21 set the language version to 1.21.
// The original tested a -lang version of 1.4 with a file version of
// go1.4 while this new version tests a -lang version of go1.1
// with a file version of go1.21.
//go:build go1.21
package p
const c = 0o123 // ERROR "file declares //go:build go1.4"
func f() {
for _ = range 10 { // ERROR "file declares //go:build go1.21"
}
}

View File

@ -0,0 +1,15 @@
// compile -goexperiment aliastypeparams
// 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
type A[P any] = struct{ _ P }
type N[P any] A[P]
func f[P any](N[P]) {}
var _ = f[int]

View File

@ -0,0 +1,57 @@
// 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 (
"maps"
_ "unsafe"
)
func main() {
for i := 0; i < 100; i++ {
f()
}
}
const NB = 4
func f() {
// Make a map with NB buckets, at max capacity.
// 6.5 entries/bucket.
ne := NB * 13 / 2
m := map[int]int{}
for i := 0; i < ne; i++ {
m[i] = i
}
// delete/insert a lot, to hopefully get lots of overflow buckets
// and trigger a same-size grow.
ssg := false
for i := ne; i < ne+1000; i++ {
delete(m, i-ne)
m[i] = i
if sameSizeGrow(m) {
ssg = true
break
}
}
if !ssg {
return
}
// Insert 1 more entry, which would ordinarily trigger a growth.
// We can't grow while growing, so we instead go over our
// target capacity.
m[-1] = -1
// Cloning in this state will make a map with a destination bucket
// array twice the size of the source.
_ = maps.Clone(m)
}
//go:linkname sameSizeGrow runtime.sameSizeGrowForIssue69110Test
func sameSizeGrow(m map[int]int) bool

View File

@ -0,0 +1,173 @@
// 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 (
"bufio"
"fmt"
"io"
"iter"
"math/rand"
"os"
"strings"
"unicode"
)
// WordReader is the struct that implements io.Reader
type WordReader struct {
scanner *bufio.Scanner
}
// NewWordReader creates a new WordReader from an io.Reader
func NewWordReader(r io.Reader) *WordReader {
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanWords)
return &WordReader{
scanner: scanner,
}
}
// Read reads data from the input stream and returns a single lowercase word at a time
func (wr *WordReader) Read(p []byte) (n int, err error) {
if !wr.scanner.Scan() {
if err := wr.scanner.Err(); err != nil {
return 0, err
}
return 0, io.EOF
}
word := wr.scanner.Text()
cleanedWord := removeNonAlphabetic(word)
if len(cleanedWord) == 0 {
return wr.Read(p)
}
n = copy(p, []byte(cleanedWord))
return n, nil
}
// All returns an iterator allowing the caller to iterate over the WordReader using for/range.
func (wr *WordReader) All() iter.Seq[string] {
word := make([]byte, 1024)
return func(yield func(string) bool) {
var err error
var n int
for n, err = wr.Read(word); err == nil; n, err = wr.Read(word) {
if !yield(string(word[:n])) {
return
}
}
if err != io.EOF {
fmt.Fprintf(os.Stderr, "error reading word: %v\n", err)
}
}
}
// removeNonAlphabetic removes non-alphabetic characters from a word using strings.Map
func removeNonAlphabetic(word string) string {
return strings.Map(func(r rune) rune {
if unicode.IsLetter(r) {
return unicode.ToLower(r)
}
return -1
}, word)
}
// ProbabilisticSkipper determines if an item should be retained with probability 1/(1<<n)
type ProbabilisticSkipper struct {
n int
counter uint64
bitmask uint64
}
// NewProbabilisticSkipper initializes the ProbabilisticSkipper
func NewProbabilisticSkipper(n int) *ProbabilisticSkipper {
pr := &ProbabilisticSkipper{n: n}
pr.refreshCounter()
return pr
}
// check panics if pr.n is not the expected value
func (pr *ProbabilisticSkipper) check(n int) {
if pr.n != n {
panic(fmt.Sprintf("check: pr.n != n %d != %d", pr.n, n))
}
}
// refreshCounter refreshes the counter with a new random value
func (pr *ProbabilisticSkipper) refreshCounter() {
if pr.n == 0 {
pr.bitmask = ^uint64(0) // All bits set to 1
} else {
pr.bitmask = rand.Uint64()
for i := 0; i < pr.n-1; i++ {
pr.bitmask &= rand.Uint64()
}
}
pr.counter = 64
}
// ShouldSkip returns true with probability 1/(1<<n)
func (pr *ProbabilisticSkipper) ShouldSkip() bool {
remove := pr.bitmask&1 == 0
pr.bitmask >>= 1
pr.counter--
if pr.counter == 0 {
pr.refreshCounter()
}
return remove
}
// EstimateUniqueWordsIter estimates the number of unique words using a probabilistic counting method
func EstimateUniqueWordsIter(reader io.Reader, memorySize int) int {
wordReader := NewWordReader(reader)
words := make(map[string]struct{}, memorySize)
rounds := 0
roundRemover := NewProbabilisticSkipper(1)
wordSkipper := NewProbabilisticSkipper(rounds)
wordSkipper.check(rounds)
for word := range wordReader.All() {
wordSkipper.check(rounds)
if wordSkipper.ShouldSkip() {
delete(words, word)
} else {
words[word] = struct{}{}
if len(words) >= memorySize {
rounds++
wordSkipper = NewProbabilisticSkipper(rounds)
for w := range words {
if roundRemover.ShouldSkip() {
delete(words, w)
}
}
}
}
wordSkipper.check(rounds)
}
if len(words) == 0 {
return 0
}
invProbability := 1 << rounds
estimatedUniqueWords := len(words) * invProbability
return estimatedUniqueWords
}
func main() {
input := "Hello, world! This is a test. Hello, world, hello!"
expectedUniqueWords := 6 // "hello", "world", "this", "is", "a", "test" (but "hello" and "world" are repeated)
memorySize := 6
reader := strings.NewReader(input)
estimatedUniqueWords := EstimateUniqueWordsIter(reader, memorySize)
if estimatedUniqueWords != expectedUniqueWords {
// ...
}
}

View File

@ -0,0 +1,133 @@
// 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() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
methods := "AB"
type node struct {
tag string
choices []string
}
all := []node{
{"000", permutations(methods)},
}
next := 1
for len(all) > 0 {
cur := all[0]
k := copy(all, all[1:])
all = all[:k]
if len(cur.choices) == 1 {
continue
}
var bestM map[byte][]string
bMax := len(cur.choices) + 1
bMin := -1
for sel := range selections(methods) {
m := make(map[byte][]string)
for _, order := range cur.choices {
x := findFirstMatch(order, sel)
m[x] = append(m[x], order)
}
min := len(cur.choices) + 1
max := -1
for _, v := range m {
if len(v) < min {
min = len(v)
}
if len(v) > max {
max = len(v)
}
}
if max < bMax || (max == bMax && min > bMin) {
bestM = m
bMin = min
bMax = max
}
}
if bMax == len(cur.choices) {
continue
}
cc := Keys(bestM)
for c := range cc {
choices := bestM[c]
next++
switch c {
case 'A':
case 'B':
default:
panic("unexpected selector type " + string(c))
}
all = append(all, node{"", choices})
}
}
return nil
}
func permutations(s string) []string {
if len(s) <= 1 {
return []string{s}
}
var result []string
for i, char := range s {
rest := s[:i] + s[i+1:]
for _, perm := range permutations(rest) {
result = append(result, string(char)+perm)
}
}
return result
}
type Seq[V any] func(yield func(V) bool)
func selections(s string) Seq[string] {
return func(yield func(string) bool) {
for bits := 1; bits < 1<<len(s); bits++ {
var choice string
for j, char := range s {
if bits&(1<<j) != 0 {
choice += string(char)
}
}
if !yield(choice) {
break
}
}
}
}
func findFirstMatch(order, sel string) byte {
for _, c := range order {
return byte(c)
}
return 0
}
func Keys[Map ~map[K]V, K comparable, V any](m Map) Seq[K] {
return func(yield func(K) bool) {
for k := range m {
if !yield(k) {
return
}
}
}
}