// run // Copyright 2026 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 ( "runtime" "unsafe" ) // 1 of these is 28 bytes. // When allocating 1 of them in a 32-byte size class, // we accidentally write 2 pointer bitmasks, which // marks the first 6 fields of the following object // as pointers. type E struct { a [7]*byte } // 32 bytes, and has pointers. // First field is not a pointer, but will contain // a badPtr value. type Victim struct { a uintptr b [6]int32 c *byte } //go:noinline func f(n int) []E { var r []E for range n { r = append(r, E{}) } return r } //go:noinline func newVictim() *Victim { return &Victim{a: badPtr} } var badPtr uintptr func init() { x := make([]byte, 1<<18-8) sink = &x[0] badPtr = uintptr(unsafe.Pointer(&x[len(x)-1])) + 5 } func main() { fs := make([]*Victim, 1000) // Allocate a bunch of Victims. for i := range fs { fs[i] = newVictim() } // Deallocate every other one. for i := range fs { if i%2 == 1 { fs[i] = nil } } runtime.GC() // Allocate Es in the deallocated slots. // Those allocations will incorrectly set the // pointer bit for the first field of all the // Victims we allocated. for range len(fs) / 2 { _ = f(1) } runtime.GC() // Keep fs alive. sink = &fs[0] } var sink any