From 2bbb2ace346a26e0b1f7e32f1cdc645db8170d1c Mon Sep 17 00:00:00 2001 From: jjpinto Date: Mon, 5 Jan 2026 23:08:44 +0000 Subject: runtime/trace: fix documentation comment Correct documentation comment for mul function Change-Id: I8b90f02bf0aaba9bb5813833d1b9dd1ebb7d71f4 GitHub-Last-Rev: e91af64af9bad9cd2574dc3dd7ed88123a288be8 GitHub-Pull-Request: golang/go#77082 Reviewed-on: https://go-review.googlesource.com/c/go/+/734100 Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/runtime/trace/recorder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/runtime') diff --git a/src/runtime/trace/recorder.go b/src/runtime/trace/recorder.go index a18d764141..8617231aaa 100644 --- a/src/runtime/trace/recorder.go +++ b/src/runtime/trace/recorder.go @@ -112,7 +112,7 @@ func runtime_traceClockNow() uint64 // frequency is nanoseconds per timestamp unit. type frequency float64 -// mul multiplies an unprocessed to produce a time in nanoseconds. +// mul multiplies an unprocessed timestamp to produce a time in nanoseconds. func (f frequency) mul(t timestamp) eventTime { return eventTime(float64(t) * float64(f)) } -- cgit v1.3 From e2fef50def98b87107ab963f657d43d7869b8463 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Mon, 12 Jan 2026 14:37:39 -0500 Subject: runtime: rename mallocTiny* to mallocgcTinySize* This makes it easier to identify which functions are used for memory allocation by looking for functions that start with mallocgc. The Size suffix is added so that the isSpecializedMalloc function in cmd/compile/internal/ssa can distinguish between the generated functions and the mallocgcTiny function called by mallocgc, similar to the SC suffixes for the mallocgcSmallNoScanSC* and mallocgcSmallScanNoHeaderSC* functons. Change-Id: I6ad7f15617bf6f18ae5d1bfa2a0b94e86a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/735780 Reviewed-by: Michael Matloob Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/ssa/rewrite.go | 2 +- src/cmd/compile/internal/ssagen/ssa.go | 2 +- src/runtime/_mkmalloc/mkmalloc.go | 2 +- src/runtime/malloc_generated.go | 30 +++++++++++++++--------------- src/runtime/malloc_tables_generated.go | 30 +++++++++++++++--------------- test/codegen/strings.go | 2 +- test/live.go | 4 ++-- test/live_regabi.go | 4 ++-- 8 files changed, 38 insertions(+), 38 deletions(-) (limited to 'src/runtime') diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index af2568ae89..032915f701 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -480,7 +480,7 @@ func isSpecializedMalloc(aux Aux) bool { name := fn.String() return strings.HasPrefix(name, "runtime.mallocgcSmallNoScanSC") || strings.HasPrefix(name, "runtime.mallocgcSmallScanNoHeaderSC") || - strings.HasPrefix(name, "runtime.mallocTiny") + strings.HasPrefix(name, "runtime.mallocgcTinySize") } // canLoadUnaligned reports if the architecture supports unaligned load operations. diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index dd5baa0ed5..17feb90df7 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -140,7 +140,7 @@ func InitConfig() { ir.Syms.MallocGCSmallScanNoHeader[i] = typecheck.LookupRuntimeFunc(fmt.Sprintf("mallocgcSmallScanNoHeaderSC%d", i)) } for i := 1; i < len(ir.Syms.MallocGCTiny); i++ { - ir.Syms.MallocGCTiny[i] = typecheck.LookupRuntimeFunc(fmt.Sprintf("mallocTiny%d", i)) + ir.Syms.MallocGCTiny[i] = typecheck.LookupRuntimeFunc(fmt.Sprintf("mallocgcTinySize%d", i)) } ir.Syms.MallocGC = typecheck.LookupRuntimeFunc("mallocgc") ir.Syms.Memmove = typecheck.LookupRuntimeFunc("memmove") diff --git a/src/runtime/_mkmalloc/mkmalloc.go b/src/runtime/_mkmalloc/mkmalloc.go index 434eaad767..450608a7a4 100644 --- a/src/runtime/_mkmalloc/mkmalloc.go +++ b/src/runtime/_mkmalloc/mkmalloc.go @@ -130,7 +130,7 @@ func tinyFuncName(size uintptr) string { if size == 0 || size > smallScanNoHeaderMax { return "mallocPanic" } - return fmt.Sprintf("mallocTiny%d", size) + return fmt.Sprintf("mallocgcTinySize%d", size) } func smallNoScanSCFuncName(sc, scMax uint8) string { diff --git a/src/runtime/malloc_generated.go b/src/runtime/malloc_generated.go index 2be6a5b6f5..8d7112646f 100644 --- a/src/runtime/malloc_generated.go +++ b/src/runtime/malloc_generated.go @@ -4300,7 +4300,7 @@ func mallocgcSmallScanNoHeaderSC26(size uintptr, typ *_type, needzero bool) unsa return x } -func mallocTiny1(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize1(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -4456,7 +4456,7 @@ func mallocTiny1(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny2(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize2(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -4612,7 +4612,7 @@ func mallocTiny2(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny3(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize3(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -4768,7 +4768,7 @@ func mallocTiny3(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny4(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize4(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -4924,7 +4924,7 @@ func mallocTiny4(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny5(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize5(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -5080,7 +5080,7 @@ func mallocTiny5(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny6(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize6(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -5236,7 +5236,7 @@ func mallocTiny6(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny7(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize7(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -5392,7 +5392,7 @@ func mallocTiny7(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny8(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize8(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -5548,7 +5548,7 @@ func mallocTiny8(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny9(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize9(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -5704,7 +5704,7 @@ func mallocTiny9(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny10(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize10(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -5860,7 +5860,7 @@ func mallocTiny10(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny11(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize11(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -6016,7 +6016,7 @@ func mallocTiny11(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny12(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize12(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -6172,7 +6172,7 @@ func mallocTiny12(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny13(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize13(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -6328,7 +6328,7 @@ func mallocTiny13(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny14(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize14(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { @@ -6484,7 +6484,7 @@ func mallocTiny14(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } -func mallocTiny15(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySize15(size uintptr, typ *_type, needzero bool) unsafe.Pointer { gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { diff --git a/src/runtime/malloc_tables_generated.go b/src/runtime/malloc_tables_generated.go index 36650881fe..b1ddde2aad 100644 --- a/src/runtime/malloc_tables_generated.go +++ b/src/runtime/malloc_tables_generated.go @@ -523,21 +523,21 @@ var mallocScanTable = [513]func(size uintptr, typ *_type, needzero bool) unsafe. var mallocNoScanTable = [513]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{ mallocPanic, - mallocTiny1, - mallocTiny2, - mallocTiny3, - mallocTiny4, - mallocTiny5, - mallocTiny6, - mallocTiny7, - mallocTiny8, - mallocTiny9, - mallocTiny10, - mallocTiny11, - mallocTiny12, - mallocTiny13, - mallocTiny14, - mallocTiny15, + mallocgcTinySize1, + mallocgcTinySize2, + mallocgcTinySize3, + mallocgcTinySize4, + mallocgcTinySize5, + mallocgcTinySize6, + mallocgcTinySize7, + mallocgcTinySize8, + mallocgcTinySize9, + mallocgcTinySize10, + mallocgcTinySize11, + mallocgcTinySize12, + mallocgcTinySize13, + mallocgcTinySize14, + mallocgcTinySize15, mallocgcSmallNoScanSC2, mallocgcSmallNoScanSC3, mallocgcSmallNoScanSC3, diff --git a/test/codegen/strings.go b/test/codegen/strings.go index 0c5ee2f8f5..1c14021150 100644 --- a/test/codegen/strings.go +++ b/test/codegen/strings.go @@ -23,7 +23,7 @@ func CountBytes(s []byte) int { func ToByteSlice() []byte { // Issue #24698 // amd64:`LEAQ type:\[3\]uint8` - // amd64:`CALL runtime\.(newobject|mallocTiny3)` + // amd64:`CALL runtime\.(newobject|mallocgcTinySize3)` // amd64:-`.*runtime.stringtoslicebyte` return []byte("foo") } diff --git a/test/live.go b/test/live.go index f8ad8df1ca..6561b20925 100644 --- a/test/live.go +++ b/test/live.go @@ -665,14 +665,14 @@ func f39a() (x []int) { func f39b() (x [10]*int) { x = [10]*int{} - x[0] = new(int) // ERROR "live at call to (newobject|mallocTiny[48]): x$" + x[0] = new(int) // ERROR "live at call to (newobject|mallocgcTinySize[48]): x$" printnl() // ERROR "live at call to printnl: x$" return x } func f39c() (x [10]*int) { x = [10]*int{} - x[0] = new(int) // ERROR "live at call to (newobject|mallocTiny[48]): x$" + x[0] = new(int) // ERROR "live at call to (newobject|mallocgcTinySize[48]): x$" printnl() // ERROR "live at call to printnl: x$" return } diff --git a/test/live_regabi.go b/test/live_regabi.go index 9809353f1b..75b842d732 100644 --- a/test/live_regabi.go +++ b/test/live_regabi.go @@ -663,14 +663,14 @@ func f39a() (x []int) { func f39b() (x [10]*int) { x = [10]*int{} - x[0] = new(int) // ERROR "live at call to (newobject|mallocTiny[48]): x$" + x[0] = new(int) // ERROR "live at call to (newobject|mallocgcTinySize[48]): x$" printnl() // ERROR "live at call to printnl: x$" return x } func f39c() (x [10]*int) { x = [10]*int{} - x[0] = new(int) // ERROR "live at call to (newobject|mallocTiny[48]): x$" + x[0] = new(int) // ERROR "live at call to (newobject|mallocgcTinySize[48]): x$" printnl() // ERROR "live at call to printnl: x$" return } -- cgit v1.3 From 2dcaaa751295597e1f603b7488c4624db6a84d2b Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Mon, 3 Nov 2025 14:28:47 -0800 Subject: net/url: add urlmaxqueryparams GODEBUG to limit the number of query parameters net/url does not currently limit the number of query parameters parsed by url.ParseQuery or URL.Query. When parsing a application/x-www-form-urlencoded form, net/http.Request.ParseForm will parse up to 10 MB of query parameters. An input consisting of a large number of small, unique parameters can cause excessive memory consumption. We now limit the number of query parameters parsed to 10000 by default. The limit can be adjusted by setting GODEBUG=urlmaxqueryparams=. Setting urlmaxqueryparams to 0 disables the limit. Thanks to jub0bs for reporting this issue. Fixes #77101 Fixes CVE-2025-61726 Change-Id: Iee3374c7ee2d8586dbf158536d3ade424203ff66 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3020 Reviewed-by: Nicholas Husin Reviewed-by: Neal Patel Reviewed-on: https://go-review.googlesource.com/c/go/+/736712 Auto-Submit: Michael Pratt Reviewed-by: Junyang Shao LUCI-TryBot-Result: Go LUCI --- doc/godebug.md | 7 ++++++ src/internal/godebugs/table.go | 1 + src/net/url/url.go | 23 ++++++++++++++++++++ src/net/url/url_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++ src/runtime/metrics/doc.go | 5 +++++ 5 files changed, 84 insertions(+) (limited to 'src/runtime') diff --git a/doc/godebug.md b/doc/godebug.md index 28a2dc506e..184e161c40 100644 --- a/doc/godebug.md +++ b/doc/godebug.md @@ -163,6 +163,13 @@ will fail early. The default value is `httpcookiemaxnum=3000`. Setting number of cookies. To avoid denial of service attacks, this setting and default was backported to Go 1.25.2 and Go 1.24.8. +Go 1.26 added a new `urlmaxqueryparams` setting that controls the maximum number +of query parameters that net/url will accept when parsing a URL-encoded query string. +If the number of parameters exceeds the number set in `urlmaxqueryparams`, +parsing will fail early. The default value is `urlmaxqueryparams=10000`. +Setting `urlmaxqueryparams=0`bles the limit. To avoid denial of service attacks, +this setting and default was backported to Go 1.25.4 and Go 1.24.10. + Go 1.26 added a new `urlstrictcolons` setting that controls whether `net/url.Parse` allows malformed hostnames containing colons outside of a bracketed IPv6 address. The default `urlstrictcolons=1` rejects URLs such as `http://localhost:1:2` or `http://::1/`. diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go index 8f6d8bbdda..87b499385a 100644 --- a/src/internal/godebugs/table.go +++ b/src/internal/godebugs/table.go @@ -69,6 +69,7 @@ var All = []Info{ {Name: "tlssha1", Package: "crypto/tls", Changed: 25, Old: "1"}, {Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"}, {Name: "updatemaxprocs", Package: "runtime", Changed: 25, Old: "0"}, + {Name: "urlmaxqueryparams", Package: "net/url", Changed: 24, Old: "0"}, {Name: "urlstrictcolons", Package: "net/url", Changed: 26, Old: "0"}, {Name: "winreadlinkvolume", Package: "os", Changed: 23, Old: "0"}, {Name: "winsymlink", Package: "os", Changed: 23, Old: "0"}, diff --git a/src/net/url/url.go b/src/net/url/url.go index 3acd202c24..202957a3a2 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -929,7 +929,30 @@ func ParseQuery(query string) (Values, error) { return m, err } +var urlmaxqueryparams = godebug.New("urlmaxqueryparams") + +const defaultMaxParams = 10000 + +func urlParamsWithinMax(params int) bool { + withinDefaultMax := params <= defaultMaxParams + if urlmaxqueryparams.Value() == "" { + return withinDefaultMax + } + customMax, err := strconv.Atoi(urlmaxqueryparams.Value()) + if err != nil { + return withinDefaultMax + } + withinCustomMax := customMax == 0 || params < customMax + if withinDefaultMax != withinCustomMax { + urlmaxqueryparams.IncNonDefault() + } + return withinCustomMax +} + func parseQuery(m Values, query string) (err error) { + if !urlParamsWithinMax(strings.Count(query, "&") + 1) { + return errors.New("number of URL query parameters exceeded limit") + } for query != "" { var key string key, query, _ = strings.Cut(query, "&") diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index bb48bb6bee..d099353eb2 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -1521,6 +1521,54 @@ func TestParseQuery(t *testing.T) { } } +func TestParseQueryLimits(t *testing.T) { + for _, test := range []struct { + params int + godebug string + wantErr bool + }{{ + params: 10, + wantErr: false, + }, { + params: defaultMaxParams, + wantErr: false, + }, { + params: defaultMaxParams + 1, + wantErr: true, + }, { + params: 10, + godebug: "urlmaxqueryparams=9", + wantErr: true, + }, { + params: defaultMaxParams + 1, + godebug: "urlmaxqueryparams=0", + wantErr: false, + }} { + t.Setenv("GODEBUG", test.godebug) + want := Values{} + var b strings.Builder + for i := range test.params { + if i > 0 { + b.WriteString("&") + } + p := fmt.Sprintf("p%v", i) + b.WriteString(p) + want[p] = []string{""} + } + query := b.String() + got, err := ParseQuery(query) + if gotErr, wantErr := err != nil, test.wantErr; gotErr != wantErr { + t.Errorf("GODEBUG=%v ParseQuery(%v params) = %v, want error: %v", test.godebug, test.params, err, wantErr) + } + if err != nil { + continue + } + if got, want := len(got), test.params; got != want { + t.Errorf("GODEBUG=%v ParseQuery(%v params): got %v params, want %v", test.godebug, test.params, got, want) + } + } +} + type RequestURITest struct { url *URL out string diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go index ca032f51b1..6b774c36f3 100644 --- a/src/runtime/metrics/doc.go +++ b/src/runtime/metrics/doc.go @@ -404,6 +404,11 @@ Below is the full list of supported metrics, ordered lexicographically. The number of non-default behaviors executed by the runtime package due to a non-default GODEBUG=updatemaxprocs=... setting. + /godebug/non-default-behavior/urlmaxqueryparams:events + The number of non-default behaviors executed by the net/url + package due to a non-default GODEBUG=urlmaxqueryparams=... + setting. + /godebug/non-default-behavior/urlstrictcolons:events The number of non-default behaviors executed by the net/url package due to a non-default GODEBUG=urlstrictcolons=... -- cgit v1.3 From 2baa1d17628bb2f09757617382b1e61f1f9f0ddd Mon Sep 17 00:00:00 2001 From: Youlin Feng Date: Sat, 17 Jan 2026 14:20:22 +0800 Subject: runtime: remove the unused scanIdx from mspan After CL 700496, mspan.scanIdx is never used, this CL just remove it. Change-Id: I41ce9902957c0cfa6fbf26b66a2a7787b179376a Reviewed-on: https://go-review.googlesource.com/c/go/+/737220 LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee Auto-Submit: Carlos Amedee Reviewed-by: Michael Knyszek --- src/runtime/mheap.go | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 68dfca4668..9b62ee4273 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -457,12 +457,6 @@ type mspan struct { // mallocgc, and issue 54596). freeIndexForScan uint16 - // Temporary storage for the object index that caused this span to - // be queued for scanning. - // - // Used only with goexperiment.GreenTeaGC. - scanIdx uint16 - // Cache of the allocBits at freeindex. allocCache is shifted // such that the lowest bit corresponds to the bit freeindex. // allocCache holds the complement of allocBits, thus allowing -- cgit v1.3