]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: keep track of secret allocation size
authorDaniel Morsing <daniel.morsing@gmail.com>
Tue, 16 Dec 2025 13:50:57 +0000 (13:50 +0000)
committerMichael Knyszek <mknyszek@google.com>
Wed, 17 Dec 2025 21:04:25 +0000 (13:04 -0800)
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 <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
src/runtime/malloc.go
src/runtime/malloc_generated.go
src/runtime/malloc_stubs.go
src/runtime/mheap.go
src/runtime/secret.go
src/runtime/secret/alloc_test.go [new file with mode: 0644]
src/runtime/secret_nosecret.go

index fd79356abab7644a76dc2a1ef4ad7e51bf6d8573..c08bc7574ba4117f6539c16c8cba806b820a1c06 100644 (file)
@@ -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.
index cf329d26969e7fcfdcd7c8618cf18f092bdfb599..2be6a5b6f502976991a936a5b955da249c2ffe32 100644 (file)
@@ -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 {
index 8c424935bf25c33727c2a36ec43ff1c05d305c45..b395172e4b8feb7aec61df2b296fd035326ffbce 100644 (file)
@@ -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)
                }
        }
 
index 61dc5457fc14ca635290070858bbc1e3613b0188..68dfca4668602471695b9664e5e46b28978aeeda 100644 (file)
@@ -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)
index 4c199d31d03ac5487bd6e1fe82bf4e1ffbe819d5..8aad63b54fb5dfa45ad97dc49d4f9c884cc90fa4 100644 (file)
@@ -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 (file)
index 0000000..8f82dad
--- /dev/null
@@ -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)
+       }
+}
index bf50fb5a54ce6512381ee1650eef2b66f1878936..0692d6bf702b2967915988c54cf3a4df46968783 100644 (file)
@@ -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 }