Skip to content
This repository was archived by the owner on Dec 1, 2021. It is now read-only.

Commit ee1923e

Browse files
committed
Return errors.Frame to a uintptr
Updates aws/aws-xray-sdk-go#77 Updates evalphobia/logrus_sentry#74 Go 1.12 has updated the behaviour of runtime.FuncForPC so that it behaves as it did in Go 1.11 and earlier. This allows errors.Frame to return to a uintptr representing the PC +1 of the caller. This will fix the build breakages of projects that were tracking HEAD of this package. Signed-off-by: Dave Cheney <dave@cheney.net>
1 parent 72fa05e commit ee1923e

File tree

3 files changed

+61
-71
lines changed

3 files changed

+61
-71
lines changed

format_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ func TestFormatWrappedNew(t *testing.T) {
385385
}
386386

387387
func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) {
388+
t.Helper()
388389
got := fmt.Sprintf(format, arg)
389390
gotLines := strings.SplitN(got, "\n", -1)
390391
wantLines := strings.SplitN(want, "\n", -1)

stack.go

Lines changed: 54 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package errors
22

33
import (
4-
"bytes"
54
"fmt"
65
"io"
76
"path"
@@ -11,7 +10,42 @@ import (
1110
)
1211

1312
// Frame represents a program counter inside a stack frame.
14-
type Frame runtime.Frame
13+
type Frame uintptr
14+
15+
// pc returns the program counter for this frame;
16+
// multiple frames may have the same PC value.
17+
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
18+
19+
// file returns the full path to the file that contains the
20+
// function for this Frame's pc.
21+
func (f Frame) file() string {
22+
fn := runtime.FuncForPC(f.pc())
23+
if fn == nil {
24+
return "unknown"
25+
}
26+
file, _ := fn.FileLine(f.pc())
27+
return file
28+
}
29+
30+
// line returns the line number of source code of the
31+
// function for this Frame's pc.
32+
func (f Frame) line() int {
33+
fn := runtime.FuncForPC(f.pc())
34+
if fn == nil {
35+
return 0
36+
}
37+
_, line := fn.FileLine(f.pc())
38+
return line
39+
}
40+
41+
// name returns the name of this function, if known.
42+
func (f Frame) name() string {
43+
fn := runtime.FuncForPC(f.pc())
44+
if fn == nil {
45+
return "unknown"
46+
}
47+
return fn.Name()
48+
}
1549

1650
// Format formats the frame according to the fmt.Formatter interface.
1751
//
@@ -35,25 +69,16 @@ func (f Frame) format(w io.Writer, s fmt.State, verb rune) {
3569
case 's':
3670
switch {
3771
case s.Flag('+'):
38-
if f.Function == "" {
39-
io.WriteString(w, "unknown")
40-
} else {
41-
io.WriteString(w, f.Function)
42-
io.WriteString(w, "\n\t")
43-
io.WriteString(w, f.File)
44-
}
72+
io.WriteString(w, f.name())
73+
io.WriteString(w, "\n\t")
74+
io.WriteString(w, f.file())
4575
default:
46-
file := f.File
47-
if file == "" {
48-
file = "unknown"
49-
}
50-
io.WriteString(w, path.Base(file))
76+
io.WriteString(w, path.Base(f.file()))
5177
}
5278
case 'd':
53-
io.WriteString(w, strconv.Itoa(f.Line))
79+
io.WriteString(w, strconv.Itoa(f.line()))
5480
case 'n':
55-
name := f.Function
56-
io.WriteString(s, funcname(name))
81+
io.WriteString(w, funcname(f.name()))
5782
case 'v':
5883
f.format(w, s, 's')
5984
io.WriteString(w, ":")
@@ -73,50 +98,23 @@ type StackTrace []Frame
7398
//
7499
// %+v Prints filename, function, and line number for each Frame in the stack.
75100
func (st StackTrace) Format(s fmt.State, verb rune) {
76-
var b bytes.Buffer
77101
switch verb {
78102
case 'v':
79103
switch {
80104
case s.Flag('+'):
81-
b.Grow(len(st) * stackMinLen)
82-
for _, fr := range st {
83-
b.WriteByte('\n')
84-
fr.format(&b, s, verb)
105+
for _, f := range st {
106+
fmt.Fprintf(s, "\n%+v", f)
85107
}
86108
case s.Flag('#'):
87-
fmt.Fprintf(&b, "%#v", []Frame(st))
109+
fmt.Fprintf(s, "%#v", []Frame(st))
88110
default:
89-
st.formatSlice(&b, s, verb)
111+
fmt.Fprintf(s, "%v", []Frame(st))
90112
}
91113
case 's':
92-
st.formatSlice(&b, s, verb)
114+
fmt.Fprintf(s, "%s", []Frame(st))
93115
}
94-
io.Copy(s, &b)
95116
}
96117

97-
// formatSlice will format this StackTrace into the given buffer as a slice of
98-
// Frame, only valid when called with '%s' or '%v'.
99-
func (st StackTrace) formatSlice(b *bytes.Buffer, s fmt.State, verb rune) {
100-
b.WriteByte('[')
101-
if len(st) == 0 {
102-
b.WriteByte(']')
103-
return
104-
}
105-
106-
b.Grow(len(st) * (stackMinLen / 4))
107-
st[0].format(b, s, verb)
108-
for _, fr := range st[1:] {
109-
b.WriteByte(' ')
110-
fr.format(b, s, verb)
111-
}
112-
b.WriteByte(']')
113-
}
114-
115-
// stackMinLen is a best-guess at the minimum length of a stack trace. It
116-
// doesn't need to be exact, just give a good enough head start for the buffer
117-
// to avoid the expensive early growth.
118-
const stackMinLen = 96
119-
120118
// stack represents a stack of program counters.
121119
type stack []uintptr
122120

@@ -125,29 +123,20 @@ func (s *stack) Format(st fmt.State, verb rune) {
125123
case 'v':
126124
switch {
127125
case st.Flag('+'):
128-
frames := runtime.CallersFrames(*s)
129-
for {
130-
frame, more := frames.Next()
131-
fmt.Fprintf(st, "\n%+v", Frame(frame))
132-
if !more {
133-
break
134-
}
126+
for _, pc := range *s {
127+
f := Frame(pc)
128+
fmt.Fprintf(st, "\n%+v", f)
135129
}
136130
}
137131
}
138132
}
139133

140134
func (s *stack) StackTrace() StackTrace {
141-
var st []Frame
142-
frames := runtime.CallersFrames(*s)
143-
for {
144-
frame, more := frames.Next()
145-
st = append(st, Frame(frame))
146-
if !more {
147-
break
148-
}
135+
f := make([]Frame, len(*s))
136+
for i := 0; i < len(f); i++ {
137+
f[i] = Frame((*s)[i])
149138
}
150-
return st
139+
return f
151140
}
152141

153142
func callers() *stack {

stack_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ func TestFrameFormat(t *testing.T) {
3535
"github.com/pkg/errors.init\n" +
3636
"\t.+/github.com/pkg/errors/stack_test.go",
3737
}, {
38-
Frame{},
38+
0,
3939
"%s",
4040
"unknown",
4141
}, {
42-
Frame{},
42+
0,
4343
"%+s",
4444
"unknown",
4545
}, {
4646
initpc,
4747
"%d",
4848
"9",
4949
}, {
50-
Frame{},
50+
0,
5151
"%d",
5252
"0",
5353
}, {
@@ -69,7 +69,7 @@ func TestFrameFormat(t *testing.T) {
6969
"%n",
7070
"X.val",
7171
}, {
72-
Frame{},
72+
0,
7373
"%n",
7474
"",
7575
}, {
@@ -82,7 +82,7 @@ func TestFrameFormat(t *testing.T) {
8282
"github.com/pkg/errors.init\n" +
8383
"\t.+/github.com/pkg/errors/stack_test.go:9",
8484
}, {
85-
Frame{},
85+
0,
8686
"%v",
8787
"unknown:0",
8888
}}
@@ -246,7 +246,7 @@ func caller() Frame {
246246
n := runtime.Callers(2, pcs[:])
247247
frames := runtime.CallersFrames(pcs[:n])
248248
frame, _ := frames.Next()
249-
return Frame(frame)
249+
return Frame(frame.PC)
250250
}
251251

252252
//go:noinline

0 commit comments

Comments
 (0)