diff --git a/stack/context.go b/stack/context.go index 8b92e05..d216c25 100644 --- a/stack/context.go +++ b/stack/context.go @@ -257,14 +257,15 @@ var ( // gotRaceHeader1, done raceHeaderFooter = []byte("==================") // gotRaceHeader2 - raceHeader = []byte("WARNING: DATA RACE") - crlf = []byte("\r\n") - lf = []byte("\n") - commaSpace = []byte(", ") - writeCap = []byte("Write") - writeLow = []byte("write") - threeDots = []byte("...") - underscore = []byte("_") + raceHeader = []byte("WARNING: DATA RACE") + crlf = []byte("\r\n") + lf = []byte("\n") + commaSpace = []byte(", ") + writeCap = []byte("Write") + writeLow = []byte("write") + threeDots = []byte("...") + underscore = []byte("_") + inaccurateQuestionMark = []byte("?") ) // These are effectively constants. @@ -854,13 +855,18 @@ func parseArgs(line []byte) (Args, error) { arg := Arg{IsOffsetTooLarge: true} cur.Values = append(cur.Values, arg) default: + inaccurate := bytes.HasSuffix(a, inaccurateQuestionMark) + if inaccurate { + a = a[:len(a)-len(inaccurateQuestionMark)] + } + v, err := strconv.ParseUint(unsafeString(a), 0, 64) if err != nil { return Args{}, errors.New("failed to parse int") } // Assume the stack was generated with the same bitness (32 vs 64) as // the code processing it. - arg := Arg{Value: v, IsPtr: v > pointerFloor && v < pointerCeiling} + arg := Arg{Value: v, IsPtr: v > pointerFloor && v < pointerCeiling, IsInaccurate: inaccurate} cur.Values = append(cur.Values, arg) } } diff --git a/stack/context_test.go b/stack/context_test.go index d0ebfff..0c88e3d 100644 --- a/stack/context_test.go +++ b/stack/context_test.go @@ -1057,6 +1057,56 @@ func TestScanSnapshotSynthetic(t *testing.T) { }, }, + { + name: "WithCarriageReturn1.18Inaccurate", + in: []string{ + "goroutine 1 [running]:", + "github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek()", + " ??:0 +0x6d", + "gopkg.in/yaml%2ev2.handleErr(0x433b20?)", + "\t/gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6", + "reflect.Value.assignTo(0x570860, 0x803f3e0, 0x15)", + "\t/goroot/src/reflect/value.go:2125 +0x368", + "main.main()", + "\t/gopath/src/github.com/maruel/panicparse/stack/stack.go:428 +0x27", + "", + }, + err: io.EOF, + want: []*Goroutine{ + { + Signature: Signature{ + State: "running", + Stack: Stack{ + Calls: []Call{ + newCall( + "github.com/cockroachdb/cockroach/storage/engine._Cfunc_DBIterSeek", + Args{}, + "??", + 0), + newCall( + "gopkg.in/yaml%2ev2.handleErr", + Args{Values: []Arg{{Value: 0x433b20, IsPtr: true, IsInaccurate: true}}}, + "/gopath/src/gopkg.in/yaml.v2/yaml.go", + 153), + newCall( + "reflect.Value.assignTo", + Args{Values: []Arg{{Value: 0x570860, IsPtr: true}, {Value: 0x803f3e0, IsPtr: true}, {Value: 0x15}}}, + "/goroot/src/reflect/value.go", + 2125), + newCall( + "main.main", + Args{}, + "/gopath/src/github.com/maruel/panicparse/stack/stack.go", + 428), + }, + }, + }, + ID: 1, + First: true, + }, + }, + }, + // goconvey is culprit of this. { name: "Indented", diff --git a/stack/stack.go b/stack/stack.go index f83fa87..1ae2622 100644 --- a/stack/stack.go +++ b/stack/stack.go @@ -122,6 +122,10 @@ type Arg struct { // preventing the argument from being printed in the stack trace. IsOffsetTooLarge bool + // IsInaccurate determines if Value is inaccurate. Stacks could have inaccurate values + // for arguments passed in registers. Go 1.18 prints a ? for these values. + IsInaccurate bool + // The following are set if IsAggregate == true. // Fields are the fields/elements of aggregate-typed arguments.