From: Daniel Morsing Date: Tue, 16 Dec 2025 13:50:57 +0000 (+0000) Subject: runtime: keep track of secret allocation size X-Git-Tag: go1.26rc2~7^2~62 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=b8c4cc63e77bd457dffa6ec83a3ff65382dac94b;p=gostls13.git runtime: keep track of secret allocation size During a naive attempt to test the new runtime/secret package, I tried wrapping the entire handshake in a secret.Do call. This lead to a panic because some of the allocator logic had been previously untested. freeSpecial takes p and size, but they can be misleading. They don't refer to the pointer and size of the object with the special attached, but a pointer to the enclosing object and the size of the span element. The previous code did not take this into account and when passing the size to memclr would overwrite nearby objects. Fix by storing the size of the object being cleared inside the special. Fixes #76865. Change-Id: Ifae31f1c8d0609a562a37f37c45aec2f369dc6a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/730361 Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index fd79356aba..c08bc7574b 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -1213,7 +1213,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { if goexperiment.RuntimeSecret && gp.secret > 0 { // Mark any object allocated while in secret mode as secret. // This ensures we zero it immediately when freeing it. - addSecret(x) + addSecret(x, size) } // Notify sanitizers, if enabled. diff --git a/src/runtime/malloc_generated.go b/src/runtime/malloc_generated.go index cf329d2696..2be6a5b6f5 100644 --- a/src/runtime/malloc_generated.go +++ b/src/runtime/malloc_generated.go @@ -156,7 +156,7 @@ func mallocgcSmallScanNoHeaderSC1(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -321,7 +321,7 @@ func mallocgcSmallScanNoHeaderSC2(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -486,7 +486,7 @@ func mallocgcSmallScanNoHeaderSC3(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -651,7 +651,7 @@ func mallocgcSmallScanNoHeaderSC4(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -816,7 +816,7 @@ func mallocgcSmallScanNoHeaderSC5(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -981,7 +981,7 @@ func mallocgcSmallScanNoHeaderSC6(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -1146,7 +1146,7 @@ func mallocgcSmallScanNoHeaderSC7(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -1311,7 +1311,7 @@ func mallocgcSmallScanNoHeaderSC8(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -1476,7 +1476,7 @@ func mallocgcSmallScanNoHeaderSC9(size uintptr, typ *_type, needzero bool) unsaf gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -1641,7 +1641,7 @@ func mallocgcSmallScanNoHeaderSC10(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -1806,7 +1806,7 @@ func mallocgcSmallScanNoHeaderSC11(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -1971,7 +1971,7 @@ func mallocgcSmallScanNoHeaderSC12(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -2136,7 +2136,7 @@ func mallocgcSmallScanNoHeaderSC13(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -2301,7 +2301,7 @@ func mallocgcSmallScanNoHeaderSC14(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -2466,7 +2466,7 @@ func mallocgcSmallScanNoHeaderSC15(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -2631,7 +2631,7 @@ func mallocgcSmallScanNoHeaderSC16(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -2796,7 +2796,7 @@ func mallocgcSmallScanNoHeaderSC17(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -2961,7 +2961,7 @@ func mallocgcSmallScanNoHeaderSC18(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -3126,7 +3126,7 @@ func mallocgcSmallScanNoHeaderSC19(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -3291,7 +3291,7 @@ func mallocgcSmallScanNoHeaderSC20(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -3456,7 +3456,7 @@ func mallocgcSmallScanNoHeaderSC21(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -3621,7 +3621,7 @@ func mallocgcSmallScanNoHeaderSC22(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -3786,7 +3786,7 @@ func mallocgcSmallScanNoHeaderSC23(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -3951,7 +3951,7 @@ func mallocgcSmallScanNoHeaderSC24(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -4116,7 +4116,7 @@ func mallocgcSmallScanNoHeaderSC25(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -4281,7 +4281,7 @@ func mallocgcSmallScanNoHeaderSC26(size uintptr, typ *_type, needzero bool) unsa gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -6686,7 +6686,7 @@ func mallocgcSmallNoScanSC2(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -6757,7 +6757,7 @@ func mallocgcSmallNoScanSC2(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -6822,7 +6822,7 @@ func mallocgcSmallNoScanSC3(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -6893,7 +6893,7 @@ func mallocgcSmallNoScanSC3(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -6958,7 +6958,7 @@ func mallocgcSmallNoScanSC4(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7029,7 +7029,7 @@ func mallocgcSmallNoScanSC4(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7094,7 +7094,7 @@ func mallocgcSmallNoScanSC5(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7165,7 +7165,7 @@ func mallocgcSmallNoScanSC5(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7230,7 +7230,7 @@ func mallocgcSmallNoScanSC6(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7301,7 +7301,7 @@ func mallocgcSmallNoScanSC6(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7366,7 +7366,7 @@ func mallocgcSmallNoScanSC7(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7437,7 +7437,7 @@ func mallocgcSmallNoScanSC7(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7502,7 +7502,7 @@ func mallocgcSmallNoScanSC8(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7573,7 +7573,7 @@ func mallocgcSmallNoScanSC8(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7638,7 +7638,7 @@ func mallocgcSmallNoScanSC9(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7709,7 +7709,7 @@ func mallocgcSmallNoScanSC9(size uintptr, typ *_type, needzero bool) unsafe.Poin gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7774,7 +7774,7 @@ func mallocgcSmallNoScanSC10(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7845,7 +7845,7 @@ func mallocgcSmallNoScanSC10(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7910,7 +7910,7 @@ func mallocgcSmallNoScanSC11(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -7981,7 +7981,7 @@ func mallocgcSmallNoScanSC11(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8046,7 +8046,7 @@ func mallocgcSmallNoScanSC12(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8117,7 +8117,7 @@ func mallocgcSmallNoScanSC12(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8182,7 +8182,7 @@ func mallocgcSmallNoScanSC13(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8253,7 +8253,7 @@ func mallocgcSmallNoScanSC13(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8318,7 +8318,7 @@ func mallocgcSmallNoScanSC14(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8389,7 +8389,7 @@ func mallocgcSmallNoScanSC14(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8454,7 +8454,7 @@ func mallocgcSmallNoScanSC15(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8525,7 +8525,7 @@ func mallocgcSmallNoScanSC15(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8590,7 +8590,7 @@ func mallocgcSmallNoScanSC16(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8661,7 +8661,7 @@ func mallocgcSmallNoScanSC16(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8726,7 +8726,7 @@ func mallocgcSmallNoScanSC17(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8797,7 +8797,7 @@ func mallocgcSmallNoScanSC17(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8862,7 +8862,7 @@ func mallocgcSmallNoScanSC18(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8933,7 +8933,7 @@ func mallocgcSmallNoScanSC18(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -8998,7 +8998,7 @@ func mallocgcSmallNoScanSC19(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9069,7 +9069,7 @@ func mallocgcSmallNoScanSC19(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9134,7 +9134,7 @@ func mallocgcSmallNoScanSC20(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9205,7 +9205,7 @@ func mallocgcSmallNoScanSC20(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9270,7 +9270,7 @@ func mallocgcSmallNoScanSC21(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9341,7 +9341,7 @@ func mallocgcSmallNoScanSC21(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9406,7 +9406,7 @@ func mallocgcSmallNoScanSC22(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9477,7 +9477,7 @@ func mallocgcSmallNoScanSC22(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9542,7 +9542,7 @@ func mallocgcSmallNoScanSC23(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9613,7 +9613,7 @@ func mallocgcSmallNoScanSC23(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9678,7 +9678,7 @@ func mallocgcSmallNoScanSC24(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9749,7 +9749,7 @@ func mallocgcSmallNoScanSC24(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9814,7 +9814,7 @@ func mallocgcSmallNoScanSC25(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9885,7 +9885,7 @@ func mallocgcSmallNoScanSC25(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -9950,7 +9950,7 @@ func mallocgcSmallNoScanSC26(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { @@ -10021,7 +10021,7 @@ func mallocgcSmallNoScanSC26(size uintptr, typ *_type, needzero bool) unsafe.Poi gp := getg() if goexperiment.RuntimeSecret && gp.secret > 0 { - addSecret(x) + addSecret(x, size) } if valgrindenabled { diff --git a/src/runtime/malloc_stubs.go b/src/runtime/malloc_stubs.go index 8c424935bf..b395172e4b 100644 --- a/src/runtime/malloc_stubs.go +++ b/src/runtime/malloc_stubs.go @@ -101,7 +101,7 @@ func mallocStub(size uintptr, typ *_type, needzero bool) unsafe.Pointer { if goexperiment.RuntimeSecret && gp.secret > 0 { // Mark any object allocated while in secret mode as secret. // This ensures we zero it immediately when freeing it. - addSecret(x) + addSecret(x, size) } } diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 61dc5457fc..68dfca4668 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -2745,6 +2745,14 @@ type specialPinCounter struct { counter uintptr } +// specialSecret tracks whether we need to zero an object immediately +// upon freeing. +type specialSecret struct { + _ sys.NotInHeap + special special + size uintptr +} + // specialsIter helps iterate over specials lists. type specialsIter struct { pprev **special @@ -2775,6 +2783,12 @@ func (i *specialsIter) unlinkAndNext() *special { // freeSpecial performs any cleanup on special s and deallocates it. // s must already be unlinked from the specials list. +// TODO(mknyszek): p and size together DO NOT represent a valid allocation. +// size is the size of the allocation block in the span (mspan.elemsize), and p is +// whatever pointer the special was attached to, which need not point to the +// beginning of the block, though it may. +// Consider passing the arguments differently to avoid giving the impression +// that p and size together represent an address range. func freeSpecial(s *special, p unsafe.Pointer, size uintptr) { switch s.kind { case _KindSpecialFinalizer: @@ -2828,7 +2842,19 @@ func freeSpecial(s *special, p unsafe.Pointer, size uintptr) { mheap_.specialBubbleAlloc.free(unsafe.Pointer(st)) unlock(&mheap_.speciallock) case _KindSpecialSecret: - memclrNoHeapPointers(p, size) + ss := (*specialSecret)(unsafe.Pointer(s)) + // p is the actual byte location that the special was + // attached to, but the size argument is the span + // element size. If we were to zero out using the size + // argument, we'd trounce over adjacent memory in cases + // where the allocation contains a header. Hence, we use + // the user-visible size which we stash in the special itself. + // + // p always points to the beginning of the user-visible + // allocation since the only way to attach a secret special + // is via the allocation path. This isn't universal for + // tiny allocs, but we avoid them in mallocgc anyway. + memclrNoHeapPointers(p, ss.size) lock(&mheap_.speciallock) mheap_.specialSecretAlloc.free(unsafe.Pointer(s)) unlock(&mheap_.speciallock) diff --git a/src/runtime/secret.go b/src/runtime/secret.go index 4c199d31d0..8aad63b54f 100644 --- a/src/runtime/secret.go +++ b/src/runtime/secret.go @@ -55,15 +55,9 @@ func secret_eraseSecrets() { // Don't put any code here: the stack frame's contents are gone! } -// specialSecret tracks whether we need to zero an object immediately -// upon freeing. -type specialSecret struct { - special special -} - // addSecret records the fact that we need to zero p immediately // when it is freed. -func addSecret(p unsafe.Pointer) { +func addSecret(p unsafe.Pointer, size uintptr) { // TODO(dmo): figure out the cost of these. These are mostly // intended to catch allocations that happen via the runtime // that the user has no control over and not big buffers that user @@ -72,6 +66,7 @@ func addSecret(p unsafe.Pointer) { lock(&mheap_.speciallock) s := (*specialSecret)(mheap_.specialSecretAlloc.alloc()) s.special.kind = _KindSpecialSecret + s.size = size unlock(&mheap_.speciallock) addspecial(p, &s.special, false) } diff --git a/src/runtime/secret/alloc_test.go b/src/runtime/secret/alloc_test.go new file mode 100644 index 0000000000..8f82dad4b5 --- /dev/null +++ b/src/runtime/secret/alloc_test.go @@ -0,0 +1,39 @@ +// 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. + +//go:build goexperiment.runtimesecret && (arm64 || amd64) && linux + +package secret_test + +import ( + "runtime" + "runtime/secret" + "testing" +) + +func TestInterleavedAllocFrees(t *testing.T) { + // Interleave heap objects that are kept alive beyond secret.Do + // with heap objects that do not live past secret.Do. + // The intent is for the clearing of one object (with the wrong size) + // to clobber the type header of the next slot. If the GC sees a nil type header + // when it expects to find one, it can throw. + type T struct { + p *int + x [1024]byte + } + for range 10 { + var s []*T + secret.Do(func() { + for i := range 100 { + t := &T{} + if i%2 == 0 { + s = append(s, t) + } + } + }) + runtime.GC() + runtime.GC() + runtime.KeepAlive(s) + } +} diff --git a/src/runtime/secret_nosecret.go b/src/runtime/secret_nosecret.go index bf50fb5a54..0692d6bf70 100644 --- a/src/runtime/secret_nosecret.go +++ b/src/runtime/secret_nosecret.go @@ -22,9 +22,7 @@ func secret_dec() {} //go:linkname secret_eraseSecrets runtime/secret.eraseSecrets func secret_eraseSecrets() {} -func addSecret(p unsafe.Pointer) {} - -type specialSecret struct{} +func addSecret(p unsafe.Pointer, size uintptr) {} //go:linkname secret_getStack runtime/secret.getStack func secret_getStack() (uintptr, uintptr) { return 0, 0 }