]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add go:nosplit to cgo_mmap.go:mmap() and sys_darwin.go:mmap()
authorDan Scales <danscales@google.com>
Tue, 19 Nov 2019 20:41:51 +0000 (12:41 -0800)
committerDan Scales <danscales@google.com>
Mon, 25 Nov 2019 03:41:16 +0000 (03:41 +0000)
cgo_mmap.go:mmap() is called by mem_linux.go:sysAlloc(), a low-level memory
allocation function. mmap() should be nosplit, since it is called in a lot of
low-level parts of the runtime and callers often assume it won't acquire any
locks.

As an example there is a potential deadlock involving two threads if mmap is not nosplit:

trace.bufLock acquired, then stackpool[order].item.mu, then mheap_.lock
  - can happen for traceEvents that are not invoked on the system stack and cause
    a traceFlush, which causes a sysAlloc, which calls mmap(), which may cause a
    stack split. mheap_.lock
mheap_.lock acquired, then trace.bufLock
  - can happen when doing a trace in reclaimChunk (which holds the mheap_ lock)

Also, sysAlloc() has a comment that it is nosplit because it may be invoked
without a valid G, in which case its callee mmap() should also be nosplit.

Similarly, sys_darwin.go:mmap() is called by mem_darwin.go:sysAlloc(), and should
be nosplit for the same reasons.

Extra gomote testing:  linux/arm64, darwin/amd64

Change-Id: Ia4d10cec5cf1e186a0fe5aab2858c6e0e5b80fdc
Reviewed-on: https://go-review.googlesource.com/c/go/+/207844
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/runtime/cgo_mmap.go
src/runtime/sys_darwin.go

index 048621f3065f3c0dd08cdedc50f509460d79f140..d5e0cc1e3ee3da3bde36cbe612fc74a628c612e3 100644 (file)
@@ -20,6 +20,11 @@ var _cgo_mmap unsafe.Pointer
 //go:linkname _cgo_munmap _cgo_munmap
 var _cgo_munmap unsafe.Pointer
 
+// mmap is used to route the mmap system call through C code when using cgo, to
+// support sanitizer interceptors. Don't allow stack splits, since this function
+// (used by sysAlloc) is called in a lot of low-level parts of the runtime and
+// callers often assume it won't acquire any locks.
+//go:nosplit
 func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (unsafe.Pointer, int) {
        if _cgo_mmap != nil {
                // Make ret a uintptr so that writing to it in the
index 31304ce737ece3beafd9d9dcdbfb1d9ae7eb1663..d2d1822aaba58184fe977121beabdb0adf75aab1 100644 (file)
@@ -170,6 +170,10 @@ func pthread_kill(t pthread, sig uint32) {
 }
 func pthread_kill_trampoline()
 
+// mmap is used to do low-level memory allocation via mmap. Don't allow stack
+// splits, since this function (used by sysAlloc) is called in a lot of low-level
+// parts of the runtime and callers often assume it won't acquire any locks.
+// go:nosplit
 func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (unsafe.Pointer, int) {
        args := struct {
                addr            unsafe.Pointer