From a73d68e75eece80f8514bb1b368420843c1f58ad Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 20 Oct 2016 22:27:39 -0400 Subject: runtime: fix call* signatures and deferArgs with siz=0 This commit fixes two bizarrely related bugs: 1. The signatures for the call* functions were wrong, indicating that they had only two pointer arguments instead of three. We didn't notice because the call* functions are defined by a macro expansion, which go vet doesn't see. 2. deferArgs on a defer object with a zero-sized frame returned a pointer just past the end of the allocated object, which is illegal in Go (and can cause the "sweep increased allocation count" crashes). In a fascinating twist, these two bugs canceled each other out, which is why I'm fixing them together. The pointer returned by deferArgs is used in only two ways: as an argument to memmove and as an argument to reflectcall. memmove is NOSPLIT, so the argument was unobservable. reflectcall immediately tail calls one of the call* functions, which are not NOSPLIT, but the deferArgs pointer just happened to be the third argument that was accidentally marked as a scalar. Hence, when the garbage collector scanned the stack, it didn't see the bad pointer as a pointer. I believe this was all ultimately benign. In principle, stack growth during the reflectcall could fail to update the args pointer, but it never points to the stack, so it never needs to be updated. Also in principle, the garbage collector could fail to mark the args object because of the incorrect call* signatures, but in all calls to reflectcall (including the ones spelled "call" in the reflect package) the args object is kept live by the calling stack. Change-Id: Ic932c79d5f4382be23118fdd9dba9688e9169e28 Reviewed-on: https://go-review.googlesource.com/31654 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/runtime/panic.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/runtime/panic.go') diff --git a/src/runtime/panic.go b/src/runtime/panic.go index f78e67f9bb..73924365c3 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -168,6 +168,10 @@ func testdefersizes() { // immediately after the _defer header in memory. //go:nosplit func deferArgs(d *_defer) unsafe.Pointer { + if d.siz == 0 { + // Avoid pointer past the defer allocation. + return nil + } return add(unsafe.Pointer(d), unsafe.Sizeof(*d)) } -- cgit v1.3-5-g9baa