From: Michael Anthony Knyszek Date: Wed, 12 Nov 2025 18:22:58 +0000 (+0000) Subject: cmd/go: keep objects alive while stopping cleanups X-Git-Tag: go1.26rc1~308 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0929d21978;p=gostls13.git cmd/go: keep objects alive while stopping cleanups There are two places in cmd/go where cleanups are stopped before they fire, and where the objects the cleanups are attached to may be dead while we call Stop. This is essentially a race between Stop and the cleanup being called. This can be fine, but these cleanups are used as a way to check some invariants, so just panic if they're executed. As a result, if they fire erroneously, they'll take down the whole process, even if no invariant was actually violated. The runtime.Cleanup.Stop documentation explains that users of Stop need to hold the object alive across the call to Stop if they want to be sure that Stop succeeds, so do that here by adding an explicit runtime.KeepAlive call. Kudos to Michael Pratt for finding the issue. Fixes #74780. Change-Id: I22e6f4642ac68f727ca3781f5d39a85015047925 Reviewed-on: https://go-review.googlesource.com/c/go/+/719961 Auto-Submit: Michael Knyszek Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee --- diff --git a/src/cmd/go/internal/base/limit.go b/src/cmd/go/internal/base/limit.go index 4317432527..a90b700a03 100644 --- a/src/cmd/go/internal/base/limit.go +++ b/src/cmd/go/internal/base/limit.go @@ -63,6 +63,12 @@ func AcquireNet() (release func(), err error) { <-netLimitSem } cleanup.Stop() + + // checker may be dead at the moment after we last access + // it in this function, so the cleanup can fire before Stop + // completes. Keep checker alive while we call Stop. See + // the documentation for runtime.Cleanup.Stop. + runtime.KeepAlive(checker) }, nil } diff --git a/src/cmd/go/internal/lockedfile/lockedfile.go b/src/cmd/go/internal/lockedfile/lockedfile.go index 8bd2ffbe8f..f48124ffbc 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile.go +++ b/src/cmd/go/internal/lockedfile/lockedfile.go @@ -94,6 +94,11 @@ func (f *File) Close() error { err := closeFile(f.osFile.File) f.cleanup.Stop() + // f may be dead at the moment after we access f.cleanup, + // so the cleanup can fire before Stop completes. Keep f + // alive while we call Stop. See the documentation for + // runtime.Cleanup.Stop. + runtime.KeepAlive(f) return err }