github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/safecopy/safecopy_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package safecopy
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"math/rand"
    22  	"testing"
    23  	"unsafe"
    24  
    25  	"golang.org/x/sys/unix"
    26  )
    27  
    28  // Size of a page in bytes. Cloned from hostarch.PageSize to avoid a circular
    29  // dependency.
    30  const pageSize = 4096
    31  
    32  func initRandom(b []byte) {
    33  	for i := range b {
    34  		b[i] = byte(rand.Intn(256))
    35  	}
    36  }
    37  
    38  func randBuf(size int) []byte {
    39  	b := make([]byte, size)
    40  	initRandom(b)
    41  	return b
    42  }
    43  
    44  func TestCopyInSuccess(t *testing.T) {
    45  	// Test that CopyIn does not return an error when all pages are accessible.
    46  	const bufLen = 8192
    47  	a := randBuf(bufLen)
    48  	b := make([]byte, bufLen)
    49  
    50  	n, err := CopyIn(b, unsafe.Pointer(&a[0]))
    51  	if n != bufLen {
    52  		t.Errorf("Unexpected copy length, got %v, want %v", n, bufLen)
    53  	}
    54  	if err != nil {
    55  		t.Errorf("Unexpected error: %v", err)
    56  	}
    57  	if !bytes.Equal(a, b) {
    58  		t.Errorf("Buffers are not equal when they should be: %v %v", a, b)
    59  	}
    60  }
    61  
    62  func TestCopyOutSuccess(t *testing.T) {
    63  	// Test that CopyOut does not return an error when all pages are
    64  	// accessible.
    65  	const bufLen = 8192
    66  	a := randBuf(bufLen)
    67  	b := make([]byte, bufLen)
    68  
    69  	n, err := CopyOut(unsafe.Pointer(&b[0]), a)
    70  	if n != bufLen {
    71  		t.Errorf("Unexpected copy length, got %v, want %v", n, bufLen)
    72  	}
    73  	if err != nil {
    74  		t.Errorf("Unexpected error: %v", err)
    75  	}
    76  	if !bytes.Equal(a, b) {
    77  		t.Errorf("Buffers are not equal when they should be: %v %v", a, b)
    78  	}
    79  }
    80  
    81  func TestCopySuccess(t *testing.T) {
    82  	// Test that Copy does not return an error when all pages are accessible.
    83  	const bufLen = 8192
    84  	a := randBuf(bufLen)
    85  	b := make([]byte, bufLen)
    86  
    87  	n, err := Copy(unsafe.Pointer(&b[0]), unsafe.Pointer(&a[0]), bufLen)
    88  	if n != bufLen {
    89  		t.Errorf("Unexpected copy length, got %v, want %v", n, bufLen)
    90  	}
    91  	if err != nil {
    92  		t.Errorf("Unexpected error: %v", err)
    93  	}
    94  	if !bytes.Equal(a, b) {
    95  		t.Errorf("Buffers are not equal when they should be: %v %v", a, b)
    96  	}
    97  }
    98  
    99  func TestZeroOutSuccess(t *testing.T) {
   100  	// Test that ZeroOut does not return an error when all pages are
   101  	// accessible.
   102  	const bufLen = 8192
   103  	a := make([]byte, bufLen)
   104  	b := randBuf(bufLen)
   105  
   106  	n, err := ZeroOut(unsafe.Pointer(&b[0]), bufLen)
   107  	if n != bufLen {
   108  		t.Errorf("Unexpected copy length, got %v, want %v", n, bufLen)
   109  	}
   110  	if err != nil {
   111  		t.Errorf("Unexpected error: %v", err)
   112  	}
   113  	if !bytes.Equal(a, b) {
   114  		t.Errorf("Buffers are not equal when they should be: %v %v", a, b)
   115  	}
   116  }
   117  
   118  func TestSwapUint32Success(t *testing.T) {
   119  	// Test that SwapUint32 does not return an error when the page is
   120  	// accessible.
   121  	before := uint32(rand.Int31())
   122  	after := uint32(rand.Int31())
   123  	val := before
   124  
   125  	old, err := SwapUint32(unsafe.Pointer(&val), after)
   126  	if err != nil {
   127  		t.Errorf("Unexpected error: %v", err)
   128  	}
   129  	if old != before {
   130  		t.Errorf("Unexpected old value: got %v, want %v", old, before)
   131  	}
   132  	if val != after {
   133  		t.Errorf("Unexpected new value: got %v, want %v", val, after)
   134  	}
   135  }
   136  
   137  func TestSwapUint32AlignmentError(t *testing.T) {
   138  	// Test that SwapUint32 returns an AlignmentError when passed an unaligned
   139  	// address.
   140  	data := make([]byte, 8) // 2 * sizeof(uint32).
   141  	alignedIndex := uintptr(0)
   142  	if offset := uintptr(unsafe.Pointer(&data[0])) % 4; offset != 0 {
   143  		alignedIndex = 4 - offset
   144  	}
   145  	ptr := unsafe.Pointer(&data[alignedIndex+1])
   146  	want := AlignmentError{Addr: uintptr(ptr), Alignment: 4}
   147  	if _, err := SwapUint32(ptr, 1); err != want {
   148  		t.Errorf("Unexpected error: got %v, want %v", err, want)
   149  	}
   150  }
   151  
   152  func TestSwapUint64Success(t *testing.T) {
   153  	// Test that SwapUint64 does not return an error when the page is
   154  	// accessible.
   155  	before := uint64(rand.Int63())
   156  	after := uint64(rand.Int63())
   157  	// "The first word in ... an allocated struct or slice can be relied upon
   158  	// to be 64-bit aligned." - sync/atomic docs
   159  	data := new(struct{ val uint64 })
   160  	data.val = before
   161  
   162  	old, err := SwapUint64(unsafe.Pointer(&data.val), after)
   163  	if err != nil {
   164  		t.Errorf("Unexpected error: %v", err)
   165  	}
   166  	if old != before {
   167  		t.Errorf("Unexpected old value: got %v, want %v", old, before)
   168  	}
   169  	if data.val != after {
   170  		t.Errorf("Unexpected new value: got %v, want %v", data.val, after)
   171  	}
   172  }
   173  
   174  func TestSwapUint64AlignmentError(t *testing.T) {
   175  	// Test that SwapUint64 returns an AlignmentError when passed an unaligned
   176  	// address.
   177  	data := make([]byte, 16) // 2 * sizeof(uint64).
   178  	alignedIndex := uintptr(0)
   179  	if offset := uintptr(unsafe.Pointer(&data[0])) % 8; offset != 0 {
   180  		alignedIndex = 8 - offset
   181  	}
   182  	ptr := unsafe.Pointer(&data[alignedIndex+1])
   183  	want := AlignmentError{Addr: uintptr(ptr), Alignment: 8}
   184  	if _, err := SwapUint64(ptr, 1); err != want {
   185  		t.Errorf("Unexpected error: got %v, want %v", err, want)
   186  	}
   187  }
   188  
   189  func TestCompareAndSwapUint32Success(t *testing.T) {
   190  	// Test that CompareAndSwapUint32 does not return an error when the page is
   191  	// accessible.
   192  	before := uint32(rand.Int31())
   193  	after := uint32(rand.Int31())
   194  	val := before
   195  
   196  	old, err := CompareAndSwapUint32(unsafe.Pointer(&val), before, after)
   197  	if err != nil {
   198  		t.Errorf("Unexpected error: %v", err)
   199  	}
   200  	if old != before {
   201  		t.Errorf("Unexpected old value: got %v, want %v", old, before)
   202  	}
   203  	if val != after {
   204  		t.Errorf("Unexpected new value: got %v, want %v", val, after)
   205  	}
   206  }
   207  
   208  func TestCompareAndSwapUint32AlignmentError(t *testing.T) {
   209  	// Test that CompareAndSwapUint32 returns an AlignmentError when passed an
   210  	// unaligned address.
   211  	data := make([]byte, 8) // 2 * sizeof(uint32).
   212  	alignedIndex := uintptr(0)
   213  	if offset := uintptr(unsafe.Pointer(&data[0])) % 4; offset != 0 {
   214  		alignedIndex = 4 - offset
   215  	}
   216  	ptr := unsafe.Pointer(&data[alignedIndex+1])
   217  	want := AlignmentError{Addr: uintptr(ptr), Alignment: 4}
   218  	if _, err := CompareAndSwapUint32(ptr, 0, 1); err != want {
   219  		t.Errorf("Unexpected error: got %v, want %v", err, want)
   220  	}
   221  }
   222  
   223  // withSegvErrorTestMapping calls fn with a two-page mapping. The first page
   224  // contains random data, and the second page generates SIGSEGV when accessed.
   225  func withSegvErrorTestMapping(t *testing.T, fn func(m []byte)) {
   226  	mapping, err := unix.Mmap(-1, 0, 2*pageSize, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_ANONYMOUS|unix.MAP_PRIVATE)
   227  	if err != nil {
   228  		t.Fatalf("Mmap failed: %v", err)
   229  	}
   230  	defer unix.Munmap(mapping)
   231  	if err := unix.Mprotect(mapping[pageSize:], unix.PROT_NONE); err != nil {
   232  		t.Fatalf("Mprotect failed: %v", err)
   233  	}
   234  	initRandom(mapping[:pageSize])
   235  
   236  	fn(mapping)
   237  }
   238  
   239  // withBusErrorTestMapping calls fn with a two-page mapping. The first page
   240  // contains random data, and the second page generates SIGBUS when accessed.
   241  func withBusErrorTestMapping(t *testing.T, fn func(m []byte)) {
   242  	f, err := ioutil.TempFile("", "sigbus_test")
   243  	if err != nil {
   244  		t.Fatalf("TempFile failed: %v", err)
   245  	}
   246  	defer f.Close()
   247  	if err := f.Truncate(pageSize); err != nil {
   248  		t.Fatalf("Truncate failed: %v", err)
   249  	}
   250  	mapping, err := unix.Mmap(int(f.Fd()), 0, 2*pageSize, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
   251  	if err != nil {
   252  		t.Fatalf("Mmap failed: %v", err)
   253  	}
   254  	defer unix.Munmap(mapping)
   255  	initRandom(mapping[:pageSize])
   256  
   257  	fn(mapping)
   258  }
   259  
   260  func TestCopyInSegvError(t *testing.T) {
   261  	// Test that CopyIn returns a SegvError when reaching a page that signals
   262  	// SIGSEGV.
   263  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   264  		t.Run(fmt.Sprintf("starting copy %d bytes before SIGSEGV", bytesBeforeFault), func(t *testing.T) {
   265  			withSegvErrorTestMapping(t, func(mapping []byte) {
   266  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   267  				src := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   268  				dst := randBuf(pageSize)
   269  				n, err := CopyIn(dst, src)
   270  				if n != bytesBeforeFault {
   271  					t.Errorf("Unexpected copy length: got %v, want %v", n, bytesBeforeFault)
   272  				}
   273  				if want := (SegvError{secondPage}); err != want {
   274  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   275  				}
   276  				if got, want := dst[:bytesBeforeFault], mapping[pageSize-bytesBeforeFault:pageSize]; !bytes.Equal(got, want) {
   277  					t.Errorf("Buffers are not equal when they should be: %v %v", got, want)
   278  				}
   279  			})
   280  		})
   281  	}
   282  }
   283  
   284  func TestCopyInBusError(t *testing.T) {
   285  	// Test that CopyIn returns a BusError when reaching a page that signals
   286  	// SIGBUS.
   287  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   288  		t.Run(fmt.Sprintf("starting copy %d bytes before SIGBUS", bytesBeforeFault), func(t *testing.T) {
   289  			withBusErrorTestMapping(t, func(mapping []byte) {
   290  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   291  				src := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   292  				dst := randBuf(pageSize)
   293  				n, err := CopyIn(dst, src)
   294  				if n != bytesBeforeFault {
   295  					t.Errorf("Unexpected copy length: got %v, want %v", n, bytesBeforeFault)
   296  				}
   297  				if want := (BusError{secondPage}); err != want {
   298  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   299  				}
   300  				if got, want := dst[:bytesBeforeFault], mapping[pageSize-bytesBeforeFault:pageSize]; !bytes.Equal(got, want) {
   301  					t.Errorf("Buffers are not equal when they should be: %v %v", got, want)
   302  				}
   303  			})
   304  		})
   305  	}
   306  }
   307  
   308  func TestCopyOutSegvError(t *testing.T) {
   309  	// Test that CopyOut returns a SegvError when reaching a page that signals
   310  	// SIGSEGV.
   311  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   312  		t.Run(fmt.Sprintf("starting copy %d bytes before SIGSEGV", bytesBeforeFault), func(t *testing.T) {
   313  			withSegvErrorTestMapping(t, func(mapping []byte) {
   314  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   315  				dst := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   316  				src := randBuf(pageSize)
   317  				n, err := CopyOut(dst, src)
   318  				if n != bytesBeforeFault {
   319  					t.Errorf("Unexpected copy length: got %v, want %v", n, bytesBeforeFault)
   320  				}
   321  				if want := (SegvError{secondPage}); err != want {
   322  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   323  				}
   324  				if got, want := mapping[pageSize-bytesBeforeFault:pageSize], src[:bytesBeforeFault]; !bytes.Equal(got, want) {
   325  					t.Errorf("Buffers are not equal when they should be: %v %v", got, want)
   326  				}
   327  			})
   328  		})
   329  	}
   330  }
   331  
   332  func TestCopyOutBusError(t *testing.T) {
   333  	// Test that CopyOut returns a BusError when reaching a page that signals
   334  	// SIGBUS.
   335  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   336  		t.Run(fmt.Sprintf("starting copy %d bytes before SIGSEGV", bytesBeforeFault), func(t *testing.T) {
   337  			withBusErrorTestMapping(t, func(mapping []byte) {
   338  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   339  				dst := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   340  				src := randBuf(pageSize)
   341  				n, err := CopyOut(dst, src)
   342  				if n != bytesBeforeFault {
   343  					t.Errorf("Unexpected copy length: got %v, want %v", n, bytesBeforeFault)
   344  				}
   345  				if want := (BusError{secondPage}); err != want {
   346  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   347  				}
   348  				if got, want := mapping[pageSize-bytesBeforeFault:pageSize], src[:bytesBeforeFault]; !bytes.Equal(got, want) {
   349  					t.Errorf("Buffers are not equal when they should be: %v %v", got, want)
   350  				}
   351  			})
   352  		})
   353  	}
   354  }
   355  
   356  func TestCopySourceSegvError(t *testing.T) {
   357  	// Test that Copy returns a SegvError when copying from a page that signals
   358  	// SIGSEGV.
   359  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   360  		t.Run(fmt.Sprintf("starting copy %d bytes before SIGSEGV", bytesBeforeFault), func(t *testing.T) {
   361  			withSegvErrorTestMapping(t, func(mapping []byte) {
   362  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   363  				src := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   364  				dst := randBuf(pageSize)
   365  				n, err := Copy(unsafe.Pointer(&dst[0]), src, pageSize)
   366  				if n != uintptr(bytesBeforeFault) {
   367  					t.Errorf("Unexpected copy length: got %v, want %v", n, bytesBeforeFault)
   368  				}
   369  				if want := (SegvError{secondPage}); err != want {
   370  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   371  				}
   372  				if got, want := dst[:bytesBeforeFault], mapping[pageSize-bytesBeforeFault:pageSize]; !bytes.Equal(got, want) {
   373  					t.Errorf("Buffers are not equal when they should be: %v %v", got, want)
   374  				}
   375  			})
   376  		})
   377  	}
   378  }
   379  
   380  func TestCopySourceBusError(t *testing.T) {
   381  	// Test that Copy returns a BusError when copying from a page that signals
   382  	// SIGBUS.
   383  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   384  		t.Run(fmt.Sprintf("starting copy %d bytes before SIGBUS", bytesBeforeFault), func(t *testing.T) {
   385  			withBusErrorTestMapping(t, func(mapping []byte) {
   386  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   387  				src := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   388  				dst := randBuf(pageSize)
   389  				n, err := Copy(unsafe.Pointer(&dst[0]), src, pageSize)
   390  				if n != uintptr(bytesBeforeFault) {
   391  					t.Errorf("Unexpected copy length: got %v, want %v", n, bytesBeforeFault)
   392  				}
   393  				if want := (BusError{secondPage}); err != want {
   394  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   395  				}
   396  				if got, want := dst[:bytesBeforeFault], mapping[pageSize-bytesBeforeFault:pageSize]; !bytes.Equal(got, want) {
   397  					t.Errorf("Buffers are not equal when they should be: %v %v", got, want)
   398  				}
   399  			})
   400  		})
   401  	}
   402  }
   403  
   404  func TestCopyDestinationSegvError(t *testing.T) {
   405  	// Test that Copy returns a SegvError when copying to a page that signals
   406  	// SIGSEGV.
   407  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   408  		t.Run(fmt.Sprintf("starting copy %d bytes before SIGSEGV", bytesBeforeFault), func(t *testing.T) {
   409  			withSegvErrorTestMapping(t, func(mapping []byte) {
   410  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   411  				dst := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   412  				src := randBuf(pageSize)
   413  				n, err := Copy(dst, unsafe.Pointer(&src[0]), pageSize)
   414  				if n != uintptr(bytesBeforeFault) {
   415  					t.Errorf("Unexpected copy length: got %v, want %v", n, bytesBeforeFault)
   416  				}
   417  				if want := (SegvError{secondPage}); err != want {
   418  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   419  				}
   420  				if got, want := mapping[pageSize-bytesBeforeFault:pageSize], src[:bytesBeforeFault]; !bytes.Equal(got, want) {
   421  					t.Errorf("Buffers are not equal when they should be: %v %v", got, want)
   422  				}
   423  			})
   424  		})
   425  	}
   426  }
   427  
   428  func TestCopyDestinationBusError(t *testing.T) {
   429  	// Test that Copy returns a BusError when copying to a page that signals
   430  	// SIGBUS.
   431  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   432  		t.Run(fmt.Sprintf("starting copy %d bytes before SIGBUS", bytesBeforeFault), func(t *testing.T) {
   433  			withBusErrorTestMapping(t, func(mapping []byte) {
   434  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   435  				dst := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   436  				src := randBuf(pageSize)
   437  				n, err := Copy(dst, unsafe.Pointer(&src[0]), pageSize)
   438  				if n != uintptr(bytesBeforeFault) {
   439  					t.Errorf("Unexpected copy length: got %v, want %v", n, bytesBeforeFault)
   440  				}
   441  				if want := (BusError{secondPage}); err != want {
   442  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   443  				}
   444  				if got, want := mapping[pageSize-bytesBeforeFault:pageSize], src[:bytesBeforeFault]; !bytes.Equal(got, want) {
   445  					t.Errorf("Buffers are not equal when they should be: %v %v", got, want)
   446  				}
   447  			})
   448  		})
   449  	}
   450  }
   451  
   452  func TestZeroOutSegvError(t *testing.T) {
   453  	// Test that ZeroOut returns a SegvError when reaching a page that signals
   454  	// SIGSEGV.
   455  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   456  		t.Run(fmt.Sprintf("starting write %d bytes before SIGSEGV", bytesBeforeFault), func(t *testing.T) {
   457  			withSegvErrorTestMapping(t, func(mapping []byte) {
   458  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   459  				dst := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   460  				n, err := ZeroOut(dst, pageSize)
   461  				if n != uintptr(bytesBeforeFault) {
   462  					t.Errorf("Unexpected write length: got %v, want %v", n, bytesBeforeFault)
   463  				}
   464  				if want := (SegvError{secondPage}); err != want {
   465  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   466  				}
   467  				if got, want := mapping[pageSize-bytesBeforeFault:pageSize], make([]byte, bytesBeforeFault); !bytes.Equal(got, want) {
   468  					t.Errorf("Non-zero bytes in written part of mapping: %v", got)
   469  				}
   470  			})
   471  		})
   472  	}
   473  }
   474  
   475  func TestZeroOutBusError(t *testing.T) {
   476  	// Test that ZeroOut returns a BusError when reaching a page that signals
   477  	// SIGBUS.
   478  	for bytesBeforeFault := 0; bytesBeforeFault <= 2*maxRegisterSize; bytesBeforeFault++ {
   479  		t.Run(fmt.Sprintf("starting write %d bytes before SIGBUS", bytesBeforeFault), func(t *testing.T) {
   480  			withBusErrorTestMapping(t, func(mapping []byte) {
   481  				secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   482  				dst := unsafe.Pointer(&mapping[pageSize-bytesBeforeFault])
   483  				n, err := ZeroOut(dst, pageSize)
   484  				if n != uintptr(bytesBeforeFault) {
   485  					t.Errorf("Unexpected write length: got %v, want %v", n, bytesBeforeFault)
   486  				}
   487  				if want := (BusError{secondPage}); err != want {
   488  					t.Errorf("Unexpected error: got %v, want %v", err, want)
   489  				}
   490  				if got, want := mapping[pageSize-bytesBeforeFault:pageSize], make([]byte, bytesBeforeFault); !bytes.Equal(got, want) {
   491  					t.Errorf("Non-zero bytes in written part of mapping: %v", got)
   492  				}
   493  			})
   494  		})
   495  	}
   496  }
   497  
   498  func TestSwapUint32SegvError(t *testing.T) {
   499  	// Test that SwapUint32 returns a SegvError when reaching a page that
   500  	// signals SIGSEGV.
   501  	withSegvErrorTestMapping(t, func(mapping []byte) {
   502  		secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   503  		_, err := SwapUint32(unsafe.Pointer(secondPage), 1)
   504  		if want := (SegvError{secondPage}); err != want {
   505  			t.Errorf("Unexpected error: got %v, want %v", err, want)
   506  		}
   507  	})
   508  }
   509  
   510  func TestSwapUint32BusError(t *testing.T) {
   511  	// Test that SwapUint32 returns a BusError when reaching a page that
   512  	// signals SIGBUS.
   513  	withBusErrorTestMapping(t, func(mapping []byte) {
   514  		secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   515  		_, err := SwapUint32(unsafe.Pointer(secondPage), 1)
   516  		if want := (BusError{secondPage}); err != want {
   517  			t.Errorf("Unexpected error: got %v, want %v", err, want)
   518  		}
   519  	})
   520  }
   521  
   522  func TestSwapUint64SegvError(t *testing.T) {
   523  	// Test that SwapUint64 returns a SegvError when reaching a page that
   524  	// signals SIGSEGV.
   525  	withSegvErrorTestMapping(t, func(mapping []byte) {
   526  		secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   527  		_, err := SwapUint64(unsafe.Pointer(secondPage), 1)
   528  		if want := (SegvError{secondPage}); err != want {
   529  			t.Errorf("Unexpected error: got %v, want %v", err, want)
   530  		}
   531  	})
   532  }
   533  
   534  func TestSwapUint64BusError(t *testing.T) {
   535  	// Test that SwapUint64 returns a BusError when reaching a page that
   536  	// signals SIGBUS.
   537  	withBusErrorTestMapping(t, func(mapping []byte) {
   538  		secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   539  		_, err := SwapUint64(unsafe.Pointer(secondPage), 1)
   540  		if want := (BusError{secondPage}); err != want {
   541  			t.Errorf("Unexpected error: got %v, want %v", err, want)
   542  		}
   543  	})
   544  }
   545  
   546  func TestCompareAndSwapUint32SegvError(t *testing.T) {
   547  	// Test that CompareAndSwapUint32 returns a SegvError when reaching a page
   548  	// that signals SIGSEGV.
   549  	withSegvErrorTestMapping(t, func(mapping []byte) {
   550  		secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   551  		_, err := CompareAndSwapUint32(unsafe.Pointer(secondPage), 0, 1)
   552  		if want := (SegvError{secondPage}); err != want {
   553  			t.Errorf("Unexpected error: got %v, want %v", err, want)
   554  		}
   555  	})
   556  }
   557  
   558  func TestCompareAndSwapUint32BusError(t *testing.T) {
   559  	// Test that CompareAndSwapUint32 returns a BusError when reaching a page
   560  	// that signals SIGBUS.
   561  	withBusErrorTestMapping(t, func(mapping []byte) {
   562  		secondPage := uintptr(unsafe.Pointer(&mapping[pageSize]))
   563  		_, err := CompareAndSwapUint32(unsafe.Pointer(secondPage), 0, 1)
   564  		if want := (BusError{secondPage}); err != want {
   565  			t.Errorf("Unexpected error: got %v, want %v", err, want)
   566  		}
   567  	})
   568  }