go-stack/stack

what the sigpanic is used for ?

Closed this issue · 2 comments

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 ?

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

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, golang/go@8db71d4. 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.