diff -Nru golang-1.24-1.24.2/debian/changelog golang-1.24-1.24.4/debian/changelog --- golang-1.24-1.24.2/debian/changelog 2025-04-17 20:15:41.000000000 +0530 +++ golang-1.24-1.24.4/debian/changelog 2025-06-16 17:04:18.000000000 +0530 @@ -1,3 +1,15 @@ +golang-1.24 (1.24.4-1) unstable; urgency=medium + + * Team upload + * New upstream version 1.24.1 + + CVE-2025-4673: net/http: sensitive headers not cleared on cross-origin redirect (Closes: #1107364) + + CVE-2025-0913: os: inconsistent handling of O_CREATE|O_EXCL on Unix and Windows + + CVE 2025-22874: crypto/x509: usage of ExtKeyUsageAny disables policy validation (Closes: #1107364) + + CVE-2025-22873: os: Root permits access to parent directory (Closes: #1104816) + * d/patches: Removed patch 0003 as it's already applied upstream now + + -- Anshul Singh Mon, 16 Jun 2025 17:04:18 +0530 + golang-1.24 (1.24.2-2) unstable; urgency=medium * Team upload diff -Nru golang-1.24-1.24.2/debian/patches/0003-runtime-cleanup-M-vgetrandom-state-before-dropping-P.patch golang-1.24-1.24.4/debian/patches/0003-runtime-cleanup-M-vgetrandom-state-before-dropping-P.patch --- golang-1.24-1.24.2/debian/patches/0003-runtime-cleanup-M-vgetrandom-state-before-dropping-P.patch 2025-04-17 20:15:41.000000000 +0530 +++ golang-1.24-1.24.4/debian/patches/0003-runtime-cleanup-M-vgetrandom-state-before-dropping-P.patch 1970-01-01 05:30:00.000000000 +0530 @@ -1,246 +0,0 @@ -From: Michael Pratt -Date: Thu, 3 Apr 2025 03:26:25 +0000 -Subject: runtime: cleanup M vgetrandom state before dropping P - -When an M is destroyed, we put its vgetrandom state back on the shared -list for another M to reuse. This list is simply a slice, so appending -to the slice may allocate. Currently this operation is performed in -mdestroy, after the P is released, meaning allocation is not allowed. - -More the cleanup earlier in mdestroy when allocation is still OK. - -Also add //go:nowritebarrierrec to mdestroy since it runs without a P, -which would have caught this bug. - -Fixes #73144. -For #73141. - -Change-Id: I6a6a636c3fbf5c6eec09d07a260e39dbb4d2db12 -Reviewed-on: https://go-review.googlesource.com/c/go/+/662455 -Reviewed-by: Jason Donenfeld -LUCI-TryBot-Result: Go LUCI -Reviewed-by: Keith Randall -Reviewed-by: Keith Randall -(cherry picked from commit 0b31e6d4cc804ab76ae8ced151ee2f50657aec14) ---- - src/runtime/os3_solaris.go | 5 ++++- - src/runtime/os_aix.go | 5 ++++- - src/runtime/os_darwin.go | 5 ++++- - src/runtime/os_dragonfly.go | 5 ++++- - src/runtime/os_linux.go | 9 ++++----- - src/runtime/os_netbsd.go | 5 ++++- - src/runtime/os_openbsd.go | 5 ++++- - src/runtime/os_plan9.go | 5 ++++- - src/runtime/os_windows.go | 4 +++- - src/runtime/proc.go | 3 +++ - src/runtime/vgetrandom_linux.go | 11 +++++++++-- - src/runtime/vgetrandom_unsupported.go | 2 +- - 12 files changed, 48 insertions(+), 16 deletions(-) - -diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go -index cf163a6..ded821b 100644 ---- a/src/runtime/os3_solaris.go -+++ b/src/runtime/os3_solaris.go -@@ -234,8 +234,11 @@ func unminit() { - getg().m.procid = 0 - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -+// -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - func mdestroy(mp *m) { - } - -diff --git a/src/runtime/os_aix.go b/src/runtime/os_aix.go -index 93464cb..1b483c2 100644 ---- a/src/runtime/os_aix.go -+++ b/src/runtime/os_aix.go -@@ -186,8 +186,11 @@ func unminit() { - getg().m.procid = 0 - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -+// -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - func mdestroy(mp *m) { - } - -diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go -index 0ecbea7..6eab3b5 100644 ---- a/src/runtime/os_darwin.go -+++ b/src/runtime/os_darwin.go -@@ -344,8 +344,11 @@ func unminit() { - getg().m.procid = 0 - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -+// -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - func mdestroy(mp *m) { - } - -diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go -index a02696e..9b32350 100644 ---- a/src/runtime/os_dragonfly.go -+++ b/src/runtime/os_dragonfly.go -@@ -216,8 +216,11 @@ func unminit() { - getg().m.procid = 0 - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -+// -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - func mdestroy(mp *m) { - } - -diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go -index 8b3c4d0..fb46b81 100644 ---- a/src/runtime/os_linux.go -+++ b/src/runtime/os_linux.go -@@ -412,13 +412,12 @@ func unminit() { - getg().m.procid = 0 - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -+// -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - func mdestroy(mp *m) { -- if mp.vgetrandomState != 0 { -- vgetrandomPutState(mp.vgetrandomState) -- mp.vgetrandomState = 0 -- } - } - - // #ifdef GOARCH_386 -diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go -index 735ace2..a06e5fe 100644 ---- a/src/runtime/os_netbsd.go -+++ b/src/runtime/os_netbsd.go -@@ -320,8 +320,11 @@ func unminit() { - // must continue working after unminit. - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -+// -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - func mdestroy(mp *m) { - } - -diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go -index 574bfa8..4ce4c3c 100644 ---- a/src/runtime/os_openbsd.go -+++ b/src/runtime/os_openbsd.go -@@ -182,8 +182,11 @@ func unminit() { - getg().m.procid = 0 - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -+// -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - func mdestroy(mp *m) { - } - -diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go -index 2dbb42a..3b5965a 100644 ---- a/src/runtime/os_plan9.go -+++ b/src/runtime/os_plan9.go -@@ -217,8 +217,11 @@ func minit() { - func unminit() { - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -+// -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - func mdestroy(mp *m) { - } - -diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go -index 7183e79..54407a3 100644 ---- a/src/runtime/os_windows.go -+++ b/src/runtime/os_windows.go -@@ -906,9 +906,11 @@ func unminit() { - mp.procid = 0 - } - --// Called from exitm, but not from drop, to undo the effect of thread-owned -+// Called from mexit, but not from dropm, to undo the effect of thread-owned - // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. - // -+// This always runs without a P, so //go:nowritebarrierrec is required. -+//go:nowritebarrierrec - //go:nosplit - func mdestroy(mp *m) { - if mp.highResTimer != 0 { -diff --git a/src/runtime/proc.go b/src/runtime/proc.go -index e9873e5..21bee4d 100644 ---- a/src/runtime/proc.go -+++ b/src/runtime/proc.go -@@ -1935,6 +1935,9 @@ func mexit(osStack bool) { - mp.gsignal = nil - } - -+ // Free vgetrandom state. -+ vgetrandomDestroy(mp) -+ - // Remove m from allm. - lock(&sched.lock) - for pprev := &allm; *pprev != nil; pprev = &(*pprev).alllink { -diff --git a/src/runtime/vgetrandom_linux.go b/src/runtime/vgetrandom_linux.go -index a6ec4b7..40be022 100644 ---- a/src/runtime/vgetrandom_linux.go -+++ b/src/runtime/vgetrandom_linux.go -@@ -73,9 +73,16 @@ func vgetrandomGetState() uintptr { - return state - } - --func vgetrandomPutState(state uintptr) { -+// Free vgetrandom state from the M (if any) prior to destroying the M. -+// -+// This may allocate, so it must have a P. -+func vgetrandomDestroy(mp *m) { -+ if mp.vgetrandomState == 0 { -+ return -+ } -+ - lock(&vgetrandomAlloc.statesLock) -- vgetrandomAlloc.states = append(vgetrandomAlloc.states, state) -+ vgetrandomAlloc.states = append(vgetrandomAlloc.states, mp.vgetrandomState) - unlock(&vgetrandomAlloc.statesLock) - } - -diff --git a/src/runtime/vgetrandom_unsupported.go b/src/runtime/vgetrandom_unsupported.go -index 070392c..43c53e1 100644 ---- a/src/runtime/vgetrandom_unsupported.go -+++ b/src/runtime/vgetrandom_unsupported.go -@@ -13,6 +13,6 @@ func vgetrandom(p []byte, flags uint32) (ret int, supported bool) { - return -1, false - } - --func vgetrandomPutState(state uintptr) {} -+func vgetrandomDestroy(mp *m) {} - - func vgetrandomInit() {} diff -Nru golang-1.24-1.24.2/debian/patches/series golang-1.24-1.24.4/debian/patches/series --- golang-1.24-1.24.2/debian/patches/series 2025-04-17 20:15:41.000000000 +0530 +++ golang-1.24-1.24.4/debian/patches/series 2025-06-16 17:04:18.000000000 +0530 @@ -1,3 +1,2 @@ 0001-Skip-flaky-TestCrashDumpsAllThreads-on-mips64le.patch 0002-Skip-flaky-TestCrashDumpsAllThreads-on-s390x.patch -0003-runtime-cleanup-M-vgetrandom-state-before-dropping-P.patch diff -Nru golang-1.24-1.24.2/lib/fips140/inprocess.txt golang-1.24-1.24.4/lib/fips140/inprocess.txt --- golang-1.24-1.24.2/lib/fips140/inprocess.txt 1970-01-01 05:30:00.000000000 +0530 +++ golang-1.24-1.24.4/lib/fips140/inprocess.txt 2025-05-30 01:07:36.000000000 +0530 @@ -0,0 +1 @@ +v1.0.0 diff -Nru golang-1.24-1.24.2/src/cmd/cgo/internal/test/issue42018_windows.go golang-1.24-1.24.4/src/cmd/cgo/internal/test/issue42018_windows.go --- golang-1.24-1.24.2/src/cmd/cgo/internal/test/issue42018_windows.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/cgo/internal/test/issue42018_windows.go 2025-05-30 01:07:36.000000000 +0530 @@ -27,6 +27,7 @@ recurseHWND(400, hwnd, uintptr(unsafe.Pointer(&i))) } +//go:noinline func recurseHANDLE(n int, p C.HANDLE, v uintptr) { if n > 0 { recurseHANDLE(n-1, p, v) @@ -36,6 +37,7 @@ } } +//go:noinline func recurseHWND(n int, p C.HWND, v uintptr) { if n > 0 { recurseHWND(n-1, p, v) diff -Nru golang-1.24-1.24.2/src/cmd/compile/internal/inline/inl.go golang-1.24-1.24.4/src/cmd/compile/internal/inline/inl.go --- golang-1.24-1.24.2/src/cmd/compile/internal/inline/inl.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/compile/internal/inline/inl.go 2025-05-30 01:07:36.000000000 +0530 @@ -170,19 +170,8 @@ } ir.VisitFuncsBottomUp(funcs, func(funcs []*ir.Func, recursive bool) { - numfns := numNonClosures(funcs) - for _, fn := range funcs { - if !recursive || numfns > 1 { - // We allow inlining if there is no - // recursion, or the recursion cycle is - // across more than one function. - CanInline(fn, profile) - } else { - if base.Flag.LowerM > 1 && fn.OClosure == nil { - fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(fn), fn.Nname) - } - } + CanInline(fn, profile) if inlheur.Enabled() { analyzeFuncProps(fn, profile) } @@ -1021,68 +1010,6 @@ } return false, 0, false } - } - - if callee == callerfn { - // Can't recursively inline a function into itself. - if log && logopt.Enabled() { - logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(callerfn))) - } - return false, 0, false - } - - isClosureParent := func(closure, parent *ir.Func) bool { - for p := closure.ClosureParent; p != nil; p = p.ClosureParent { - if p == parent { - return true - } - } - return false - } - if isClosureParent(callerfn, callee) { - // Can't recursively inline a parent of the closure into itself. - if log && logopt.Enabled() { - logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to closure parent: %s, %s", ir.FuncName(callerfn), ir.FuncName(callee))) - } - return false, 0, false - } - if isClosureParent(callee, callerfn) { - // Can't recursively inline a closure if there's a call to the parent in closure body. - if ir.Any(callee, func(node ir.Node) bool { - if call, ok := node.(*ir.CallExpr); ok { - if name, ok := call.Fun.(*ir.Name); ok && isClosureParent(callerfn, name.Func) { - return true - } - } - return false - }) { - if log && logopt.Enabled() { - logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to closure parent: %s, %s", ir.FuncName(callerfn), ir.FuncName(callee))) - } - return false, 0, false - } - } - do := func(fn *ir.Func) bool { - // Can't recursively inline a function if the function body contains - // a call to a function f, which the function f is one of the call arguments. - return ir.Any(fn, func(node ir.Node) bool { - if call, ok := node.(*ir.CallExpr); ok { - for _, arg := range call.Args { - if call.Fun == arg { - return true - } - } - } - return false - }) - } - for _, fn := range []*ir.Func{callerfn, callee} { - if do(fn) { - if log && logopt.Enabled() { - logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to function: %s", ir.FuncName(fn))) - } - return false, 0, false - } } if base.Flag.Cfg.Instrumenting && types.IsNoInstrumentPkg(callee.Sym().Pkg) { diff -Nru golang-1.24-1.24.2/src/cmd/go/internal/load/pkg.go golang-1.24-1.24.4/src/cmd/go/internal/load/pkg.go --- golang-1.24-1.24.2/src/cmd/go/internal/load/pkg.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/go/internal/load/pkg.go 2025-05-30 01:07:36.000000000 +0530 @@ -2571,7 +2571,12 @@ vers := revInfo.Version if vers != "" { if st.Uncommitted { - vers += "+dirty" + // SemVer build metadata is dot-separated https://semver.org/#spec-item-10 + if strings.HasSuffix(vers, "+incompatible") { + vers += ".dirty" + } else { + vers += "+dirty" + } } info.Main.Version = vers } diff -Nru golang-1.24-1.24.2/src/cmd/go/testdata/script/build_version_stamping_git.txt golang-1.24-1.24.4/src/cmd/go/testdata/script/build_version_stamping_git.txt --- golang-1.24-1.24.2/src/cmd/go/testdata/script/build_version_stamping_git.txt 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/go/testdata/script/build_version_stamping_git.txt 2025-05-30 01:07:36.000000000 +0530 @@ -108,6 +108,19 @@ stdout '\s+mod\s+example\s+v1.0.3-0.20220719150703-2e239bf29c13\s+' rm example$GOEXE +# Create +incompatible module +exec git checkout v1.0.4 +exec git rm go.mod +exec git commit -m 'commit 6' +exec git tag v2.0.0 +exec git checkout HEAD^ go.mod +# And make the tree +dirty +mv README4 README5 +go build +go version -m example$GOEXE +stdout '\s+mod\s+example\s+v2.0.0\+incompatible.dirty\s+' +rm example$GOEXE + -- $WORK/repo/go.mod -- module example diff -Nru golang-1.24-1.24.2/src/cmd/internal/obj/wasm/wasmobj.go golang-1.24-1.24.4/src/cmd/internal/obj/wasm/wasmobj.go --- golang-1.24-1.24.2/src/cmd/internal/obj/wasm/wasmobj.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/internal/obj/wasm/wasmobj.go 2025-05-30 01:07:36.000000000 +0530 @@ -1006,9 +1006,10 @@ // In the unwinding case, we call wasm_pc_f_loop_export to handle stack switch and rewinding, // until a normal return (non-unwinding) back to this function. p = appendp(p, AIf) - p = appendp(p, AI32Const, retAddr) - p = appendp(p, AI32Const, constAddr(16)) - p = appendp(p, AI32ShrU) + p = appendp(p, AI64Const, retAddr) + p = appendp(p, AI64Const, constAddr(16)) + p = appendp(p, AI64ShrU) + p = appendp(p, AI32WrapI64) p = appendp(p, ACall, obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: wasm_pc_f_loop_export}) p = appendp(p, AEnd) diff -Nru golang-1.24-1.24.2/src/cmd/link/internal/loader/loader.go golang-1.24-1.24.4/src/cmd/link/internal/loader/loader.go --- golang-1.24-1.24.2/src/cmd/link/internal/loader/loader.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/link/internal/loader/loader.go 2025-05-30 01:07:36.000000000 +0530 @@ -432,16 +432,16 @@ return i } // symbol already exists + // Fix for issue #47185 -- given two dupok or BSS symbols with + // different sizes, favor symbol with larger size. See also + // issue #46653 and #72032. + oldsz := l.SymSize(oldi) + sz := int64(r.Sym(li).Siz()) if osym.Dupok() { if l.flags&FlagStrictDups != 0 { l.checkdup(name, r, li, oldi) } - // Fix for issue #47185 -- given two dupok symbols with - // different sizes, favor symbol with larger size. See - // also issue #46653. - szdup := l.SymSize(oldi) - sz := int64(r.Sym(li).Siz()) - if szdup < sz { + if oldsz < sz { // new symbol overwrites old symbol. l.objSyms[oldi] = objSym{r.objidx, li} } @@ -452,20 +452,50 @@ if oldsym.Dupok() { return oldi } - overwrite := r.DataSize(li) != 0 - if overwrite { + // If one is a DATA symbol (i.e. has content, DataSize != 0, + // including RODATA) and the other is BSS, the one with content wins. + // If both are BSS, the one with larger size wins. + // + // For a special case, we allow a TEXT symbol overwrites a BSS symbol + // even if the BSS symbol has larger size. This is because there is + // code like below to take the address of a function + // + // //go:linkname fn + // var fn uintptr + // var fnAddr = uintptr(unsafe.Pointer(&fn)) + // + // TODO: maybe limit this case to just pointer sized variable? + // + // In summary, the "overwrite" variable and the final result are + // + // new sym old sym result + // --------------------------------------------- + // TEXT BSS new wins + // DATA DATA ERROR + // DATA lg/eq BSS sm/eq new wins + // DATA small BSS large ERROR + // BSS large DATA small ERROR + // BSS large BSS small new wins + // BSS sm/eq D/B lg/eq old wins + // BSS TEXT old wins + oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())] + newtyp := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())] + oldIsText := oldtyp.IsText() + newIsText := newtyp.IsText() + oldHasContent := oldr.DataSize(oldli) != 0 + newHasContent := r.DataSize(li) != 0 + oldIsBSS := oldtyp.IsData() && !oldHasContent + newIsBSS := newtyp.IsData() && !newHasContent + switch { + case newIsText && oldIsBSS, + newHasContent && oldIsBSS && sz >= oldsz, + newIsBSS && oldIsBSS && sz > oldsz: // new symbol overwrites old symbol. - oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())] - if !(oldtyp.IsData() && oldr.DataSize(oldli) == 0) { - log.Fatalf("duplicated definition of symbol %s, from %s and %s", name, r.unit.Lib.Pkg, oldr.unit.Lib.Pkg) - } l.objSyms[oldi] = objSym{r.objidx, li} - } else { - // old symbol overwrites new symbol. - typ := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())] - if !typ.IsData() { // only allow overwriting data symbol - log.Fatalf("duplicated definition of symbol %s, from %s and %s", name, r.unit.Lib.Pkg, oldr.unit.Lib.Pkg) - } + case newIsBSS && (oldsz >= sz || oldIsText): + // old win, just ignore the new symbol. + default: + log.Fatalf("duplicated definition of symbol %s, from %s (type %s size %d) and %s (type %s size %d)", name, r.unit.Lib.Pkg, newtyp, sz, oldr.unit.Lib.Pkg, oldtyp, oldsz) } return oldi } diff -Nru golang-1.24-1.24.2/src/cmd/link/link_test.go golang-1.24-1.24.4/src/cmd/link/link_test.go --- golang-1.24-1.24.2/src/cmd/link/link_test.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/link/link_test.go 2025-05-30 01:07:36.000000000 +0530 @@ -20,6 +20,7 @@ "testing" imacho "cmd/internal/macho" + "cmd/internal/objfile" "cmd/internal/sys" ) @@ -1511,6 +1512,9 @@ {"ok.go", true}, // push linkname is ok {"push.go", true}, + // using a linknamed variable to reference an assembly + // function in the same package is ok + {"textvar", true}, // pull linkname of blocked symbol is not ok {"coro.go", false}, {"coro_var.go", false}, @@ -1528,7 +1532,7 @@ test := test t.Run(test.src, func(t *testing.T) { t.Parallel() - src := filepath.Join("testdata", "linkname", test.src) + src := "./testdata/linkname/" + test.src exe := filepath.Join(tmpdir, test.src+".exe") cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src) out, err := cmd.CombinedOutput() @@ -1541,3 +1545,53 @@ }) } } + +func TestLinknameBSS(t *testing.T) { + // Test that the linker chooses the right one as the definition + // for linknamed variables. See issue #72032. + testenv.MustHaveGoBuild(t) + t.Parallel() + + tmpdir := t.TempDir() + + src := filepath.Join("testdata", "linkname", "sched.go") + exe := filepath.Join(tmpdir, "sched.exe") + cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("build failed unexpectedly: %v:\n%s", err, out) + } + + // Check the symbol size. + f, err := objfile.Open(exe) + if err != nil { + t.Fatalf("fail to open executable: %v", err) + } + defer f.Close() + syms, err := f.Symbols() + if err != nil { + t.Fatalf("fail to get symbols: %v", err) + } + found := false + for _, s := range syms { + if s.Name == "runtime.sched" || s.Name == "_runtime.sched" { + found = true + if s.Size < 100 { + // As of Go 1.25 (Mar 2025), runtime.sched has 6848 bytes on + // darwin/arm64. It should always be larger than 100 bytes on + // all platforms. + t.Errorf("runtime.sched symbol size too small: want > 100, got %d", s.Size) + } + } + } + if !found { + t.Errorf("runtime.sched symbol not found") + } + + // Executable should run. + cmd = testenv.Command(t, exe) + out, err = cmd.CombinedOutput() + if err != nil { + t.Errorf("executable failed to run: %v\n%s", err, out) + } +} diff -Nru golang-1.24-1.24.2/src/cmd/link/testdata/linkname/sched.go golang-1.24-1.24.4/src/cmd/link/testdata/linkname/sched.go --- golang-1.24-1.24.2/src/cmd/link/testdata/linkname/sched.go 1970-01-01 05:30:00.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/link/testdata/linkname/sched.go 2025-05-30 01:07:36.000000000 +0530 @@ -0,0 +1,19 @@ +// Copyright 2025 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 _ "unsafe" + +type schedt struct{} + +//go:linkname sched runtime.sched +var sched schedt + +func main() { + select { + default: + println("hello") + } +} diff -Nru golang-1.24-1.24.2/src/cmd/link/testdata/linkname/textvar/asm.s golang-1.24-1.24.4/src/cmd/link/testdata/linkname/textvar/asm.s --- golang-1.24-1.24.2/src/cmd/link/testdata/linkname/textvar/asm.s 1970-01-01 05:30:00.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/link/testdata/linkname/textvar/asm.s 2025-05-30 01:07:36.000000000 +0530 @@ -0,0 +1,6 @@ +// 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. + +TEXT ·asmfunc(SB),0,$0-0 + RET diff -Nru golang-1.24-1.24.2/src/cmd/link/testdata/linkname/textvar/main.go golang-1.24-1.24.4/src/cmd/link/testdata/linkname/textvar/main.go --- golang-1.24-1.24.2/src/cmd/link/testdata/linkname/textvar/main.go 1970-01-01 05:30:00.000000000 +0530 +++ golang-1.24-1.24.4/src/cmd/link/testdata/linkname/textvar/main.go 2025-05-30 01:07:36.000000000 +0530 @@ -0,0 +1,17 @@ +// 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. + +// Using a linknamed variable to reference an assembly +// function in the same package is ok. + +package main + +import _ "unsafe" + +func main() { + println(&asmfunc) +} + +//go:linkname asmfunc +var asmfunc uintptr diff -Nru golang-1.24-1.24.2/src/crypto/tls/ech.go golang-1.24-1.24.4/src/crypto/tls/ech.go --- golang-1.24-1.24.2/src/crypto/tls/ech.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/crypto/tls/ech.go 2025-05-30 01:07:36.000000000 +0530 @@ -381,8 +381,28 @@ return nil, errInvalidECHExt } - if len(inner.supportedVersions) != 1 || (len(inner.supportedVersions) >= 1 && inner.supportedVersions[0] != VersionTLS13) { - return nil, errors.New("tls: client sent encrypted_client_hello extension and offered incompatible versions") + hasTLS13 := false + for _, v := range inner.supportedVersions { + // Skip GREASE values (values of the form 0x?A0A). + // GREASE (Generate Random Extensions And Sustain Extensibility) is a mechanism used by + // browsers like Chrome to ensure TLS implementations correctly ignore unknown values. + // GREASE values follow a specific pattern: 0x?A0A, where ? can be any hex digit. + // These values should be ignored when processing supported TLS versions. + if v&0x0F0F == 0x0A0A && v&0xff == v>>8 { + continue + } + + // Ensure at least TLS 1.3 is offered. + if v == VersionTLS13 { + hasTLS13 = true + } else if v < VersionTLS13 { + // Reject if any non-GREASE value is below TLS 1.3, as ECH requires TLS 1.3+. + return nil, errors.New("tls: client sent encrypted_client_hello extension with unsupported versions") + } + } + + if !hasTLS13 { + return nil, errors.New("tls: client sent encrypted_client_hello extension but did not offer TLS 1.3") } return inner, nil diff -Nru golang-1.24-1.24.2/src/crypto/x509/verify.go golang-1.24-1.24.4/src/crypto/x509/verify.go --- golang-1.24-1.24.2/src/crypto/x509/verify.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/crypto/x509/verify.go 2025-05-30 01:07:36.000000000 +0530 @@ -841,31 +841,45 @@ } } - if len(opts.KeyUsages) == 0 { - opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} + chains = make([][]*Certificate, 0, len(candidateChains)) + + var invalidPoliciesChains int + for _, candidate := range candidateChains { + if !policiesValid(candidate, opts) { + invalidPoliciesChains++ + continue + } + chains = append(chains, candidate) + } + + if len(chains) == 0 { + return nil, CertificateInvalidError{c, NoValidChains, "all candidate chains have invalid policies"} } for _, eku := range opts.KeyUsages { if eku == ExtKeyUsageAny { // If any key usage is acceptable, no need to check the chain for // key usages. - return candidateChains, nil + return chains, nil } } - chains = make([][]*Certificate, 0, len(candidateChains)) - var incompatibleKeyUsageChains, invalidPoliciesChains int + if len(opts.KeyUsages) == 0 { + opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} + } + + candidateChains = chains + chains = chains[:0] + + var incompatibleKeyUsageChains int for _, candidate := range candidateChains { if !checkChainForKeyUsage(candidate, opts.KeyUsages) { incompatibleKeyUsageChains++ continue } - if !policiesValid(candidate, opts) { - invalidPoliciesChains++ - continue - } chains = append(chains, candidate) } + if len(chains) == 0 { var details []string if incompatibleKeyUsageChains > 0 { diff -Nru golang-1.24-1.24.2/src/crypto/x509/verify_test.go golang-1.24-1.24.4/src/crypto/x509/verify_test.go --- golang-1.24-1.24.2/src/crypto/x509/verify_test.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/crypto/x509/verify_test.go 2025-05-30 01:07:36.000000000 +0530 @@ -3012,3 +3012,39 @@ }) } } + +func TestInvalidPolicyWithAnyKeyUsage(t *testing.T) { + loadTestCert := func(t *testing.T, path string) *Certificate { + b, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + p, _ := pem.Decode(b) + c, err := ParseCertificate(p.Bytes) + if err != nil { + t.Fatal(err) + } + return c + } + + testOID3 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 3}) + root, intermediate, leaf := loadTestCert(t, "testdata/policy_root.pem"), loadTestCert(t, "testdata/policy_intermediate_require.pem"), loadTestCert(t, "testdata/policy_leaf.pem") + + expectedErr := "x509: no valid chains built: all candidate chains have invalid policies" + + roots, intermediates := NewCertPool(), NewCertPool() + roots.AddCert(root) + intermediates.AddCert(intermediate) + + _, err := leaf.Verify(VerifyOptions{ + Roots: roots, + Intermediates: intermediates, + KeyUsages: []ExtKeyUsage{ExtKeyUsageAny}, + CertificatePolicies: []OID{testOID3}, + }) + if err == nil { + t.Fatal("unexpected success, invalid policy shouldn't be bypassed by passing VerifyOptions.KeyUsages with ExtKeyUsageAny") + } else if err.Error() != expectedErr { + t.Fatalf("unexpected error, got %q, want %q", err, expectedErr) + } +} diff -Nru golang-1.24-1.24.2/src/hash/maphash/maphash_purego.go golang-1.24-1.24.4/src/hash/maphash/maphash_purego.go --- golang-1.24-1.24.2/src/hash/maphash/maphash_purego.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/hash/maphash/maphash_purego.go 2025-05-30 01:07:36.000000000 +0530 @@ -161,7 +161,7 @@ case reflect.Bool: h.WriteByte(btoi(v.Bool())) return - case reflect.UnsafePointer, reflect.Pointer: + case reflect.UnsafePointer, reflect.Pointer, reflect.Chan: var buf [8]byte // because pointing to the abi.Escape call in comparableReady, // So this is ok to hash pointer, diff -Nru golang-1.24-1.24.2/src/hash/maphash/maphash_test.go golang-1.24-1.24.4/src/hash/maphash/maphash_test.go --- golang-1.24-1.24.2/src/hash/maphash/maphash_test.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/hash/maphash/maphash_test.go 2025-05-30 01:07:36.000000000 +0530 @@ -253,12 +253,17 @@ } testComparable(t, s1, s2) testComparable(t, s1.s, s2.s) + c1 := make(chan struct{}) + c2 := make(chan struct{}) + testComparable(t, c1, c1) + testComparable(t, chan struct{}(nil)) testComparable(t, float32(0), negativeZero[float32]()) testComparable(t, float64(0), negativeZero[float64]()) testComparableNoEqual(t, math.NaN(), math.NaN()) testComparableNoEqual(t, [2]string{"a", ""}, [2]string{"", "a"}) testComparableNoEqual(t, struct{ a, b string }{"foo", ""}, struct{ a, b string }{"", "foo"}) testComparableNoEqual(t, struct{ a, b any }{int(0), struct{}{}}, struct{ a, b any }{struct{}{}, int(0)}) + testComparableNoEqual(t, c1, c2) } func testComparableNoEqual[T comparable](t *testing.T, v1, v2 T) { diff -Nru golang-1.24-1.24.2/src/internal/runtime/maps/runtime_fast32_swiss.go golang-1.24-1.24.4/src/internal/runtime/maps/runtime_fast32_swiss.go --- golang-1.24-1.24.2/src/internal/runtime/maps/runtime_fast32_swiss.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/internal/runtime/maps/runtime_fast32_swiss.go 2025-05-30 01:07:36.000000000 +0530 @@ -17,7 +17,7 @@ func runtime_mapaccess1_fast32(typ *abi.SwissMapType, m *Map, key uint32) unsafe.Pointer { if race.Enabled && m != nil { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapaccess1) + pc := abi.FuncPCABIInternal(runtime_mapaccess1_fast32) race.ReadPC(unsafe.Pointer(m), callerpc, pc) } @@ -86,7 +86,7 @@ func runtime_mapaccess2_fast32(typ *abi.SwissMapType, m *Map, key uint32) (unsafe.Pointer, bool) { if race.Enabled && m != nil { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapaccess1) + pc := abi.FuncPCABIInternal(runtime_mapaccess2_fast32) race.ReadPC(unsafe.Pointer(m), callerpc, pc) } @@ -198,7 +198,7 @@ } if race.Enabled { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapassign) + pc := abi.FuncPCABIInternal(runtime_mapassign_fast32) race.WritePC(unsafe.Pointer(m), callerpc, pc) } if m.writing != 0 { @@ -332,7 +332,7 @@ } if race.Enabled { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapassign) + pc := abi.FuncPCABIInternal(runtime_mapassign_fast32ptr) race.WritePC(unsafe.Pointer(m), callerpc, pc) } if m.writing != 0 { @@ -458,7 +458,7 @@ func runtime_mapdelete_fast32(typ *abi.SwissMapType, m *Map, key uint32) { if race.Enabled { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapassign) + pc := abi.FuncPCABIInternal(runtime_mapdelete_fast32) race.WritePC(unsafe.Pointer(m), callerpc, pc) } diff -Nru golang-1.24-1.24.2/src/internal/runtime/maps/runtime_fast64_swiss.go golang-1.24-1.24.4/src/internal/runtime/maps/runtime_fast64_swiss.go --- golang-1.24-1.24.2/src/internal/runtime/maps/runtime_fast64_swiss.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/internal/runtime/maps/runtime_fast64_swiss.go 2025-05-30 01:07:36.000000000 +0530 @@ -17,7 +17,7 @@ func runtime_mapaccess1_fast64(typ *abi.SwissMapType, m *Map, key uint64) unsafe.Pointer { if race.Enabled && m != nil { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapaccess1) + pc := abi.FuncPCABIInternal(runtime_mapaccess1_fast64) race.ReadPC(unsafe.Pointer(m), callerpc, pc) } @@ -86,7 +86,7 @@ func runtime_mapaccess2_fast64(typ *abi.SwissMapType, m *Map, key uint64) (unsafe.Pointer, bool) { if race.Enabled && m != nil { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapaccess1) + pc := abi.FuncPCABIInternal(runtime_mapaccess2_fast64) race.ReadPC(unsafe.Pointer(m), callerpc, pc) } @@ -198,7 +198,7 @@ } if race.Enabled { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapassign) + pc := abi.FuncPCABIInternal(runtime_mapassign_fast64) race.WritePC(unsafe.Pointer(m), callerpc, pc) } if m.writing != 0 { @@ -370,7 +370,7 @@ } if race.Enabled { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapassign) + pc := abi.FuncPCABIInternal(runtime_mapassign_fast64ptr) race.WritePC(unsafe.Pointer(m), callerpc, pc) } if m.writing != 0 { @@ -497,7 +497,7 @@ func runtime_mapdelete_fast64(typ *abi.SwissMapType, m *Map, key uint64) { if race.Enabled { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapassign) + pc := abi.FuncPCABIInternal(runtime_mapdelete_fast64) race.WritePC(unsafe.Pointer(m), callerpc, pc) } diff -Nru golang-1.24-1.24.2/src/internal/runtime/maps/runtime_faststr_swiss.go golang-1.24-1.24.4/src/internal/runtime/maps/runtime_faststr_swiss.go --- golang-1.24-1.24.2/src/internal/runtime/maps/runtime_faststr_swiss.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/internal/runtime/maps/runtime_faststr_swiss.go 2025-05-30 01:07:36.000000000 +0530 @@ -103,7 +103,7 @@ func runtime_mapaccess1_faststr(typ *abi.SwissMapType, m *Map, key string) unsafe.Pointer { if race.Enabled && m != nil { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapaccess1) + pc := abi.FuncPCABIInternal(runtime_mapaccess1_faststr) race.ReadPC(unsafe.Pointer(m), callerpc, pc) } @@ -162,7 +162,7 @@ func runtime_mapaccess2_faststr(typ *abi.SwissMapType, m *Map, key string) (unsafe.Pointer, bool) { if race.Enabled && m != nil { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapaccess1) + pc := abi.FuncPCABIInternal(runtime_mapaccess2_faststr) race.ReadPC(unsafe.Pointer(m), callerpc, pc) } @@ -266,7 +266,7 @@ } if race.Enabled { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapassign) + pc := abi.FuncPCABIInternal(runtime_mapassign_faststr) race.WritePC(unsafe.Pointer(m), callerpc, pc) } if m.writing != 0 { @@ -396,7 +396,7 @@ func runtime_mapdelete_faststr(typ *abi.SwissMapType, m *Map, key string) { if race.Enabled { callerpc := sys.GetCallerPC() - pc := abi.FuncPCABIInternal(runtime_mapassign) + pc := abi.FuncPCABIInternal(runtime_mapdelete_faststr) race.WritePC(unsafe.Pointer(m), callerpc, pc) } diff -Nru golang-1.24-1.24.2/src/internal/syscall/unix/at_openbsd.go golang-1.24-1.24.4/src/internal/syscall/unix/at_openbsd.go --- golang-1.24-1.24.2/src/internal/syscall/unix/at_openbsd.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/internal/syscall/unix/at_openbsd.go 2025-05-30 01:07:36.000000000 +0530 @@ -43,7 +43,7 @@ if err != nil { return err } - _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(p)), 0, 0, 0, 0) + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(p)), uintptr(mode), 0, 0, 0) if errno != 0 { return errno } diff -Nru golang-1.24-1.24.2/src/internal/syscall/windows/at_windows.go golang-1.24-1.24.4/src/internal/syscall/windows/at_windows.go --- golang-1.24-1.24.2/src/internal/syscall/windows/at_windows.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/internal/syscall/windows/at_windows.go 2025-05-30 01:07:36.000000000 +0530 @@ -88,6 +88,7 @@ switch { case flag&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL): disposition = FILE_CREATE + options |= FILE_OPEN_REPARSE_POINT // don't follow symlinks case flag&syscall.O_CREAT == syscall.O_CREAT: disposition = FILE_OPEN_IF default: diff -Nru golang-1.24-1.24.2/src/net/http/client.go golang-1.24-1.24.4/src/net/http/client.go --- golang-1.24-1.24.2/src/net/http/client.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/net/http/client.go 2025-05-30 01:07:36.000000000 +0530 @@ -805,7 +805,8 @@ for k, vv := range ireqhdr { sensitive := false switch CanonicalHeaderKey(k) { - case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": + case "Authorization", "Www-Authenticate", "Cookie", "Cookie2", + "Proxy-Authorization", "Proxy-Authenticate": sensitive = true } if !(sensitive && stripSensitiveHeaders) { diff -Nru golang-1.24-1.24.2/src/net/http/client_test.go golang-1.24-1.24.4/src/net/http/client_test.go --- golang-1.24-1.24.2/src/net/http/client_test.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/net/http/client_test.go 2025-05-30 01:07:36.000000000 +0530 @@ -1547,6 +1547,8 @@ if r.Host+r.URL.Path != "a.example.com/" { if h := r.Header.Get("Authorization"); h != "" { t.Errorf("on request to %v%v, Authorization=%q, want no header", r.Host, r.URL.Path, h) + } else if h := r.Header.Get("Proxy-Authorization"); h != "" { + t.Errorf("on request to %v%v, Proxy-Authorization=%q, want no header", r.Host, r.URL.Path, h) } } // Follow a chain of redirects from a to b and back to a. @@ -1575,6 +1577,7 @@ req, _ := NewRequest("GET", proto+"://a.example.com/", nil) req.Header.Add("Cookie", "foo=bar") req.Header.Add("Authorization", "secretpassword") + req.Header.Add("Proxy-Authorization", "secretpassword") res, err := c.Do(req) if err != nil { t.Fatal(err) diff -Nru golang-1.24-1.24.2/src/os/os_test.go golang-1.24-1.24.4/src/os/os_test.go --- golang-1.24-1.24.2/src/os/os_test.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/os/os_test.go 2025-05-30 01:07:36.000000000 +0530 @@ -2223,6 +2223,31 @@ } +func TestOpenFileCreateExclDanglingSymlink(t *testing.T) { + testMaybeRooted(t, func(t *testing.T, r *Root) { + const link = "link" + if err := Symlink("does_not_exist", link); err != nil { + t.Fatal(err) + } + var f *File + var err error + if r == nil { + f, err = OpenFile(link, O_WRONLY|O_CREATE|O_EXCL, 0o444) + } else { + f, err = r.OpenFile(link, O_WRONLY|O_CREATE|O_EXCL, 0o444) + } + if err == nil { + f.Close() + } + if !errors.Is(err, ErrExist) { + t.Errorf("OpenFile of a dangling symlink with O_CREATE|O_EXCL = %v, want ErrExist", err) + } + if _, err := Stat(link); err == nil { + t.Errorf("OpenFile of a dangling symlink with O_CREATE|O_EXCL created a file") + } + }) +} + // TestFileRDWRFlags tests the O_RDONLY, O_WRONLY, and O_RDWR flags. func TestFileRDWRFlags(t *testing.T) { for _, test := range []struct { diff -Nru golang-1.24-1.24.2/src/os/root.go golang-1.24-1.24.4/src/os/root.go --- golang-1.24-1.24.2/src/os/root.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/os/root.go 2025-05-30 01:07:36.000000000 +0530 @@ -186,20 +186,20 @@ // // "." components are removed, except in the last component. // -// Path separators following the last component are preserved. -func splitPathInRoot(s string, prefix, suffix []string) (_ []string, err error) { +// Path separators following the last component are returned in suffixSep. +func splitPathInRoot(s string, prefix, suffix []string) (_ []string, suffixSep string, err error) { if len(s) == 0 { - return nil, errors.New("empty path") + return nil, "", errors.New("empty path") } if IsPathSeparator(s[0]) { - return nil, errPathEscapes + return nil, "", errPathEscapes } if runtime.GOOS == "windows" { // Windows cleans paths before opening them. s, err = rootCleanPath(s, prefix, suffix) if err != nil { - return nil, err + return nil, "", err } prefix = nil suffix = nil @@ -215,13 +215,14 @@ } parts = append(parts, s[i:j]) // Advance to the next component, or end of the path. + partEnd := j for j < len(s) && IsPathSeparator(s[j]) { j++ } if j == len(s) { // If this is the last path component, // preserve any trailing path separators. - parts[len(parts)-1] = s[i:] + suffixSep = s[partEnd:] break } if parts[len(parts)-1] == "." { @@ -235,7 +236,7 @@ parts = parts[:len(parts)-1] } parts = append(parts, suffix...) - return parts, nil + return parts, suffixSep, nil } // FS returns a file system (an fs.FS) for the tree of files in the root. diff -Nru golang-1.24-1.24.2/src/os/root_js.go golang-1.24-1.24.4/src/os/root_js.go --- golang-1.24-1.24.2/src/os/root_js.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/os/root_js.go 2025-05-30 01:07:36.000000000 +0530 @@ -33,7 +33,7 @@ if r.root.closed.Load() { return ErrClosed } - parts, err := splitPathInRoot(name, nil, nil) + parts, suffixSep, err := splitPathInRoot(name, nil, nil) if err != nil { return err } @@ -61,11 +61,15 @@ continue } - if lstat && i == len(parts)-1 { - break + part := parts[i] + if i == len(parts)-1 { + if lstat { + break + } + part += suffixSep } - next := joinPath(base, parts[i]) + next := joinPath(base, part) fi, err := Lstat(next) if err != nil { if IsNotExist(err) { @@ -82,10 +86,19 @@ if symlinks > rootMaxSymlinks { return errors.New("too many symlinks") } - newparts, err := splitPathInRoot(link, parts[:i], parts[i+1:]) + newparts, newSuffixSep, err := splitPathInRoot(link, parts[:i], parts[i+1:]) if err != nil { return err } + if i == len(parts) { + // suffixSep contains any trailing path separator characters + // in the link target. + // If we are replacing the remainder of the path, retain these. + // If we're replacing some intermediate component of the path, + // ignore them, since intermediate components must always be + // directories. + suffixSep = newSuffixSep + } parts = newparts continue } diff -Nru golang-1.24-1.24.2/src/os/root_openat.go golang-1.24-1.24.4/src/os/root_openat.go --- golang-1.24-1.24.2/src/os/root_openat.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/os/root_openat.go 2025-05-30 01:07:36.000000000 +0530 @@ -98,7 +98,7 @@ } defer r.root.decref() - parts, err := splitPathInRoot(name, nil, nil) + parts, suffixSep, err := splitPathInRoot(name, nil, nil) if err != nil { return ret, err } @@ -146,6 +146,9 @@ return ret, errPathEscapes } parts = slices.Delete(parts, i-count, end) + if len(parts) == 0 { + parts = []string{"."} + } i = 0 if dirfd != rootfd { syscall.Close(dirfd) @@ -159,7 +162,9 @@ // Call f to decide what to do with it. // If f returns errSymlink, this element is a symlink // which should be followed. - ret, err = f(dirfd, parts[i]) + // suffixSep contains any trailing separator characters + // which we rejoin to the final part at this time. + ret, err = f(dirfd, parts[i]+suffixSep) if _, ok := err.(errSymlink); !ok { return ret, err } @@ -181,10 +186,19 @@ if symlinks > rootMaxSymlinks { return ret, syscall.ELOOP } - newparts, err := splitPathInRoot(string(e), parts[:i], parts[i+1:]) + newparts, newSuffixSep, err := splitPathInRoot(string(e), parts[:i], parts[i+1:]) if err != nil { return ret, err } + if i == len(parts)-1 { + // suffixSep contains any trailing path separator characters + // in the link target. + // If we are replacing the remainder of the path, retain these. + // If we're replacing some intermediate component of the path, + // ignore them, since intermediate components must always be + // directories. + suffixSep = newSuffixSep + } if len(newparts) < i || !slices.Equal(parts[:i], newparts[:i]) { // Some component in the path which we have already traversed // has changed. We need to restart parsing from the root. diff -Nru golang-1.24-1.24.2/src/os/root_test.go golang-1.24-1.24.4/src/os/root_test.go --- golang-1.24-1.24.2/src/os/root_test.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/os/root_test.go 2025-05-30 01:07:36.000000000 +0530 @@ -187,6 +187,30 @@ target: "target", ltarget: "link", }, { + name: "symlink dotdot slash", + fs: []string{ + "link => ../", + }, + open: "link", + ltarget: "link", + wantError: true, +}, { + name: "symlink ending in slash", + fs: []string{ + "dir/", + "link => dir/", + }, + open: "link/target", + target: "dir/target", +}, { + name: "symlink dotdot dotdot slash", + fs: []string{ + "dir/link => ../../", + }, + open: "dir/link", + ltarget: "dir/link", + wantError: true, +}, { name: "symlink chain", fs: []string{ "link => a/b/c/target", @@ -214,6 +238,16 @@ open: "a/../a/b/../../a/b/../b/target", target: "a/b/target", }, { + name: "path with dotdot slash", + fs: []string{}, + open: "../", + wantError: true, +}, { + name: "path with dotdot dotdot slash", + fs: []string{}, + open: "a/../../", + wantError: true, +}, { name: "dotdot no symlink", fs: []string{ "a/", @@ -413,6 +447,12 @@ if !fi.IsDir() { t.Fatalf(`stat file created with Root.Mkdir(%q): not a directory`, test.open) } + if mode := fi.Mode(); mode&0o777 == 0 { + // Issue #73559: We're not going to worry about the exact + // mode bits (which will have been modified by umask), + // but there should be mode bits. + t.Fatalf(`stat file created with Root.Mkdir(%q): mode=%v, want non-zero`, test.open, mode) + } }) } } @@ -1176,6 +1216,33 @@ } } +func TestRootSymlinkToRoot(t *testing.T) { + dir := makefs(t, []string{ + "d/d => ..", + }) + root, err := os.OpenRoot(dir) + if err != nil { + t.Fatal(err) + } + defer root.Close() + if err := root.Mkdir("d/d/new", 0777); err != nil { + t.Fatal(err) + } + f, err := root.Open("d/d") + if err != nil { + t.Fatal(err) + } + defer f.Close() + names, err := f.Readdirnames(-1) + if err != nil { + t.Fatal(err) + } + slices.Sort(names) + if got, want := names, []string{"d", "new"}; !slices.Equal(got, want) { + t.Errorf("root contains: %q, want %q", got, want) + } +} + func TestOpenInRoot(t *testing.T) { dir := makefs(t, []string{ "file", diff -Nru golang-1.24-1.24.2/src/runtime/debug/mod.go golang-1.24-1.24.4/src/runtime/debug/mod.go --- golang-1.24-1.24.2/src/runtime/debug/mod.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/debug/mod.go 2025-05-30 01:07:36.000000000 +0530 @@ -77,6 +77,7 @@ // - CGO_CPPFLAGS: the effective CGO_CPPFLAGS environment variable // - CGO_CXXFLAGS: the effective CGO_CXXFLAGS environment variable // - CGO_LDFLAGS: the effective CGO_LDFLAGS environment variable +// - DefaultGODEBUG: the effective GODEBUG settings // - GOARCH: the architecture target // - GOAMD64/GOARM/GO386/etc: the architecture feature level for GOARCH // - GOOS: the operating system target diff -Nru golang-1.24-1.24.2/src/runtime/os3_solaris.go golang-1.24-1.24.4/src/runtime/os3_solaris.go --- golang-1.24-1.24.2/src/runtime/os3_solaris.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os3_solaris.go 2025-05-30 01:07:36.000000000 +0530 @@ -234,8 +234,11 @@ getg().m.procid = 0 } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec func mdestroy(mp *m) { } diff -Nru golang-1.24-1.24.2/src/runtime/os_aix.go golang-1.24-1.24.4/src/runtime/os_aix.go --- golang-1.24-1.24.2/src/runtime/os_aix.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os_aix.go 2025-05-30 01:07:36.000000000 +0530 @@ -186,8 +186,11 @@ getg().m.procid = 0 } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec func mdestroy(mp *m) { } diff -Nru golang-1.24-1.24.2/src/runtime/os_darwin.go golang-1.24-1.24.4/src/runtime/os_darwin.go --- golang-1.24-1.24.2/src/runtime/os_darwin.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os_darwin.go 2025-05-30 01:07:36.000000000 +0530 @@ -344,8 +344,11 @@ getg().m.procid = 0 } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec func mdestroy(mp *m) { } diff -Nru golang-1.24-1.24.2/src/runtime/os_dragonfly.go golang-1.24-1.24.4/src/runtime/os_dragonfly.go --- golang-1.24-1.24.2/src/runtime/os_dragonfly.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os_dragonfly.go 2025-05-30 01:07:36.000000000 +0530 @@ -216,8 +216,11 @@ getg().m.procid = 0 } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec func mdestroy(mp *m) { } diff -Nru golang-1.24-1.24.2/src/runtime/os_linux.go golang-1.24-1.24.4/src/runtime/os_linux.go --- golang-1.24-1.24.2/src/runtime/os_linux.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os_linux.go 2025-05-30 01:07:36.000000000 +0530 @@ -412,13 +412,12 @@ getg().m.procid = 0 } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec func mdestroy(mp *m) { - if mp.vgetrandomState != 0 { - vgetrandomPutState(mp.vgetrandomState) - mp.vgetrandomState = 0 - } } // #ifdef GOARCH_386 diff -Nru golang-1.24-1.24.2/src/runtime/os_netbsd.go golang-1.24-1.24.4/src/runtime/os_netbsd.go --- golang-1.24-1.24.2/src/runtime/os_netbsd.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os_netbsd.go 2025-05-30 01:07:36.000000000 +0530 @@ -320,8 +320,11 @@ // must continue working after unminit. } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec func mdestroy(mp *m) { } diff -Nru golang-1.24-1.24.2/src/runtime/os_openbsd.go golang-1.24-1.24.4/src/runtime/os_openbsd.go --- golang-1.24-1.24.2/src/runtime/os_openbsd.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os_openbsd.go 2025-05-30 01:07:36.000000000 +0530 @@ -182,8 +182,11 @@ getg().m.procid = 0 } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec func mdestroy(mp *m) { } diff -Nru golang-1.24-1.24.2/src/runtime/os_plan9.go golang-1.24-1.24.4/src/runtime/os_plan9.go --- golang-1.24-1.24.2/src/runtime/os_plan9.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os_plan9.go 2025-05-30 01:07:36.000000000 +0530 @@ -217,8 +217,11 @@ func unminit() { } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +// +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec func mdestroy(mp *m) { } diff -Nru golang-1.24-1.24.2/src/runtime/os_windows.go golang-1.24-1.24.4/src/runtime/os_windows.go --- golang-1.24-1.24.2/src/runtime/os_windows.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/os_windows.go 2025-05-30 01:07:36.000000000 +0530 @@ -906,9 +906,11 @@ mp.procid = 0 } -// Called from exitm, but not from drop, to undo the effect of thread-owned +// Called from mexit, but not from dropm, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. // +// This always runs without a P, so //go:nowritebarrierrec is required. +//go:nowritebarrierrec //go:nosplit func mdestroy(mp *m) { if mp.highResTimer != 0 { diff -Nru golang-1.24-1.24.2/src/runtime/pprof/proto_test.go golang-1.24-1.24.4/src/runtime/pprof/proto_test.go --- golang-1.24-1.24.2/src/runtime/pprof/proto_test.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/pprof/proto_test.go 2025-05-30 01:07:36.000000000 +0530 @@ -73,7 +73,10 @@ checkProfile(t, p, 2000*1000, periodType, sampleType, nil, "") } +//go:noinline func f1() { f1() } + +//go:noinline func f2() { f2() } // testPCs returns two PCs and two corresponding memory mappings diff -Nru golang-1.24-1.24.2/src/runtime/proc.go golang-1.24-1.24.4/src/runtime/proc.go --- golang-1.24-1.24.2/src/runtime/proc.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/proc.go 2025-05-30 01:07:36.000000000 +0530 @@ -1935,6 +1935,9 @@ mp.gsignal = nil } + // Free vgetrandom state. + vgetrandomDestroy(mp) + // Remove m from allm. lock(&sched.lock) for pprev := &allm; *pprev != nil; pprev = &(*pprev).alllink { diff -Nru golang-1.24-1.24.2/src/runtime/sys_darwin_amd64.s golang-1.24-1.24.4/src/runtime/sys_darwin_amd64.s --- golang-1.24-1.24.2/src/runtime/sys_darwin_amd64.s 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/sys_darwin_amd64.s 2025-05-30 01:07:36.000000000 +0530 @@ -745,7 +745,7 @@ // // syscall9 expects a 32-bit result and tests for 32-bit -1 // to decide there was an error. -TEXT runtime·syscall9(SB),NOSPLIT,$16 +TEXT runtime·syscall9(SB),NOSPLIT,$32 MOVQ (0*8)(DI), R13// fn MOVQ (2*8)(DI), SI // a2 MOVQ (3*8)(DI), DX // a3 @@ -753,15 +753,18 @@ MOVQ (5*8)(DI), R8 // a5 MOVQ (6*8)(DI), R9 // a6 MOVQ (7*8)(DI), R10 // a7 + MOVQ R10, 0(SP) MOVQ (8*8)(DI), R11 // a8 + MOVQ R11, 8(SP) MOVQ (9*8)(DI), R12 // a9 - MOVQ DI, (SP) + MOVQ R12, 16(SP) + MOVQ DI, 24(SP) MOVQ (1*8)(DI), DI // a1 XORL AX, AX // vararg: say "no float args" CALL R13 - MOVQ (SP), DI + MOVQ 24(SP), DI MOVQ AX, (10*8)(DI) // r1 MOVQ DX, (11*8)(DI) // r2 @@ -770,7 +773,7 @@ CALL libc_error(SB) MOVLQSX (AX), AX - MOVQ (SP), DI + MOVQ 24(SP), DI MOVQ AX, (12*8)(DI) // err ok: diff -Nru golang-1.24-1.24.2/src/runtime/vgetrandom_linux.go golang-1.24-1.24.4/src/runtime/vgetrandom_linux.go --- golang-1.24-1.24.2/src/runtime/vgetrandom_linux.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/vgetrandom_linux.go 2025-05-30 01:07:36.000000000 +0530 @@ -73,9 +73,16 @@ return state } -func vgetrandomPutState(state uintptr) { +// Free vgetrandom state from the M (if any) prior to destroying the M. +// +// This may allocate, so it must have a P. +func vgetrandomDestroy(mp *m) { + if mp.vgetrandomState == 0 { + return + } + lock(&vgetrandomAlloc.statesLock) - vgetrandomAlloc.states = append(vgetrandomAlloc.states, state) + vgetrandomAlloc.states = append(vgetrandomAlloc.states, mp.vgetrandomState) unlock(&vgetrandomAlloc.statesLock) } diff -Nru golang-1.24-1.24.2/src/runtime/vgetrandom_unsupported.go golang-1.24-1.24.4/src/runtime/vgetrandom_unsupported.go --- golang-1.24-1.24.2/src/runtime/vgetrandom_unsupported.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/runtime/vgetrandom_unsupported.go 2025-05-30 01:07:36.000000000 +0530 @@ -13,6 +13,6 @@ return -1, false } -func vgetrandomPutState(state uintptr) {} +func vgetrandomDestroy(mp *m) {} func vgetrandomInit() {} diff -Nru golang-1.24-1.24.2/src/syscall/syscall_windows.go golang-1.24-1.24.4/src/syscall/syscall_windows.go --- golang-1.24-1.24.2/src/syscall/syscall_windows.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/src/syscall/syscall_windows.go 2025-05-30 01:07:36.000000000 +0530 @@ -376,20 +376,6 @@ if flag&O_CLOEXEC == 0 { sa = makeInheritSa() } - // We don't use CREATE_ALWAYS, because when opening a file with - // FILE_ATTRIBUTE_READONLY these will replace an existing file - // with a new, read-only one. See https://go.dev/issue/38225. - // - // Instead, we ftruncate the file after opening when O_TRUNC is set. - var createmode uint32 - switch { - case flag&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL): - createmode = CREATE_NEW - case flag&O_CREAT == O_CREAT: - createmode = OPEN_ALWAYS - default: - createmode = OPEN_EXISTING - } var attrs uint32 = FILE_ATTRIBUTE_NORMAL if perm&S_IWRITE == 0 { attrs = FILE_ATTRIBUTE_READONLY @@ -404,6 +390,21 @@ const _FILE_FLAG_WRITE_THROUGH = 0x80000000 attrs |= _FILE_FLAG_WRITE_THROUGH } + // We don't use CREATE_ALWAYS, because when opening a file with + // FILE_ATTRIBUTE_READONLY these will replace an existing file + // with a new, read-only one. See https://go.dev/issue/38225. + // + // Instead, we ftruncate the file after opening when O_TRUNC is set. + var createmode uint32 + switch { + case flag&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL): + createmode = CREATE_NEW + attrs |= FILE_FLAG_OPEN_REPARSE_POINT // don't follow symlinks + case flag&O_CREAT == O_CREAT: + createmode = OPEN_ALWAYS + default: + createmode = OPEN_EXISTING + } h, err := createFile(namep, access, sharemode, sa, createmode, attrs, 0) if h == InvalidHandle { if err == ERROR_ACCESS_DENIED && (flag&O_WRONLY != 0 || flag&O_RDWR != 0) { diff -Nru golang-1.24-1.24.2/test/fixedbugs/issue40954.go golang-1.24-1.24.4/test/fixedbugs/issue40954.go --- golang-1.24-1.24.2/test/fixedbugs/issue40954.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/test/fixedbugs/issue40954.go 2025-05-30 01:07:36.000000000 +0530 @@ -30,6 +30,8 @@ // should not be adjusted when the stack is copied. recurse(100, p, v) } + +//go:noinline func recurse(n int, p *S, v uintptr) { if n > 0 { recurse(n-1, p, v) diff -Nru golang-1.24-1.24.2/test/fixedbugs/issue52193.go golang-1.24-1.24.4/test/fixedbugs/issue52193.go --- golang-1.24-1.24.2/test/fixedbugs/issue52193.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/test/fixedbugs/issue52193.go 2025-05-30 01:07:36.000000000 +0530 @@ -11,14 +11,14 @@ func f() { // ERROR "can inline f" var i interface{ m() } = T(0) // ERROR "T\(0\) does not escape" - i.m() // ERROR "devirtualizing i.m" "inlining call to T.m" + i.m() // ERROR "devirtualizing i.m" "inlining call to T.m" "inlining call to f" "T\(0\) does not escape" } type T int func (T) m() { // ERROR "can inline T.m" if never { - f() // ERROR "inlining call to f" "devirtualizing i.m" "T\(0\) does not escape" + f() // ERROR "inlining call to f" "devirtualizing i.m" "T\(0\) does not escape" "inlining call to T.m" } } diff -Nru golang-1.24-1.24.2/test/fixedbugs/issue54159.go golang-1.24-1.24.4/test/fixedbugs/issue54159.go --- golang-1.24-1.24.2/test/fixedbugs/issue54159.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/test/fixedbugs/issue54159.go 2025-05-30 01:07:36.000000000 +0530 @@ -6,7 +6,8 @@ package main -func run() { // ERROR "cannot inline run: recursive" +//go:noinline +func run() { // ERROR "cannot inline run: marked go:noinline" f := func() { // ERROR "can inline run.func1 with cost .* as:.*" "func literal does not escape" g() // ERROR "inlining call to g" } diff -Nru golang-1.24-1.24.2/test/inline.go golang-1.24-1.24.4/test/inline.go --- golang-1.24-1.24.2/test/inline.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/test/inline.go 2025-05-30 01:07:36.000000000 +0530 @@ -280,13 +280,13 @@ if x < 0 { return } - gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh" + gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh" "inlining call to ff" } func gg(x int) { // ERROR "can inline gg" - hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff" + hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff" "inlining call to gg" } func hh(x int) { // ERROR "can inline hh" - ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg" + ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh" } // Issue #14768 - make sure we can inline for loops. @@ -332,9 +332,9 @@ // Issue #42194 - make sure that functions evaluated in // go and defer statements can be inlined. func gd1(int) { - defer gd1(gd2()) // ERROR "inlining call to gd2" + defer gd1(gd2()) // ERROR "inlining call to gd2" "can inline gd1.deferwrap1" defer gd3()() // ERROR "inlining call to gd3" - go gd1(gd2()) // ERROR "inlining call to gd2" + go gd1(gd2()) // ERROR "inlining call to gd2" "can inline gd1.gowrap2" go gd3()() // ERROR "inlining call to gd3" } diff -Nru golang-1.24-1.24.2/test/loopbce.go golang-1.24-1.24.4/test/loopbce.go --- golang-1.24-1.24.2/test/loopbce.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/test/loopbce.go 2025-05-30 01:07:36.000000000 +0530 @@ -88,6 +88,7 @@ return x } +//go:noinline func f6(a []int) { for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$" b := a[0:i] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" diff -Nru golang-1.24-1.24.2/test/newinline.go golang-1.24-1.24.4/test/newinline.go --- golang-1.24-1.24.2/test/newinline.go 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/test/newinline.go 2025-05-30 01:07:36.000000000 +0530 @@ -280,13 +280,13 @@ if x < 0 { return } - gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh" + gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh" "inlining call to ff" } func gg(x int) { // ERROR "can inline gg" - hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff" + hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff" "inlining call to gg" } func hh(x int) { // ERROR "can inline hh" - ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg" + ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh" } // Issue #14768 - make sure we can inline for loops. diff -Nru golang-1.24-1.24.2/VERSION golang-1.24-1.24.4/VERSION --- golang-1.24-1.24.2/VERSION 2025-03-27 00:39:39.000000000 +0530 +++ golang-1.24-1.24.4/VERSION 2025-05-30 01:07:36.000000000 +0530 @@ -1,2 +1,2 @@ -go1.24.2 -time 2025-03-26T19:09:39Z +go1.24.4 +time 2025-05-29T19:37:36Z