From b32283b27b3b776c2d470471de056d687e1ba2b8 Mon Sep 17 00:00:00 2001 From: Weixie Cui Date: Sat, 25 Apr 2026 11:43:02 +0000 Subject: [PATCH 1/4] cmd/go: fix length is not equal cause bytes.Equal never return true Change-Id: I62d4e2277ba01480985b6df0c1e222964e89bf4d GitHub-Last-Rev: c0867661c447dcf9ad5f00ff09defcd0239adb82 GitHub-Pull-Request: golang/go#78950 Reviewed-on: https://go-review.googlesource.com/c/go/+/770640 Reviewed-by: Sean Liao LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Cherry Mui Reviewed-by: Michael Pratt Auto-Submit: Sean Liao --- src/cmd/go/internal/modfetch/cache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 4d7e2b1bfc88b3..2e6e7a5048034b 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -781,7 +781,7 @@ func rewriteVersionList(ctx context.Context, dir string) (err error) { } if fi, err := f.Stat(); err == nil && int(fi.Size()) == buf.Len() { old := make([]byte, buf.Len()+1) - if n, err := f.ReadAt(old, 0); err == io.EOF && n == buf.Len() && bytes.Equal(buf.Bytes(), old) { + if n, err := f.ReadAt(old, 0); err == io.EOF && n == buf.Len() && bytes.Equal(buf.Bytes(), old[:n]) { return nil // No edit needed. } } From 66843181d10b769d9fd572d553110c864df38fb0 Mon Sep 17 00:00:00 2001 From: Weixie Cui Date: Tue, 21 Apr 2026 12:57:41 +0000 Subject: [PATCH 2/4] cmd/go: fix potention deadlock Change-Id: I5cc0c9d69c56c6746e03c7ae2f6c0e49c8dbc7e4 GitHub-Last-Rev: b12cee8f9722cd29b52fdfc1f0435da45d713260 GitHub-Pull-Request: golang/go#78885 Reviewed-on: https://go-review.googlesource.com/c/go/+/769320 Reviewed-by: Michael Pratt Reviewed-by: Sean Liao Reviewed-by: Cherry Mui Auto-Submit: Sean Liao LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/go/internal/cache/prog.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/go/internal/cache/prog.go b/src/cmd/go/internal/cache/prog.go index 0f51021298bbc7..cbd495642cb9c5 100644 --- a/src/cmd/go/internal/cache/prog.go +++ b/src/cmd/go/internal/cache/prog.go @@ -204,6 +204,7 @@ func (c *ProgCache) send(ctx context.Context, req *cacheprog.Request) (*cachepro func (c *ProgCache) writeToChild(req *cacheprog.Request, resc chan<- *cacheprog.Response) (err error) { c.mu.Lock() if c.inFlight == nil { + c.mu.Unlock() return errCacheprogClosed } c.nextID++ From 3b7d571c99221dd65108ce4b5737912812f17056 Mon Sep 17 00:00:00 2001 From: Neal Patel Date: Mon, 4 May 2026 11:27:26 -0400 Subject: [PATCH 3/4] html/template: use zero-alloc bytes.EqualFold Change-Id: I2357b88ded7ac9f08848a67115dce6539c3c6428 Reviewed-on: https://go-review.googlesource.com/c/go/+/773820 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Nicholas Husin Reviewed-by: Nicholas Husin --- src/html/template/transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/html/template/transition.go b/src/html/template/transition.go index ea4b272cc241db..05b6abd03d1772 100644 --- a/src/html/template/transition.go +++ b/src/html/template/transition.go @@ -426,7 +426,7 @@ func tJSDelimited(c context, s []byte) (context, int) { // If " 0 && i+7 <= len(s) && bytes.Equal(bytes.ToLower(s[i-1:i+7]), []byte(" 0 && i+7 <= len(s) && bytes.EqualFold(s[i-1:i+7], []byte(" Date: Tue, 5 May 2026 21:32:07 -0400 Subject: [PATCH 4/4] internal/goexperiment,runtime: drop goroutineleakprofile experiment This is on by default now, and there's really no reason to turn it off (the "off" behavior is just that the new profile type doesn't get registered). Updates #74609. Change-Id: Ide8a3f3247c0ea72b14f66e0fdd78bca7080973f Reviewed-on: https://go-review.googlesource.com/c/go/+/774621 Reviewed-by: Georgian-Vlad Saioc Reviewed-by: Cherry Mui Auto-Submit: Austin Clements LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- .../exp_goroutineleakprofile_off.go | 8 ------ .../exp_goroutineleakprofile_on.go | 8 ------ src/net/http/pprof/pprof.go | 28 ++++++++----------- src/runtime/crash_test.go | 15 ---------- src/runtime/goroutineleakprofile_test.go | 1 - src/runtime/pprof/pprof.go | 17 +++++------ 6 files changed, 18 insertions(+), 59 deletions(-) delete mode 100644 src/internal/goexperiment/exp_goroutineleakprofile_off.go delete mode 100644 src/internal/goexperiment/exp_goroutineleakprofile_on.go diff --git a/src/internal/goexperiment/exp_goroutineleakprofile_off.go b/src/internal/goexperiment/exp_goroutineleakprofile_off.go deleted file mode 100644 index 63eafe9e6c74db..00000000000000 --- a/src/internal/goexperiment/exp_goroutineleakprofile_off.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.goroutineleakprofile - -package goexperiment - -const GoroutineLeakProfile = false -const GoroutineLeakProfileInt = 0 diff --git a/src/internal/goexperiment/exp_goroutineleakprofile_on.go b/src/internal/goexperiment/exp_goroutineleakprofile_on.go deleted file mode 100644 index 28a662eceb46f8..00000000000000 --- a/src/internal/goexperiment/exp_goroutineleakprofile_on.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.goroutineleakprofile - -package goexperiment - -const GoroutineLeakProfile = true -const GoroutineLeakProfileInt = 1 diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go index 71aade67d32046..5c45c537bcc90a 100644 --- a/src/net/http/pprof/pprof.go +++ b/src/net/http/pprof/pprof.go @@ -77,7 +77,6 @@ import ( "fmt" "html" "internal/godebug" - "internal/goexperiment" "internal/profile" "io" "log" @@ -362,22 +361,17 @@ var profileSupportsDelta = map[handler]bool{ } var profileDescriptions = map[string]string{ - "allocs": "A sampling of all past memory allocations", - "block": "Stack traces that led to blocking on synchronization primitives", - "cmdline": "The command line invocation of the current program", - "goroutine": "Stack traces of all current goroutines. Use debug=2 as a query parameter to export in the same format as an unrecovered panic.", - "heap": "A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.", - "mutex": "Stack traces of holders of contended mutexes", - "profile": "CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.", - "symbol": "Maps given program counters to function names. Counters can be specified in a GET raw query or POST body, multiple counters are separated by '+'.", - "threadcreate": "Stack traces that led to the creation of new OS threads", - "trace": "A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.", -} - -func init() { - if goexperiment.GoroutineLeakProfile { - profileDescriptions["goroutineleak"] = "Stack traces of all leaked goroutines. Use debug=2 as a query parameter to export in the same format as an unrecovered panic." - } + "allocs": "A sampling of all past memory allocations", + "block": "Stack traces that led to blocking on synchronization primitives", + "cmdline": "The command line invocation of the current program", + "goroutine": "Stack traces of all current goroutines. Use debug=2 as a query parameter to export in the same format as an unrecovered panic.", + "heap": "A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.", + "mutex": "Stack traces of holders of contended mutexes", + "profile": "CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.", + "symbol": "Maps given program counters to function names. Counters can be specified in a GET raw query or POST body, multiple counters are separated by '+'.", + "threadcreate": "Stack traces that led to the creation of new OS threads", + "trace": "A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.", + "goroutineleak": "Stack traces of all leaked goroutines. Use debug=2 as a query parameter to export in the same format as an unrecovered panic.", } type profileEntry struct { diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index 77afdc069005d4..723f25085840df 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -194,21 +194,6 @@ func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) cmd.Dir = "testdata/" + binary cmd = testenv.CleanCmdEnv(cmd) - // If tests need any experimental flags, add them here. - // - // TODO(vsaioc): Remove `goroutineleakprofile` once the feature is no longer experimental. - edited := false - for i := range cmd.Env { - e := cmd.Env[i] - if _, vars, ok := strings.Cut(e, "GOEXPERIMENT="); ok { - cmd.Env[i] = "GOEXPERIMENT=" + vars + ",goroutineleakprofile" - edited, _ = true, vars - } - } - if !edited { - cmd.Env = append(cmd.Env, "GOEXPERIMENT=goroutineleakprofile") - } - out, err := cmd.CombinedOutput() if err != nil { target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out) diff --git a/src/runtime/goroutineleakprofile_test.go b/src/runtime/goroutineleakprofile_test.go index 473edc92ec6b0e..d802b834ecb902 100644 --- a/src/runtime/goroutineleakprofile_test.go +++ b/src/runtime/goroutineleakprofile_test.go @@ -509,7 +509,6 @@ func TestGoroutineLeakProfile(t *testing.T) { cmdEnv := []string{ "GODEBUG=asyncpreemptoff=1", - "GOEXPERIMENT=goroutineleakprofile", } if tcase.simple { diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go index 2dc0ac18074684..1c116ad21dcd7b 100644 --- a/src/runtime/pprof/pprof.go +++ b/src/runtime/pprof/pprof.go @@ -80,7 +80,6 @@ import ( "cmp" "fmt" "internal/abi" - "internal/goexperiment" "internal/profilerecord" "io" "runtime" @@ -257,15 +256,13 @@ func lockProfiles() { if profiles.m == nil { // Initial built-in profiles. profiles.m = map[string]*Profile{ - "goroutine": goroutineProfile, - "threadcreate": threadcreateProfile, - "heap": heapProfile, - "allocs": allocsProfile, - "block": blockProfile, - "mutex": mutexProfile, - } - if goexperiment.GoroutineLeakProfile { - profiles.m["goroutineleak"] = goroutineLeakProfile + "goroutine": goroutineProfile, + "threadcreate": threadcreateProfile, + "heap": heapProfile, + "allocs": allocsProfile, + "block": blockProfile, + "mutex": mutexProfile, + "goroutineleak": goroutineLeakProfile, } } }