go-stack / stack

Package stack implements utilities to capture, manipulate, and format call stacks.
MIT License
395 stars 33 forks source link

what the sigpanic is used for ? #11

Closed biased-kit closed 7 years ago

biased-kit commented 7 years ago

Here is the code used in Caller() func:

    c.pc = pcs[1]
    if runtime.FuncForPC(pcs[0]) != sigpanic {
        c.pc--
    }

Could you please explain why the program counter is reduced by one ?

biased-kit commented 7 years ago

Found the answer in git history. For those who may interested see https://github.com/golang/go/issues/7690 and note that the issue is tackled today by runtime.Frames

ChrisHines commented 7 years ago

In short we must subtract one from the PC in most cases because runtime.Callers returns PCs for where each stack frame would return to rather than where it was called from.

Go 1.7 introduced the runtime.CallersFrames function which takes care of that for us automatically. I would like to update this package to use the new API sometime soon, but it hasn't happened yet.

The need to check for sigpanic is an inner detail of the Go runtime that was not documented until Go 1.4. Those docs were removed again with the improved support of the new API in Go 1.7.

From Go 1.4 until Go 1.7 the documentation for runtime.Callers had more detail about these issues. The older docs can be seen in the commit where the extra detail was added, https://github.com/golang/go/commit/8db71d4ee89a505c375b550eb8fb8cc33bbabc03. The relevant portion of the docs said:

Note that since each slice entry pc[i] is a return program counter, looking up the file and line for pc[i] (for example, using (*Func).FileLine) will return the file and line number of the instruction immediately following the call. To look up the file and line number of the call itself, use pc[i]-1. As an exception to this rule, if pc[i-1] corresponds to the function runtime.sigpanic, then pc[i] is the program counter of a faulting instruction and should be used without any subtraction.

Unfortunately runtime.sigpanic is not exported, so this package had to capture it's *runtime.Func with an ugly hack, as seen here: https://github.com/go-stack/stack/blob/master/stack.go#L208.