]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.5] runtime: fix bad signal stack when using cgo-created threads...
authorRuss Cox <rsc@golang.org>
Fri, 13 Nov 2015 21:21:01 +0000 (16:21 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 23 Nov 2015 02:01:28 +0000 (02:01 +0000)
Cgo-created threads transition between having associated Go g's and m's and not.
A signal arriving during the transition could think it was safe and appropriate to
run Go signal handlers when it was in fact not.
Avoid the race by masking all signals during the transition.

Fixes #12277.

Change-Id: Ie9711bc1d098391d58362492197a7e0f5b497d14
Reviewed-on: https://go-review.googlesource.com/16915
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/17141

src/runtime/os1_darwin.go
src/runtime/os1_dragonfly.go
src/runtime/os1_freebsd.go
src/runtime/os1_linux.go
src/runtime/os1_nacl.go
src/runtime/os1_netbsd.go
src/runtime/os1_openbsd.go
src/runtime/os1_plan9.go
src/runtime/os1_windows.go
src/runtime/os3_solaris.go
src/runtime/proc1.go

index e07022997c81b56b79e150a154e8b81325afb75b..c9dba152abe12eb0d0b1886e54efd3a8242d73f9 100644 (file)
@@ -130,6 +130,7 @@ func mpreinit(mp *m) {
        mp.gsignal.m = mp
 }
 
+//go:nosplit
 func msigsave(mp *m) {
        smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
        if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
@@ -138,6 +139,17 @@ func msigsave(mp *m) {
        sigprocmask(_SIG_SETMASK, nil, smask)
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+       smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
+       sigprocmask(_SIG_SETMASK, smask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+       sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -156,10 +168,8 @@ func minit() {
 }
 
 // Called from dropm to undo the effect of an minit.
+//go:nosplit
 func unminit() {
-       _g_ := getg()
-       smask := (*uint32)(unsafe.Pointer(&_g_.m.sigmask))
-       sigprocmask(_SIG_SETMASK, smask, nil)
        signalstack(nil)
 }
 
@@ -459,6 +469,7 @@ func getsig(i int32) uintptr {
        return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
 }
 
+//go:nosplit
 func signalstack(s *stack) {
        var st stackt
        if s == nil {
index f96c78ca80a52370916d0e9ef15b63ffc9bd9d59..da70014e556d0208cab9c237a58bb4f5e0a0a032 100644 (file)
@@ -119,6 +119,7 @@ func mpreinit(mp *m) {
        mp.gsignal.m = mp
 }
 
+//go:nosplit
 func msigsave(mp *m) {
        smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
        if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
@@ -127,6 +128,17 @@ func msigsave(mp *m) {
        sigprocmask(_SIG_SETMASK, nil, smask)
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+       smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+       sigprocmask(_SIG_SETMASK, smask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+       sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -150,9 +162,6 @@ func minit() {
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
-       _g_ := getg()
-       smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
-       sigprocmask(_SIG_SETMASK, smask, nil)
        signalstack(nil)
 }
 
@@ -222,6 +231,7 @@ func getsig(i int32) uintptr {
        return sa.sa_sigaction
 }
 
+//go:nosplit
 func signalstack(s *stack) {
        var st sigaltstackt
        if s == nil {
index f3519f3490fdd786449be57cc787a69eae2a0b28..b18e60f9b6f8cb050ee8be6747c2e93759dbc8fb 100644 (file)
@@ -118,6 +118,7 @@ func mpreinit(mp *m) {
        mp.gsignal.m = mp
 }
 
+//go:nosplit
 func msigsave(mp *m) {
        smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
        if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
@@ -126,6 +127,17 @@ func msigsave(mp *m) {
        sigprocmask(_SIG_SETMASK, nil, smask)
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+       smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+       sigprocmask(_SIG_SETMASK, smask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+       sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -151,10 +163,8 @@ func minit() {
 }
 
 // Called from dropm to undo the effect of an minit.
+//go:nosplit
 func unminit() {
-       _g_ := getg()
-       smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
-       sigprocmask(_SIG_SETMASK, smask, nil)
        signalstack(nil)
 }
 
@@ -224,6 +234,7 @@ func getsig(i int32) uintptr {
        return sa.sa_handler
 }
 
+//go:nosplit
 func signalstack(s *stack) {
        var st stackt
        if s == nil {
index 1cad8f776aea2820262f70edf6a0003384532b99..166014b502e195b3e86e8041ee030453adb5fcff 100644 (file)
@@ -198,6 +198,7 @@ func mpreinit(mp *m) {
        mp.gsignal.m = mp
 }
 
+//go:nosplit
 func msigsave(mp *m) {
        smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
        if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
@@ -206,6 +207,17 @@ func msigsave(mp *m) {
        rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+       smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+       rtsigprocmask(_SIG_SETMASK, smask, nil, int32(unsafe.Sizeof(*smask)))
+}
+
+//go:nosplit
+func sigblock() {
+       rtsigprocmask(_SIG_SETMASK, &sigset_all, nil, int32(unsafe.Sizeof(sigset_all)))
+}
+
 func gettid() uint32
 
 // Called to initialize a new m (including the bootstrap m).
@@ -229,10 +241,8 @@ func minit() {
 }
 
 // Called from dropm to undo the effect of an minit.
+//go:nosplit
 func unminit() {
-       _g_ := getg()
-       smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
-       rtsigprocmask(_SIG_SETMASK, smask, nil, int32(unsafe.Sizeof(*smask)))
        signalstack(nil)
 }
 
@@ -326,6 +336,7 @@ func getsig(i int32) uintptr {
        return sa.sa_handler
 }
 
+//go:nosplit
 func signalstack(s *stack) {
        var st sigaltstackt
        if s == nil {
index 143752ada808b10fab40ddd91bd748d81d749057..30c352968a6b40de1f3fd52e321894161bfb62e2 100644 (file)
@@ -15,9 +15,18 @@ func mpreinit(mp *m) {
 
 func sigtramp()
 
+//go:nosplit
 func msigsave(mp *m) {
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+}
+
+//go:nosplit
+func sigblock() {
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
index cacd60620b06a6f0bb320f7acb53570c7c0d7d2a..f4c5ca48eb8476fb1810f50f196e03703bf4ad3a 100644 (file)
@@ -138,6 +138,7 @@ func mpreinit(mp *m) {
        mp.gsignal.m = mp
 }
 
+//go:nosplit
 func msigsave(mp *m) {
        smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
        if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
@@ -146,6 +147,17 @@ func msigsave(mp *m) {
        sigprocmask(_SIG_SETMASK, nil, smask)
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+       smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+       sigprocmask(_SIG_SETMASK, smask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+       sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -166,11 +178,8 @@ func minit() {
 }
 
 // Called from dropm to undo the effect of an minit.
+//go:nosplit
 func unminit() {
-       _g_ := getg()
-       smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
-       sigprocmask(_SIG_SETMASK, smask, nil)
-
        signalstack(nil)
 }
 
@@ -213,6 +222,7 @@ func getsig(i int32) uintptr {
        return sa.sa_sigaction
 }
 
+//go:nosplit
 func signalstack(s *stack) {
        var st sigaltstackt
        if s == nil {
index 24a095b9d682e80d1120c113a012cde45702d7dd..88f6aef3e231f57b27ae30d4a3ec93c83d0fb542 100644 (file)
@@ -148,6 +148,7 @@ func mpreinit(mp *m) {
        mp.gsignal.m = mp
 }
 
+//go:nosplit
 func msigsave(mp *m) {
        smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
        if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
@@ -156,6 +157,17 @@ func msigsave(mp *m) {
        *smask = sigprocmask(_SIG_BLOCK, 0)
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+       smask := *(*uint32)(unsafe.Pointer(&mp.sigmask))
+       sigprocmask(_SIG_SETMASK, smask)
+}
+
+//go:nosplit
+func sigblock() {
+       sigprocmask(_SIG_SETMASK, sigset_all)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -178,10 +190,8 @@ func minit() {
 }
 
 // Called from dropm to undo the effect of an minit.
+//go:nosplit
 func unminit() {
-       _g_ := getg()
-       smask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
-       sigprocmask(_SIG_SETMASK, smask)
        signalstack(nil)
 }
 
@@ -224,6 +234,7 @@ func getsig(i int32) uintptr {
        return sa.sa_sigaction
 }
 
+//go:nosplit
 func signalstack(s *stack) {
        var st stackt
        if s == nil {
index 9615b6d1a40dadf938cd8f2a4ab9046d614532f6..38125a01f86be987a5e9f71158f24991a815f715 100644 (file)
@@ -21,6 +21,12 @@ func mpreinit(mp *m) {
 func msigsave(mp *m) {
 }
 
+func msigrestore(mp *m) {
+}
+
+func sigblock() {
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
index f608b4ad80c00183f6a5f09bab04f28b18f935f6..d0120347db8f5644dca61746edd403d1c75532d8 100644 (file)
@@ -284,9 +284,18 @@ func newosproc(mp *m, stk unsafe.Pointer) {
 func mpreinit(mp *m) {
 }
 
+//go:nosplit
 func msigsave(mp *m) {
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+}
+
+//go:nosplit
+func sigblock() {
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -296,6 +305,7 @@ func minit() {
 }
 
 // Called from dropm to undo the effect of an minit.
+//go:nosplit
 func unminit() {
        tp := &getg().m.thread
        stdcall1(_CloseHandle, *tp)
index 792188fea639515b08b343e629d81ffaecbebdd7..b27a675159157507a06116122b94f103017dfdf1 100644 (file)
@@ -192,6 +192,7 @@ func mpreinit(mp *m) {
 
 func miniterrno()
 
+//go:nosplit
 func msigsave(mp *m) {
        smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
        if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
@@ -200,6 +201,17 @@ func msigsave(mp *m) {
        sigprocmask(_SIG_SETMASK, nil, smask)
 }
 
+//go:nosplit
+func msigrestore(mp *m) {
+       smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+       sigprocmask(_SIG_SETMASK, smask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+       sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -220,10 +232,6 @@ func minit() {
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
-       _g_ := getg()
-       smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
-       sigprocmask(_SIG_SETMASK, smask, nil)
-
        signalstack(nil)
 }
 
@@ -289,6 +297,7 @@ func getsig(i int32) uintptr {
        return *((*uintptr)(unsafe.Pointer(&sa._funcptr)))
 }
 
+//go:nosplit
 func signalstack(s *stack) {
        var st sigaltstackt
        if s == nil {
@@ -493,6 +502,7 @@ func sigaltstack(ss *sigaltstackt, oss *sigaltstackt) /* int32 */ {
        sysvicall2(&libc_sigaltstack, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(oss)))
 }
 
+//go:nosplit
 func sigprocmask(how int32, set *sigset, oset *sigset) /* int32 */ {
        sysvicall3(&libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
 }
index 54cb3eb77f847bf05720c036f9a9667c90a96b10..72ab524bd2141ddf4a73df53c5afc5a5e9049277 100644 (file)
@@ -945,6 +945,15 @@ func needm(x byte) {
        mp.needextram = mp.schedlink == 0
        unlockextra(mp.schedlink.ptr())
 
+       // Save and block signals before installing g.
+       // Once g is installed, any incoming signals will try to execute,
+       // but we won't have the sigaltstack settings and other data
+       // set up appropriately until the end of minit, which will
+       // unblock the signals. This is the same dance as when
+       // starting a new m to run Go code via newosproc.
+       msigsave(mp)
+       sigblock()
+
        // Install g (= m->g0) and set the stack bounds
        // to match the current stack. We don't actually know
        // how big the stack is, like we don't know how big any
@@ -956,7 +965,6 @@ func needm(x byte) {
        _g_.stack.lo = uintptr(noescape(unsafe.Pointer(&x))) - 32*1024
        _g_.stackguard0 = _g_.stack.lo + _StackGuard
 
-       msigsave(mp)
        // Initialize this thread to use the m.
        asminit()
        minit()
@@ -1027,9 +1035,6 @@ func newextram() {
 // We may have to keep the current version on systems with cgo
 // but without pthreads, like Windows.
 func dropm() {
-       // Undo whatever initialization minit did during needm.
-       unminit()
-
        // Clear m and g, and return m to the extra list.
        // After the call to setg we can only call nosplit functions
        // with no pointer manipulation.
@@ -1037,7 +1042,16 @@ func dropm() {
        mnext := lockextra(true)
        mp.schedlink.set(mnext)
 
+       // Block signals before unminit.
+       // Unminit unregisters the signal handling stack (but needs g on some systems).
+       // Setg(nil) clears g, which is the signal handler's cue not to run Go handlers.
+       // It's important not to try to handle a signal between those two steps.
+       sigblock()
+       unminit()
        setg(nil)
+       msigrestore(mp)
+
+       // Commit the release of mp.
        unlockextra(mp)
 }