1
0
mirror of https://github.com/golang/go synced 2024-11-23 06:00:08 -07:00

runtime: fix TestGCTestMoveStackOnNextCall flakes

gcTestMoveStackOnNextCall can fail to move the stack in very rare
cases if there's an unfortunately timed preemption that clobbers the
stack guard. This won't happen multiple times in quick succession, so
make the test just retry a few times.

Change-Id: I247dc0551514e269e7132cee7945291429b0e865
Reviewed-on: https://go-review.googlesource.com/c/go/+/306671
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Austin Clements 2021-03-31 12:13:58 -04:00
parent 5579ee169f
commit 41e8a9f1cf
2 changed files with 17 additions and 4 deletions

View File

@ -205,15 +205,24 @@ func TestGcZombieReporting(t *testing.T) {
func TestGCTestMoveStackOnNextCall(t *testing.T) {
t.Parallel()
var onStack int
runtime.GCTestMoveStackOnNextCall()
moveStackCheck(t, &onStack, uintptr(unsafe.Pointer(&onStack)))
// GCTestMoveStackOnNextCall can fail in rare cases if there's
// a preemption. This won't happen many times in quick
// succession, so just retry a few times.
for retry := 0; retry < 5; retry++ {
runtime.GCTestMoveStackOnNextCall()
if moveStackCheck(t, &onStack, uintptr(unsafe.Pointer(&onStack))) {
// Passed.
return
}
}
t.Fatal("stack did not move")
}
// This must not be inlined because the point is to force a stack
// growth check and move the stack.
//
//go:noinline
func moveStackCheck(t *testing.T, new *int, old uintptr) {
func moveStackCheck(t *testing.T, new *int, old uintptr) bool {
// new should have been updated by the stack move;
// old should not have.
@ -228,8 +237,9 @@ func moveStackCheck(t *testing.T, new *int, old uintptr) {
t.Fatalf("test bug: new (%#x) should be a stack pointer, not %s", new2, cls)
}
// This was a real failure.
t.Fatal("stack did not move")
return false
}
return true
}
func TestGCTestIsReachable(t *testing.T) {

View File

@ -2347,6 +2347,9 @@ func fmtNSAsMS(buf []byte, ns uint64) []byte {
// if any other work appears after this call (such as returning).
// Typically the following call should be marked go:noinline so it
// performs a stack check.
//
// In rare cases this may not cause the stack to move, specifically if
// there's a preemption between this call and the next.
func gcTestMoveStackOnNextCall() {
gp := getg()
gp.stackguard0 = getcallersp()