Source file test/fixedbugs/issue80004.go

     1  // run
     2  
     3  // Copyright 2026 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package main
     8  
     9  import (
    10  	"runtime"
    11  	"unsafe"
    12  )
    13  
    14  // 1 of these is 28 bytes.
    15  // When allocating 1 of them in a 32-byte size class,
    16  // we accidentally write 2 pointer bitmasks, which
    17  // marks the first 6 fields of the following object
    18  // as pointers.
    19  type E struct {
    20  	a [7]*byte
    21  }
    22  
    23  // 32 bytes, and has pointers.
    24  // First field is not a pointer, but will contain
    25  // a badPtr value.
    26  type Victim struct {
    27  	a uintptr
    28  	b [6]int32
    29  	c *byte
    30  }
    31  
    32  //go:noinline
    33  func f(n int) []E {
    34  	var r []E
    35  	for range n {
    36  		r = append(r, E{})
    37  	}
    38  	return r
    39  }
    40  
    41  //go:noinline
    42  func newVictim() *Victim {
    43  	return &Victim{a: badPtr}
    44  }
    45  
    46  var badPtr uintptr
    47  
    48  func init() {
    49  	x := make([]byte, 1<<18-8)
    50  	sink = &x[0]
    51  	badPtr = uintptr(unsafe.Pointer(&x[len(x)-1])) + 5
    52  }
    53  
    54  func main() {
    55  	fs := make([]*Victim, 1000)
    56  
    57  	// Allocate a bunch of Victims.
    58  	for i := range fs {
    59  		fs[i] = newVictim()
    60  	}
    61  	// Deallocate every other one.
    62  	for i := range fs {
    63  		if i%2 == 1 {
    64  			fs[i] = nil
    65  		}
    66  	}
    67  	runtime.GC()
    68  
    69  	// Allocate Es in the deallocated slots.
    70  	// Those allocations will incorrectly set the
    71  	// pointer bit for the first field of all the
    72  	// Victims we allocated.
    73  	for range len(fs) / 2 {
    74  		_ = f(1)
    75  	}
    76  	runtime.GC()
    77  
    78  	// Keep fs alive.
    79  	sink = &fs[0]
    80  }
    81  
    82  var sink any
    83  

View as plain text