Source file test/fixedbugs/issue79874.go

     1  // run
     2  
     3  //go:build (linux || darwin) && !(386 || arm || mips || mipsle)
     4  
     5  // Copyright 2026 The Go Authors. All rights reserved.
     6  // Use of this source code is governed by a BSD-style
     7  // license that can be found in the LICENSE file.
     8  
     9  package main
    10  
    11  import (
    12  	"encoding/binary"
    13  	"fmt"
    14  	"syscall"
    15  	"unsafe"
    16  )
    17  
    18  const l = 1 << 34
    19  
    20  //go:noinline
    21  func bug(s []byte) []byte {
    22  	if len(s) < l+8 {
    23  		panic("too short")
    24  	}
    25  	return s[min(l, len(s)):]
    26  }
    27  
    28  func main() {
    29  	// This code is a bit tricky because I have two contradictory constraints:
    30  	// 1. I need a slice >4GB big, ideally more (to test with non byte size element).
    31  	// 2. I can't allocate 4GB of ram in a test, let alone the 16GB I ended up using for real.
    32  	pageSize := syscall.Getpagesize()
    33  
    34  	// Allocate a bunch of zeros, because this MAP_ANON mapping lack the PROT_WRITE permission
    35  	// the kernel will use a single shared aliased zero page to back up this memory.
    36  	// We still pay on the order of 32MB for the page table entries but it's acceptable.
    37  	s, err := syscall.Mmap(-1, 0, l+pageSize, syscall.PROT_READ, syscall.MAP_ANON|syscall.MAP_PRIVATE)
    38  	if err != nil {
    39  		panic(err)
    40  	}
    41  
    42  	// Make the tail page writable. Use unsafe.Slice rather than s[l:] because s[l:] goes through the slicemask path under test.
    43  	if err := syscall.Mprotect(unsafe.Slice(&s[l], pageSize), syscall.PROT_READ|syscall.PROT_WRITE); err != nil {
    44  		panic(err)
    45  	}
    46  
    47  	// Write without using s[l:] otherwise the same bug happens here and in bug making the test pass even if the bug is present.
    48  	const sentinel uint64 = 0x1122334455667788
    49  	for i := 0; i < 8; i++ {
    50  		s[l+i] = byte(sentinel >> (8 * i))
    51  	}
    52  
    53  	// Finally test the bug.
    54  	if v := binary.LittleEndian.Uint64(bug(s)); v != sentinel {
    55  		panic(fmt.Sprintf("got %x, want %x", v, sentinel))
    56  	}
    57  }
    58  

View as plain text