diff options
Diffstat (limited to 'src/runtime/race/race_linux_test.go')
-rw-r--r-- | src/runtime/race/race_linux_test.go | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/src/runtime/race/race_linux_test.go b/src/runtime/race/race_linux_test.go index e8a2d0fd8c..947ed7ca39 100644 --- a/src/runtime/race/race_linux_test.go +++ b/src/runtime/race/race_linux_test.go @@ -35,3 +35,31 @@ func TestAtomicMmap(t *testing.T) { t.Fatalf("bad atomic value: %v, want 2", *a) } } + +func TestAtomicPageBoundary(t *testing.T) { + // Test that atomic access near (but not cross) a page boundary + // doesn't fault. See issue 60825. + + // Mmap two pages of memory, and make the second page inaccessible, + // so we have an address at the end of a page. + pagesize := syscall.Getpagesize() + b, err := syscall.Mmap(0, 0, 2*pagesize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE) + if err != nil { + t.Fatalf("mmap failed %s", err) + } + defer syscall.Munmap(b) + err = syscall.Mprotect(b[pagesize:], syscall.PROT_NONE) + if err != nil { + t.Fatalf("mprotect high failed %s\n", err) + } + + // This should not fault. + a := (*uint32)(unsafe.Pointer(&b[pagesize-4])) + atomic.StoreUint32(a, 1) + if x := atomic.LoadUint32(a); x != 1 { + t.Fatalf("bad atomic value: %v, want 1", x) + } + if x := atomic.AddUint32(a, 1); x != 2 { + t.Fatalf("bad atomic value: %v, want 2", x) + } +} |