]> Cypherpunks repositories - gostls13.git/commitdiff
bytes: add more page boundary tests
authorKeith Randall <keithr@alum.mit.edu>
Fri, 3 Nov 2017 17:30:14 +0000 (10:30 -0700)
committerKeith Randall <khr@golang.org>
Fri, 3 Nov 2017 18:51:51 +0000 (18:51 +0000)
Make sure Index and IndexByte don't read past the queried byte slice.

Hopefully will be helpful for CL 33597.

Also remove the code which maps/unmaps the Go heap.
Much safer to play with protection bits off-heap.

Change-Id: I50d73e879b2d83285e1bc7c3e810efe4c245fe75
Reviewed-on: https://go-review.googlesource.com/75890
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/bytes/boundary_test.go [new file with mode: 0644]
src/bytes/equal_test.go [deleted file]

diff --git a/src/bytes/boundary_test.go b/src/bytes/boundary_test.go
new file mode 100644 (file)
index 0000000..f9e20e3
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2017 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.
+//
+// +build linux
+
+package bytes_test
+
+import (
+       . "bytes"
+       "syscall"
+       "testing"
+)
+
+// This file tests the situation where byte operations are checking
+// data very near to a page boundary. We want to make sure those
+// operations do not read across the boundary and cause a page
+// fault where they shouldn't.
+
+// These tests run only on linux. The code being tested is
+// not OS-specific, so it does not need to be tested on all
+// operating systems.
+
+// dangerousSlice returns a slice which is immediately
+// preceded and followed by a faulting page.
+func dangerousSlice(t *testing.T) []byte {
+       pagesize := syscall.Getpagesize()
+       b, err := syscall.Mmap(0, 0, 3*pagesize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANONYMOUS|syscall.MAP_PRIVATE)
+       if err != nil {
+               t.Fatalf("mmap failed %s", err)
+       }
+       err = syscall.Mprotect(b[:pagesize], syscall.PROT_NONE)
+       if err != nil {
+               t.Fatalf("mprotect low failed %s\n", err)
+       }
+       err = syscall.Mprotect(b[2*pagesize:], syscall.PROT_NONE)
+       if err != nil {
+               t.Fatalf("mprotect high failed %s\n", err)
+       }
+       return b[pagesize : 2*pagesize]
+}
+
+func TestEqualNearPageBoundary(t *testing.T) {
+       t.Parallel()
+       b := dangerousSlice(t)
+       for i := range b {
+               b[i] = 'A'
+       }
+       for i := 0; i <= len(b); i++ {
+               Equal(b[:i], b[len(b)-i:])
+               Equal(b[len(b)-i:], b[:i])
+       }
+}
+
+func TestIndexByteNearPageBoundary(t *testing.T) {
+       t.Parallel()
+       b := dangerousSlice(t)
+       for i := range b {
+               idx := IndexByte(b[i:], 1)
+               if idx != -1 {
+                       t.Fatalf("IndexByte(b[%d:])=%d, want -1\n", i, idx)
+               }
+       }
+}
+
+func TestIndexNearPageBoundary(t *testing.T) {
+       t.Parallel()
+       var q [64]byte
+       b := dangerousSlice(t)
+       for j := 1; j < len(q); j++ {
+               q[j-1] = 1 // difference is only found on the last byte
+               for i := range b {
+                       idx := Index(b[i:], q[:j])
+                       if idx != -1 {
+                               t.Fatalf("Index(b[%d:], q[:%d])=%d, want -1\n", i, j, idx)
+                       }
+               }
+               q[j-1] = 0
+       }
+}
diff --git a/src/bytes/equal_test.go b/src/bytes/equal_test.go
deleted file mode 100644 (file)
index 9fdead8..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2013 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.
-//
-// +build linux
-
-package bytes_test
-
-import (
-       . "bytes"
-       "syscall"
-       "testing"
-       "unsafe"
-)
-
-// This file tests the situation where memeq is checking
-// data very near to a page boundary. We want to make sure
-// equal does not read across the boundary and cause a page
-// fault where it shouldn't.
-
-// This test runs only on linux. The code being tested is
-// not OS-specific, so it does not need to be tested on all
-// operating systems.
-
-func TestEqualNearPageBoundary(t *testing.T) {
-       pagesize := syscall.Getpagesize()
-       b := make([]byte, 4*pagesize)
-       i := pagesize
-       for ; uintptr(unsafe.Pointer(&b[i]))%uintptr(pagesize) != 0; i++ {
-       }
-       syscall.Mprotect(b[i-pagesize:i], 0)
-       syscall.Mprotect(b[i+pagesize:i+2*pagesize], 0)
-       defer syscall.Mprotect(b[i-pagesize:i], syscall.PROT_READ|syscall.PROT_WRITE)
-       defer syscall.Mprotect(b[i+pagesize:i+2*pagesize], syscall.PROT_READ|syscall.PROT_WRITE)
-
-       // both of these should fault
-       //pagesize += int(b[i-1])
-       //pagesize += int(b[i+pagesize])
-
-       for j := 0; j < pagesize; j++ {
-               b[i+j] = 'A'
-       }
-       for j := 0; j <= pagesize; j++ {
-               Equal(b[i:i+j], b[i+pagesize-j:i+pagesize])
-               Equal(b[i+pagesize-j:i+pagesize], b[i:i+j])
-       }
-}