aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/gc_test.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2021-03-24 10:45:20 -0400
committerAustin Clements <austin@google.com>2021-03-29 21:50:16 +0000
commit4e1bf8ed3840632b4781d3c4abb4704dca468dd4 (patch)
treeb1137dc58e46403a9454d0acd6f8e5f1078459fd /src/runtime/gc_test.go
parent1ef114d12c39e8467d3e905d0a050bd7ce03123a (diff)
downloadgo-4e1bf8ed3840632b4781d3c4abb4704dca468dd4.tar.gz
go-4e1bf8ed3840632b4781d3c4abb4704dca468dd4.zip
runtime: add GC testing helpers for regabi signature fuzzer
This CL adds a set of helper functions for testing GC interactions. These are intended for use in the regabi signature fuzzer, but are generally useful for GC tests, so we make them generally available to runtime tests. These provide: 1. An easy way to force stack movement, for testing stack copying. 2. A simple and robust way to check the reachability of a set of pointers. 3. A way to check what general category of memory a pointer points to, mostly so tests can make sure they're testing what they mean to. For #40724, but generally useful. Change-Id: I15d33ccb3f5a792c0472a19c2cc9a8b4a9356a66 Reviewed-on: https://go-review.googlesource.com/c/go/+/305330 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src/runtime/gc_test.go')
-rw-r--r--src/runtime/gc_test.go75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go
index 7870f31ae9..1ea1c2c745 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -202,6 +202,81 @@ func TestGcZombieReporting(t *testing.T) {
}
}
+func TestGCTestMoveStackOnNextCall(t *testing.T) {
+ t.Parallel()
+ var onStack int
+ runtime.GCTestMoveStackOnNextCall()
+ moveStackCheck(t, &onStack, uintptr(unsafe.Pointer(&onStack)))
+}
+
+// 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) {
+ // new should have been updated by the stack move;
+ // old should not have.
+
+ // Capture new's value before doing anything that could
+ // further move the stack.
+ new2 := uintptr(unsafe.Pointer(new))
+
+ t.Logf("old stack pointer %x, new stack pointer %x", old, new2)
+ if new2 == old {
+ // Check that we didn't screw up the test's escape analysis.
+ if cls := runtime.GCTestPointerClass(unsafe.Pointer(new)); cls != "stack" {
+ 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")
+ }
+}
+
+func TestGCTestIsReachable(t *testing.T) {
+ var all, half []unsafe.Pointer
+ var want uint64
+ for i := 0; i < 16; i++ {
+ // The tiny allocator muddies things, so we use a
+ // scannable type.
+ p := unsafe.Pointer(new(*int))
+ all = append(all, p)
+ if i%2 == 0 {
+ half = append(half, p)
+ want |= 1 << i
+ }
+ }
+
+ got := runtime.GCTestIsReachable(all...)
+ if want != got {
+ t.Fatalf("did not get expected reachable set; want %b, got %b", want, got)
+ }
+ runtime.KeepAlive(half)
+}
+
+var pointerClassSink *int
+var pointerClassData = 42
+
+func TestGCTestPointerClass(t *testing.T) {
+ t.Parallel()
+ check := func(p unsafe.Pointer, want string) {
+ t.Helper()
+ got := runtime.GCTestPointerClass(p)
+ if got != want {
+ // Convert the pointer to a uintptr to avoid
+ // escaping it.
+ t.Errorf("for %#x, want class %s, got %s", uintptr(p), want, got)
+ }
+ }
+ var onStack int
+ var notOnStack int
+ pointerClassSink = &notOnStack
+ check(unsafe.Pointer(&onStack), "stack")
+ check(unsafe.Pointer(&notOnStack), "heap")
+ check(unsafe.Pointer(&pointerClassSink), "bss")
+ check(unsafe.Pointer(&pointerClassData), "data")
+ check(nil, "other")
+}
+
func BenchmarkSetTypePtr(b *testing.B) {
benchSetType(b, new(*byte))
}