gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 }