Skip to content

Commit

Permalink
internal/gocore: fix large types dereference (Go 1.22+)
Browse files Browse the repository at this point in the history
viewcore supports Go 1.22+ allocation headers since CL 608475. The CL
description mentions:

> This gets the goroot test passing again, which is a low bar... but
> it's something.

This CL fixes an untested path, and modifies test.go to hit that path by
allocating a "large" object (>32760 bytes). When allocating a large
object, viewcore panics:

```
panic: asking for field of non-struct [recovered]
        panic: asking for field of non-struct

goroutine 170 [running]:
testing.tRunner.func1.2({0x72ce80, 0x7b86c0})
        /usr/lib/google-golang/src/testing/testing.go:1632 +0x230
testing.tRunner.func1()
        /usr/lib/google-golang/src/testing/testing.go:1635 +0x35e
panic({0x72ce80?, 0x7b86c0?})
        /usr/lib/google-golang/src/runtime/panic.go:785 +0x132
golang.org/x/debug/internal/gocore.(*Type).field(...)
        /usr/local/google/home/aktau/gob/go/debug/internal/gocore/type.go:85
golang.org/x/debug/internal/gocore.region.Field(...)
        /usr/local/google/home/aktau/gob/go/debug/internal/gocore/region.go:163
golang.org/x/debug/internal/gocore.(*Process).readSpans(0xc0001fe000, {0xc0001fe000?, 0xc000000f50?, 0xc000000500?}, {0xc000aa0480?, 0x1, 0xc0005d7260?})
        /usr/local/google/home/aktau/gob/go/debug/internal/gocore/process.go:596 +0x5125
golang.org/x/debug/internal/gocore.(*Process).readHeap(0xc0001fe000)
        /usr/local/google/home/aktau/gob/go/debug/internal/gocore/process.go:254 +0x569
golang.org/x/debug/internal/gocore.Core(0xc0001f4000)
```

Indeed, `largeType` is not a struct, but a pointer to a struct:

```
// src/runtime/mheap.go
type mspan struct {
	_    sys.NotInHeap
	// ...
	largeType             *_type        // malloc header for large objects.
}
```

Add a `Deref()` operation to fix this. Afterwards, the test does not panic
anymore. Though no attempt has been made to verify that the results are good.

Change-Id: I3569e5e1fba14a311507944f75e2ee2d27616a15
Reviewed-on: https://go-review.googlesource.com/c/debug/+/619875
LUCI-TryBot-Result: Go LUCI <[email protected]>
Auto-Submit: Nicolas Hillegeer <[email protected]>
Reviewed-by: Michael Knyszek <[email protected]>
  • Loading branch information
aktau authored and gopherbot committed Oct 14, 2024
1 parent dfd7e92 commit 7c45582
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 1 deletion.
2 changes: 1 addition & 1 deletion internal/gocore/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ func (p *Process) readSpans(mheap region, arenas []arena) {
// is not valid if the object is dead. However, because large objects are
// 1:1 with spans, we can be certain largeType is valid as long as the span
// is in use.
typ := s.Field("largeType")
typ := s.Field("largeType").Deref()
nptrs := int64(typ.Field("PtrBytes").Uintptr()) / ptrSize
if typ.Field("Kind_").Uint8()&uint8(p.rtConstants["kindGCProg"]) != 0 {
panic("large object's GCProg was not unrolled")
Expand Down
17 changes: 17 additions & 0 deletions internal/gocore/testdata/coretest/test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
package main

// Large is an object that (since Go 1.22) is allocated in a span that has a
// non-nil largeType field. Meaning it must be (>maxSmallSize-mallocHeaderSize).
// At the time of writing this is (32768 - 8).
type Large struct {
ptr *uint8 // Object must contain a pointer to trigger code path.
arr [32768 - 8]uint8
}

func ping(o *Large) {
o.ptr = &o.arr[5]
o.arr[5] = 0xCA
}

func main() {
var o Large
go ping(&o) // Force an escape of o.
o.arr[14] = 0xDE // Prevent a future smart compiler from allocating o directly on pings stack.

_ = *(*int)(nil)
}

0 comments on commit 7c45582

Please sign in to comment.