]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add always-preempt maymorestack hook
authorAustin Clements <austin@google.com>
Wed, 15 Sep 2021 21:14:21 +0000 (17:14 -0400)
committerAustin Clements <austin@google.com>
Fri, 5 Nov 2021 00:52:08 +0000 (00:52 +0000)
This adds a maymorestack hook that forces a preemption at every
possible cooperative preemption point. This would have helped us catch
several recent preemption-related bugs earlier, including #47302,
 #47304, and #47441.

For #48297.

Change-Id: Ib82c973589c8a7223900e1842913b8591938fb9f
Reviewed-on: https://go-review.googlesource.com/c/go/+/359796
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: David Chase <drchase@google.com>
src/runtime/debug.go
src/runtime/stack.go

index 82deefa200cdf7cf68d1af6fe7cd48534423d1ca..c343f430cc3c9f20e6b01817fede54bb6867ada6 100644 (file)
@@ -61,3 +61,37 @@ func NumGoroutine() int {
 func debug_modinfo() string {
        return modinfo
 }
+
+// mayMoreStackPreempt is a maymorestack hook that forces a preemption
+// at every possible cooperative preemption point.
+//
+// This is valuable to apply to the runtime, which can be sensitive to
+// preemption points. To apply this to all preemption points in the
+// runtime and runtime-like code, use the following in bash or zsh:
+//
+//   X=(-{gc,asm}flags={runtime/...,reflect,sync}=-d=maymorestack=runtime.mayMoreStackPreempt) GOFLAGS=${X[@]}
+//
+// This must be deeply nosplit because it is called from a function
+// prologue before the stack is set up and because the compiler will
+// call it from any splittable prologue (leading to infinite
+// recursion).
+//
+// Ideally it should also use very little stack because the linker
+// doesn't currently account for this in nosplit stack depth checking.
+//
+//go:nosplit
+//
+// Ensure mayMoreStackPreempt can be called for all ABIs.
+//
+//go:linkname mayMoreStackPreempt
+func mayMoreStackPreempt() {
+       // Don't do anything on the g0 or gsignal stack.
+       g := getg()
+       if g == g.m.g0 || g == g.m.gsignal {
+               return
+       }
+       // Force a preemption, unless the stack is already poisoned.
+       if g.stackguard0 < stackPoisonMin {
+               g.stackguard0 = stackPreempt
+       }
+}
index 52d21e4ee485a8ed0b2378f110e5bae3331c5655..7d9ae1e9d24dc3f7a9d03a63991772d1d6cef1af 100644 (file)
@@ -144,6 +144,9 @@ const (
        // Force a stack movement. Used for debugging.
        // 0xfffffeed in hex.
        stackForceMove = uintptrMask & -275
+
+       // stackPoisonMin is the lowest allowed stack poison value.
+       stackPoisonMin = uintptrMask & -4096
 )
 
 // Global pool of spans that have free stacks.