From 0ccdcb21024271211a64a5bb7e9c3c64d72f2699 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 14 Apr 2021 23:38:10 -0400 Subject: [PATCH] runtime: crash the GC when clobberdead pointer is seen When -clobberdead compiler flag is set, the compiler inserts instructions that set dead slots a specific value. If the GC sees this value as a live pointer, something is probably wrong. Crash. Only do this on AMD64 for now, as it is the only platform where compiler's clobberdead mode is implemented. And on AMD64 the clobberdead address can never be a valid address. Change-Id: Ica687b132b5d3ba2a062500d13264fa730405d11 Reviewed-on: https://go-review.googlesource.com/c/go/+/310330 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/mbitmap.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 2d12c563b8..32b8db7a50 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -333,6 +333,10 @@ func heapBitsForAddr(addr uintptr) (h heapBits) { return } +// clobberdeadPtr is a special value that is used by the compiler to +// clobber dead stack slots, when -clobberdead flag is set. +const clobberdeadPtr = uintptr(0xdeaddead | 0xdeaddead<<((^uintptr(0)>>63)*32)) + // badPointer throws bad pointer in heap panic. func badPointer(s *mspan, p, refBase, refOff uintptr) { // Typically this indicates an incorrect use @@ -345,13 +349,16 @@ func badPointer(s *mspan, p, refBase, refOff uintptr) { // in allocated spans. printlock() print("runtime: pointer ", hex(p)) - state := s.state.get() - if state != mSpanInUse { - print(" to unallocated span") - } else { - print(" to unused region of span") + if s != nil { + state := s.state.get() + if state != mSpanInUse { + print(" to unallocated span") + } else { + print(" to unused region of span") + } + print(" span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", state) } - print(" span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", state, "\n") + print("\n") if refBase != 0 { print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n") gcDumpObject("object", refBase, refOff) @@ -379,6 +386,12 @@ func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex ui // If s is nil, the virtual address has never been part of the heap. // This pointer may be to some mmap'd region, so we allow it. if s == nil { + if GOARCH == "amd64" && p == clobberdeadPtr && debug.invalidptr != 0 { + // Crash if clobberdeadPtr is seen. Only on AMD64 for now, as + // it is the only platform where compiler's clobberdead mode is + // implemented. On AMD64 clobberdeadPtr cannot be a valid address. + badPointer(s, p, refBase, refOff) + } return } // If p is a bad pointer, it may not be in s's bounds. -- 2.48.1