gocore: expand bigslice test to test deconstructed values on the stack Change-Id: Ie525b23748a53fffd9876515ebf2caa93744f523 Reviewed-on: https://go-review.googlesource.com/c/debug/+/659796 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Nicolas Hillegeer <aktau@google.com>
diff --git a/internal/gocore/gocore_test.go b/internal/gocore/gocore_test.go index ffb9bd4..6899f78 100644 --- a/internal/gocore/gocore_test.go +++ b/internal/gocore/gocore_test.go
@@ -296,13 +296,15 @@ } return true }) - if largeObjects != 1 { - t.Errorf("expected exactly one object larger than %d, found %d", largeObjectThreshold, largeObjects) + if largeObjects != 3 { + t.Errorf("expected exactly three object larger than %d, found %d", largeObjectThreshold, largeObjects) } // Check object counts. + // + // TODO(mknyszek): Support typing roots in pieces. if want := 32 << 10; bigSliceElemObjects != want { - t.Errorf("expected exactly %d main.globalBigSliceInt objects, found %d", want, bigSliceElemObjects) + t.Errorf("expected exactly %d main.bigSliceElem objects, found %d", want, bigSliceElemObjects) } }) t.Run("large.go", func(t *testing.T) {
diff --git a/internal/gocore/testdata/testprogs/bigslice.go b/internal/gocore/testdata/testprogs/bigslice.go index d383fea..322913f 100644 --- a/internal/gocore/testdata/testprogs/bigslice.go +++ b/internal/gocore/testdata/testprogs/bigslice.go
@@ -10,6 +10,7 @@ import ( "os" + "runtime" "golang.org/x/debug/internal/testenv" ) @@ -19,13 +20,42 @@ } var globalBigSlice []*bigSliceElem +var block chan struct{} func main() { testenv.RunThenCrash(os.Getenv("GO_DEBUG_TEST_COREDUMP_FILTER"), func() any { - globalBigSlice = make([]*bigSliceElem, 32<<10) - for i := range globalBigSlice { - globalBigSlice[i] = &bigSliceElem{float64(i), float64(i) - 0.5, float64(i * 124)} - } + globalBigSlice = *makeBigSlice() + ready := make(chan []*bigSliceElem) + go func() { + // This funny incantation exists to force the bs0 and bs1 slice + // headers to be deconstructed by the compiler and stored in pieces + // on the stack. This tests whether gocore can piece it back + // together. + bsp0 := makeBigSlice() + bsp1 := makeBigSlice() + bs0 := *bsp0 + bs1 := *bsp1 + runtime.GC() + ready <- bs0 + ready <- bs1 + runtime.KeepAlive(bs0) + runtime.KeepAlive(bs1) + }() + <-ready + return nil }) } + +// This function signature looks weird, returning a pointer to a slice, but it's +// to try and force deconstruction of the slice value by the compiler in the caller. +// See callers of makeBigSlice. +// +//go:noinline +func makeBigSlice() *[]*bigSliceElem { + bs := make([]*bigSliceElem, 32<<10) + for i := range bs { + bs[i] = &bigSliceElem{float64(i), float64(i) - 0.5, float64(i * 124)} + } + return &bs +}