From 9401172166ee6ac64a5a74b4a8f2aa6d3f936ea1 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 17 Jun 2021 22:12:24 -0700 Subject: [PATCH] runtime: clarify Frames.Next documentation I wrote code that relied on this API, but I misunderstood the original description of the "more" result. As a consequence, my code always stopped one frame early. This CL expands the documentation to be more explicit and specifically call out my confusion (i.e., that the "more" result indicates whether the *next* Next call will return a valid Frame, and not whether this call did). Change-Id: If135f8f8c05425073d45377c4179e4f79e6bd6ca Reviewed-on: https://go-review.googlesource.com/c/go/+/329389 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Matthew Dempsky --- src/runtime/example_test.go | 16 ++++++++++++---- src/runtime/symtab.go | 11 +++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/runtime/example_test.go b/src/runtime/example_test.go index e4912a51588..dcb8f7798e2 100644 --- a/src/runtime/example_test.go +++ b/src/runtime/example_test.go @@ -12,12 +12,15 @@ import ( func ExampleFrames() { c := func() { - // Ask runtime.Callers for up to 10 pcs, including runtime.Callers itself. + // Ask runtime.Callers for up to 10 PCs, including runtime.Callers itself. pc := make([]uintptr, 10) n := runtime.Callers(0, pc) if n == 0 { - // No pcs available. Stop now. - // This can happen if the first argument to runtime.Callers is large. + // No PCs available. This can happen if the first argument to + // runtime.Callers is large. + // + // Return now to avoid processing the zero Frame that would + // otherwise be returned by frames.Next below. return } @@ -25,9 +28,12 @@ func ExampleFrames() { frames := runtime.CallersFrames(pc) // Loop to get frames. - // A fixed number of pcs can expand to an indefinite number of Frames. + // A fixed number of PCs can expand to an indefinite number of Frames. for { frame, more := frames.Next() + + // Process this frame. + // // To keep this example's output stable // even if there are changes in the testing package, // stop unwinding when we leave package runtime. @@ -35,6 +41,8 @@ func ExampleFrames() { break } fmt.Printf("- more:%v | %s\n", more, frame.Function) + + // Check whether there are more frames to process after this one. if !more { break } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 6b535dfcbfc..999300a58ec 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -68,8 +68,15 @@ func CallersFrames(callers []uintptr) *Frames { return f } -// Next returns frame information for the next caller. -// If more is false, there are no more callers (the Frame value is valid). +// Next returns a Frame representing the next call frame in the slice +// of PC values. If it has already returned all call frames, Next +// returns a zero Frame. +// +// The more result indicates whether the next call to Next will return +// a valid Frame. It does not necessarily indicate whether this call +// returned one. +// +// See the Frames example for idiomatic usage. func (ci *Frames) Next() (frame Frame, more bool) { for len(ci.frames) < 2 { // Find the next frame.