summaryrefslogtreecommitdiff
path: root/src/runtime/stubs.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-11-05 23:01:48 -0500
committerRuss Cox <rsc@golang.org>2014-11-05 23:01:48 -0500
commit480e360b9103c49c7fed8216a725e97aebcd39d0 (patch)
treece0ca79321a871369e8ccd8080fbe8e50ac5835b /src/runtime/stubs.go
parent15a5c8ec44a8db796713e0d61ea998842a001f5b (diff)
downloadgo-480e360b9103c49c7fed8216a725e97aebcd39d0.tar.gz
runtime: avoid gentraceback of self on user goroutine stack
Gentraceback may grow the stack. One of the gentraceback wrappers may grow the stack. One of the gentraceback callback calls may grow the stack. Various stack pointers are stored in various stack locations as type uintptr during the execution of these calls. If the stack does grow, these stack pointers will not be updated and will start trying to decode stack memory that is no longer valid. It may be possible to change the type of the stack pointer variables to be unsafe.Pointer, but that's pretty subtle and may still have problems, even if we catch every last one. An easier, more obviously correct fix is to require that gentraceback of the currently running goroutine must run on the g0 stack, not on the goroutine's own stack. Not doing this causes faults when you set StackFromSystem = 1 StackFaultOnFree = 1 The new check in gentraceback will catch future lapses. The more general problem is calling getcallersp but then calling a function that might relocate the stack, which would invalidate the result of getcallersp. Add note to stubs.go declaration of getcallersp explaining the problem, and check all existing calls to getcallersp. Most needed fixes. This affects Callers, Stack, and nearly all the runtime profiling routines. It does not affect stack copying directly nor garbage collection. LGTM=khr R=khr, bradfitz CC=golang-codereviews, r https://codereview.appspot.com/167060043
Diffstat (limited to 'src/runtime/stubs.go')
-rw-r--r--src/runtime/stubs.go28
1 files changed, 28 insertions, 0 deletions
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index 341904719..fe8f9c922 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -221,6 +221,34 @@ func atomicloaduint(ptr *uint) uint
//go:noescape
func setcallerpc(argp unsafe.Pointer, pc uintptr)
+// getcallerpc returns the program counter (PC) of its caller's caller.
+// getcallersp returns the stack pointer (SP) of its caller's caller.
+// For both, the argp must be a pointer to the caller's first function argument.
+// The implementation may or may not use argp, depending on
+// the architecture.
+//
+// For example:
+//
+// func f(arg1, arg2, arg3 int) {
+// pc := getcallerpc(unsafe.Pointer(&arg1))
+// sp := getcallerpc(unsafe.Pointer(&arg2))
+// }
+//
+// These two lines find the PC and SP immediately following
+// the call to f (where f will return).
+//
+// The call to getcallerpc and getcallersp must be done in the
+// frame being asked about. It would not be correct for f to pass &arg1
+// to another function g and let g call getcallerpc/getcallersp.
+// The call inside g might return information about g's caller or
+// information about f's caller or complete garbage.
+//
+// The result of getcallersp is correct at the time of the return,
+// but it may be invalidated by any subsequent call to a function
+// that might relocate the stack in order to grow or shrink it.
+// A general rule is that the result of getcallersp should be used
+// immediately and can only be passed to nosplit functions.
+
//go:noescape
func getcallerpc(argp unsafe.Pointer) uintptr