Source file src/bytes/boundary_test.go

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  //
     5  //go:build linux
     6  
     7  package bytes_test
     8  
     9  import (
    10  	. "bytes"
    11  	"syscall"
    12  	"testing"
    13  )
    14  
    15  // This file tests the situation where byte operations are checking
    16  // data very near to a page boundary. We want to make sure those
    17  // operations do not read across the boundary and cause a page
    18  // fault where they shouldn't.
    19  
    20  // These tests run only on linux. The code being tested is
    21  // not OS-specific, so it does not need to be tested on all
    22  // operating systems.
    23  
    24  // dangerousSlice returns a slice which is immediately
    25  // preceded and followed by a faulting page.
    26  func dangerousSlice(t *testing.T) []byte {
    27  	pagesize := syscall.Getpagesize()
    28  	b, err := syscall.Mmap(0, 0, 3*pagesize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANONYMOUS|syscall.MAP_PRIVATE)
    29  	if err != nil {
    30  		t.Fatalf("mmap failed %s", err)
    31  	}
    32  	err = syscall.Mprotect(b[:pagesize], syscall.PROT_NONE)
    33  	if err != nil {
    34  		t.Fatalf("mprotect low failed %s\n", err)
    35  	}
    36  	err = syscall.Mprotect(b[2*pagesize:], syscall.PROT_NONE)
    37  	if err != nil {
    38  		t.Fatalf("mprotect high failed %s\n", err)
    39  	}
    40  	return b[pagesize : 2*pagesize]
    41  }
    42  
    43  func TestEqualNearPageBoundary(t *testing.T) {
    44  	t.Parallel()
    45  	b := dangerousSlice(t)
    46  	for i := range b {
    47  		b[i] = 'A'
    48  	}
    49  	for i := 0; i <= len(b); i++ {
    50  		Equal(b[:i], b[len(b)-i:])
    51  		Equal(b[len(b)-i:], b[:i])
    52  	}
    53  }
    54  
    55  func TestIndexByteNearPageBoundary(t *testing.T) {
    56  	t.Parallel()
    57  	b := dangerousSlice(t)
    58  	for i := range b {
    59  		idx := IndexByte(b[i:], 1)
    60  		if idx != -1 {
    61  			t.Fatalf("IndexByte(b[%d:])=%d, want -1\n", i, idx)
    62  		}
    63  	}
    64  }
    65  
    66  func TestIndexNearPageBoundary(t *testing.T) {
    67  	t.Parallel()
    68  	q := dangerousSlice(t)
    69  	if len(q) > 64 {
    70  		// Only worry about when we're near the end of a page.
    71  		q = q[len(q)-64:]
    72  	}
    73  	b := dangerousSlice(t)
    74  	if len(b) > 256 {
    75  		// Only worry about when we're near the end of a page.
    76  		b = b[len(b)-256:]
    77  	}
    78  	for j := 1; j < len(q); j++ {
    79  		q[j-1] = 1 // difference is only found on the last byte
    80  		for i := range b {
    81  			idx := Index(b[i:], q[:j])
    82  			if idx != -1 {
    83  				t.Fatalf("Index(b[%d:], q[:%d])=%d, want -1\n", i, j, idx)
    84  			}
    85  		}
    86  		q[j-1] = 0
    87  	}
    88  
    89  	// Test differing alignments and sizes of q which always end on a page boundary.
    90  	q[len(q)-1] = 1 // difference is only found on the last byte
    91  	for j := 0; j < len(q); j++ {
    92  		for i := range b {
    93  			idx := Index(b[i:], q[j:])
    94  			if idx != -1 {
    95  				t.Fatalf("Index(b[%d:], q[%d:])=%d, want -1\n", i, j, idx)
    96  			}
    97  		}
    98  	}
    99  	q[len(q)-1] = 0
   100  }
   101  
   102  func TestCountNearPageBoundary(t *testing.T) {
   103  	t.Parallel()
   104  	b := dangerousSlice(t)
   105  	for i := range b {
   106  		c := Count(b[i:], []byte{1})
   107  		if c != 0 {
   108  			t.Fatalf("Count(b[%d:], {1})=%d, want 0\n", i, c)
   109  		}
   110  		c = Count(b[:i], []byte{0})
   111  		if c != i {
   112  			t.Fatalf("Count(b[:%d], {0})=%d, want %d\n", i, c, i)
   113  		}
   114  	}
   115  }
   116  

View as plain text