Home | History | Annotate | Download | only in bytes
      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 // +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 	var q [64]byte
     69 	b := dangerousSlice(t)
     70 	if len(b) > 256 {
     71 		// Only worry about when we're near the end of a page.
     72 		b = b[len(b)-256:]
     73 	}
     74 	for j := 1; j < len(q); j++ {
     75 		q[j-1] = 1 // difference is only found on the last byte
     76 		for i := range b {
     77 			idx := Index(b[i:], q[:j])
     78 			if idx != -1 {
     79 				t.Fatalf("Index(b[%d:], q[:%d])=%d, want -1\n", i, j, idx)
     80 			}
     81 		}
     82 		q[j-1] = 0
     83 	}
     84 }
     85