Skip to content

sync/atomic, runtime/internal/atomic: LoadUint32 SEGFAULTs on ARM when loading from read-only memory #23777

@paulzhol

Description

@paulzhol
package main

import (
	"os"
	"sync/atomic"
	"syscall"
	"testing"
	"unsafe"
)

func TestMmapAtomicLoad(t *testing.T) {
	b, err := syscall.Mmap(-1, 0, os.Getpagesize(), syscall.PROT_EXEC|syscall.PROT_READ, syscall.MAP_ANON|syscall.MAP_PRIVATE)
	if err != nil {
		t.Fatal(err)
	}
	defer syscall.Munmap(b)

	val := atomic.LoadUint32((*uint32)(unsafe.Pointer(&b[0])))
	_ = val
}

GOOS=linux GOARM=7 RPi3:

./atomic_test -test.v
=== RUN   TestMmapAtomicLoad
unexpected fault address 0xb6e7e000
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x2 addr=0xb6e7e000 pc=0xffff0fcc]

goroutine 5 [running]:
runtime.throw(0x11effd, 0x5)
        /usr/local/go1.9/src/runtime/panic.go:605 +0x70 fp=0x10d25f48 sp=0x10d25f3c pc=0x3a8b0
runtime.sigpanic()
        /usr/local/go1.9/src/runtime/signal_unix.go:374 +0x1cc fp=0x10d25f6c sp=0x10d25f48 pc=0x4deb0
sync/atomic.LoadUint32(0xb6e7e000, 0x127b08)
        /usr/local/go1.9/src/sync/atomic/asm_linux_arm.s:172 +0x14 fp=0x10d25f74 sp=0x10d25f70 pc=0x11500
command-line-arguments.TestMmapAtomicLoad(0x10d8a090)
        /tmp/atomic_test.go:18 +0xfc fp=0x10d25fb8 sp=0x10d25f74 pc=0xe5f4c
testing.tRunner(0x10d8a090, 0x127868)
        /usr/local/go1.9/src/testing/testing.go:746 +0xb0 fp=0x10d25fe4 sp=0x10d25fb8 pc=0xb3a58
runtime.goexit()
        /usr/local/go1.9/src/runtime/asm_arm.s:971 +0x4 fp=0x10d25fe4 sp=0x10d25fe4 pc=0x64900
created by testing.(*T).Run
        /usr/local/go1.9/src/testing/testing.go:789 +0x258

goroutine 1 [chan receive]:
testing.(*T).Run(0x10d8a000, 0x12131f, 0x12, 0x127868, 0xb3a04)
        /usr/local/go1.9/src/testing/testing.go:790 +0x270
testing.runTests.func1(0x10d8a000)
        /usr/local/go1.9/src/testing/testing.go:1004 +0x50
testing.tRunner(0x10d8a000, 0x10d33eec)
        /usr/local/go1.9/src/testing/testing.go:746 +0xb0
testing.runTests(0x10d0a050, 0x1aec38, 0x1, 0x1, 0x8)
        /usr/local/go1.9/src/testing/testing.go:1002 +0x26c
testing.(*M).Run(0x10d33f8c, 0x1)
        /usr/local/go1.9/src/testing/testing.go:921 +0xe0
main.main()
        command-line-arguments/_test/_testmain.go:44 +0xa4

GOOS=freebsd GOARM=7 Allwiner A20:

 ./atomic_test -test.v
=== RUN   TestMmapAtomicLoad
unexpected fault address 0x50442000
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x2 addr=0x50442000 pc=0x11494]

goroutine 18 [running]:
runtime.throw(0x11f4fc, 0x5)
	/usr/home/paulzhol/go1.9/src/runtime/panic.go:605 +0x70 fp=0x303bcf4c sp=0x303bcf40 pc=0x3a218
runtime.sigpanic()
	/usr/home/paulzhol/go1.9/src/runtime/signal_unix.go:374 +0x1cc fp=0x303bcf70 sp=0x303bcf4c pc=0x4d794
sync/atomic.LoadUint32(0x50442000, 0x127a78)
	/usr/home/paulzhol/go1.9/src/sync/atomic/asm_freebsd_arm.s:62 +0x8 fp=0x303bcf74 sp=0x303bcf74 pc=0x11494
command-line-arguments.TestMmapAtomicLoad(0x30424090)
	/tmp/atomic_test.go:18 +0xfc fp=0x303bcfb8 sp=0x303bcf74 pc=0xe6490
testing.tRunner(0x30424090, 0x1277d8)
	/usr/home/paulzhol/go1.9/src/testing/testing.go:746 +0xb0 fp=0x303bcfe4 sp=0x303bcfb8 pc=0xb3f9c
runtime.goexit()
	/usr/home/paulzhol/go1.9/src/runtime/asm_arm.s:971 +0x4 fp=0x303bcfe4 sp=0x303bcfe4 pc=0x64244
created by testing.(*T).Run
	/usr/home/paulzhol/go1.9/src/testing/testing.go:789 +0x258

goroutine 1 [chan receive]:
testing.(*T).Run(0x30424000, 0x121633, 0x12, 0x1277d8, 0xb3f48)
	/usr/home/paulzhol/go1.9/src/testing/testing.go:790 +0x270
testing.runTests.func1(0x30424000)
	/usr/home/paulzhol/go1.9/src/testing/testing.go:1004 +0x50
testing.tRunner(0x30424000, 0x303cfeec)
	/usr/home/paulzhol/go1.9/src/testing/testing.go:746 +0xb0
testing.runTests(0x30404020, 0x1aec40, 0x1, 0x1, 0x8)
	/usr/home/paulzhol/go1.9/src/testing/testing.go:1002 +0x26c
testing.(*M).Run(0x303cff8c, 0x1)
	/usr/home/paulzhol/go1.9/src/testing/testing.go:921 +0xe0
main.main()
	command-line-arguments/_test/_testmain.go:44 +0xa4

The cause is the STREX instruction which attempts to write into a protected area used in the implementation of LoadUint32 (implemented with Xadd(&addr,0) ).
The motivation for using atomic.Load on a read-only address is explained here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions