Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(650)

Side by Side Diff: fuzzer/go/frontend/data/stacktrace.go

Issue 1668543004: Add AddressSanitizer to fuzzer analysis (Closed) Base URL: https://skia.googlesource.com/buildbot@remove-old-tests
Patch Set: add multi threaded delete Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 package data 1 package data
2 2
3 import ( 3 import (
4 "bufio" 4 "bufio"
5 "bytes" 5 "bytes"
6 "fmt" 6 "fmt"
7 "regexp" 7 "regexp"
8 "strconv" 8 "strconv"
9 "strings" 9 "strings"
10 10
11 "github.com/skia-dev/glog" 11 "github.com/skia-dev/glog"
12 "go.skia.org/infra/fuzzer/go/common" 12 "go.skia.org/infra/fuzzer/go/common"
13 ) 13 )
14 14
15 type StackTrace struct { 15 type StackTrace struct {
16 Frames []StackTraceFrame `json:"frames"` 16 Frames []StackTraceFrame `json:"frames"`
17 } 17 }
18 18
19 type StackTraceFrame struct { 19 type StackTraceFrame struct {
20 PackageName string `json:"packageName"` 20 PackageName string `json:"packageName"`
21 FileName string `json:"fileName"` 21 FileName string `json:"fileName"`
22 LineNumber int `json:"lineNumber"` 22 LineNumber int `json:"lineNumber"`
23 FunctionName string `json:"functionName"` 23 FunctionName string `json:"functionName"`
24 } 24 }
25 25
26 // The `?:` at the beginning of the groups prevent them from being captured 26 // The `?:` at the beginning of the groups prevent them from being captured
27 // \1 is the "package", \2 is the file name, \3 is the line number, \4 is the fu nction symbol string 27 // \1 is the "package", \2 is the file name, \3 is the line number, \4 is the fu nction symbol string
28 var stackTraceLine = regexp.MustCompile(`(?:\.\./)+(?P<package>(?:\w+/)+)(?P<fil e>.+):(?P<line>\d+).*\(_(?P<symbol>.*)\)`) 28 var segvStackTraceLine = regexp.MustCompile(`(?:\.\./)+(?P<package>(?:\w+/)+)(?P <file>.+):(?P<line>\d+).*\(_(?P<symbol>.*)\)`)
29 29
30 // Given the files of a dump file (created through get_stack_trace [which uses c atchsegv]), return the stack trace 30 // parseCatchsegvStackTrace takes the contents of a dump file of a catchsegv run , and returns the
31 func ParseStackTrace(contents string) StackTrace { 31 // parsed stacktrace
32 func parseCatchsegvStackTrace(contents string) StackTrace {
32 r := bytes.NewBufferString(contents) 33 r := bytes.NewBufferString(contents)
33 scan := bufio.NewScanner(r) 34 scan := bufio.NewScanner(r)
34 35
35 hasBegun := false 36 hasBegun := false
36 37
37 frames := make([]StackTraceFrame, 0, 5) 38 frames := make([]StackTraceFrame, 0, 5)
38 39
39 for scan.Scan() { 40 for scan.Scan() {
40 line := scan.Text() 41 line := scan.Text()
41 if strings.Contains(line, "Backtrace") { 42 if strings.Contains(line, "Backtrace") {
42 hasBegun = true 43 hasBegun = true
43 } 44 }
44 if strings.Contains(line, "Memory map") { 45 if strings.Contains(line, "Memory map") {
45 break 46 break
46 } 47 }
47 if !hasBegun { 48 if !hasBegun {
48 continue 49 continue
49 } 50 }
50 51
51 » » if match := stackTraceLine.FindStringSubmatch(line); match != ni l { 52 » » if match := segvStackTraceLine.FindStringSubmatch(line); match ! = nil {
52 // match[0] is the entire matched portion, [1] is the "p ackage", [2] is the file name, 53 // match[0] is the entire matched portion, [1] is the "p ackage", [2] is the file name,
53 // [3] is the line number and [4] is the encoded functio n symbol string. 54 // [3] is the line number and [4] is the encoded functio n symbol string.
54 » » » newFrame := FullStackFrame(match[1], match[2], decodeFun ctionName(match[4]), safeParseInt(match[3])) 55 » » » newFrame := FullStackFrame(match[1], match[2], catchsegv FunctionName(match[4]), safeParseInt(match[3]))
55 frames = append(frames, newFrame) 56 frames = append(frames, newFrame)
56 } 57 }
57 } 58 }
58 return StackTrace{Frames: frames} 59 return StackTrace{Frames: frames}
59 } 60 }
60 61
61 // safeParseInt parses a string that is known to contain digits into an int. 62 // safeParseInt parses a string that is known to contain digits into an int.
62 // It may fail if the number is larger than MAX_INT, but it is unlikely those 63 // It may fail if the number is larger than MAX_INT, but it is unlikely those
63 // numbers would come up in the stacktraces. 64 // numbers would come up in the stacktraces.
64 func safeParseInt(n string) int { 65 func safeParseInt(n string) int {
65 if i, err := strconv.Atoi(n); err != nil { 66 if i, err := strconv.Atoi(n); err != nil {
66 glog.Errorf("Could not parse number from known digits %q: %v", n , err) 67 glog.Errorf("Could not parse number from known digits %q: %v", n , err)
67 return 0 68 return 0
68 } else { 69 } else {
69 return i 70 return i
70 } 71 }
71 } 72 }
72 73
73 var staticStart = regexp.MustCompile(`^ZL(\d+)`) 74 var staticStart = regexp.MustCompile(`^ZL(\d+)`)
74 var nonstaticStart = regexp.MustCompile(`^Z(\d+)`) 75 var nonstaticStart = regexp.MustCompile(`^Z(\d+)`)
75 76
76 var methodStart = regexp.MustCompile(`^(ZNK?)(\d+)`) 77 var methodStart = regexp.MustCompile(`^(ZNK?)(\d+)`)
77 var methodName = regexp.MustCompile(`^(\d+)`) 78 var methodName = regexp.MustCompile(`^(\d+)`)
78 79
79 // decodeFunctionName parses the symbol string from a stacktrace to 80 // catchsegvFunctionName parses the symbol string from a stacktrace to
80 // get the name of the related function. 81 // get the name of the related function.
81 //TODO(kjlubick) parse arguments if that helps the readability of the stacktrace s 82 //TODO(kjlubick) parse arguments if that helps the readability of the stacktrace s
82 // Here are some examples of symbol strings and what the various chars mean: 83 // Here are some examples of symbol strings and what the various chars mean:
83 // (Parameters are after the names, but are unparsed as of yet) 84 // (Parameters are after the names, but are unparsed as of yet)
84 // ZL12convert_to_8 -> ZL12 -> static function 12 long "convert_to_8" 85 // ZL12convert_to_8 -> ZL12 -> static function 12 long "convert_to_8"
85 // Z9tool_mainiPPc -> non-static function, 9 long "tool_main" 86 // Z9tool_mainiPPc -> non-static function, 9 long "tool_main"
86 // ZN14SkBmpMaskCodec10decodeRows -> ZN14 -> type is 14 long, method name is 10 long "decodeRows" 87 // ZN14SkBmpMaskCodec10decodeRows -> ZN14 -> type is 14 long, method name is 10 long "decodeRows"
87 // ZNK2DM6SKPSrc4drawEP8SkCanvas -> ZNK2 -> type is 2 long (method is konstant) "DM" -> 88 // ZNK2DM6SKPSrc4drawEP8SkCanvas -> ZNK2 -> type is 2 long (method is konstant) "DM" ->
88 // 6 -> Sub type is 6 long "SKPSrc" -> 4 -> method is 4 long "draw" 89 // 6 -> Sub type is 6 long "SKPSrc" -> 4 -> method is 4 long "draw"
89 // (since there is no number directly after the 3rd step, we have found the p aram boundary). 90 // (since there is no number directly after the 3rd step, we have found the p aram boundary).
90 func decodeFunctionName(s string) string { 91 func catchsegvFunctionName(s string) string {
91 if match := methodStart.FindStringSubmatch(s); match != nil { 92 if match := methodStart.FindStringSubmatch(s); match != nil {
92 length := safeParseInt(match[2]) 93 length := safeParseInt(match[2])
93 // ZNK? is 2-3 chars, so slice (num letters + num digits + numbe r of spaces) chars off 94 // ZNK? is 2-3 chars, so slice (num letters + num digits + numbe r of spaces) chars off
94 // the beginning. 95 // the beginning.
95 s = s[len(match[1])+len(match[2])+length:] 96 s = s[len(match[1])+len(match[2])+length:]
96 f := "" 97 f := ""
97 // We look at the beginning of our trimmed string for numbers. 98 // We look at the beginning of our trimmed string for numbers.
98 // if there are numbers, we pull off a piece of the name and sca n again. 99 // if there are numbers, we pull off a piece of the name and sca n again.
99 // If there is more than one piece, we separate it with ::, beca use it is a nested type 100 // If there is more than one piece, we separate it with ::, beca use it is a nested type
100 // or enum thing. 101 // or enum thing.
(...skipping 16 matching lines...) Expand all
117 } 118 }
118 if match := nonstaticStart.FindStringSubmatch(s); match != nil { 119 if match := nonstaticStart.FindStringSubmatch(s); match != nil {
119 length := safeParseInt(match[1]) 120 length := safeParseInt(match[1])
120 // Z is 1 char, so advance 1 space + how many digits there are 121 // Z is 1 char, so advance 1 space + how many digits there are
121 start := 1 + len(match[1]) 122 start := 1 + len(match[1])
122 return s[start : start+length] 123 return s[start : start+length]
123 } 124 }
124 return common.UNKNOWN_FUNCTION 125 return common.UNKNOWN_FUNCTION
125 } 126 }
126 127
128 // The `?:` at the beginning of the groups prevent them from being captured
129 // \1 is the (hopefully symbolized) function name, \2 is the "package", \3 is th e file name,
130 // \4 is the line number
131 var asanStackTraceLine = regexp.MustCompile(`in (?P<function>[a-zA-Z0-9_:]+).*(? :\.\./)+(?P<package>(?:\w+/)+)(?P<file>.+?):(?P<line>\d+)`)
132
133 // parseCatchsegvStackTrace takes the output of an AddressSanitizer crash, and r eturns the parsed
134 // StackTrace, if it is able to find one. If the result is not symbolized, this will return
135 // an empty StackTrace.
136 func parseASANStackTrace(contents string) StackTrace {
137 r := bytes.NewBufferString(contents)
138 scan := bufio.NewScanner(r)
139
140 hasBegun := false
141
142 frames := make([]StackTraceFrame, 0, 5)
143
144 for scan.Scan() {
145 line := scan.Text()
146 if strings.Contains(line, "ERROR: AddressSanitizer:") {
147 hasBegun = true
148 continue
149 }
150 if hasBegun && line == "" {
151 break
152 }
153 if !hasBegun {
154 continue
155 }
156
157 if match := asanStackTraceLine.FindStringSubmatch(line); match ! = nil {
158 // match[0] is the entire matched portion, [1] is the fu nction name [2] is the
159 // "package", [3] is the file name, [4] is the line numb er
160 newFrame := FullStackFrame(match[2], match[3], match[1], safeParseInt(match[4]))
161 frames = append(frames, newFrame)
162 }
163 }
164 return StackTrace{Frames: frames}
165 }
166
127 // FullStackFrame creates a StackTraceFrame with all components 167 // FullStackFrame creates a StackTraceFrame with all components
128 func FullStackFrame(packageName, fileName, functionName string, lineNumber int) StackTraceFrame { 168 func FullStackFrame(packageName, fileName, functionName string, lineNumber int) StackTraceFrame {
129 return StackTraceFrame{ 169 return StackTraceFrame{
130 PackageName: packageName, 170 PackageName: packageName,
131 FileName: fileName, 171 FileName: fileName,
132 LineNumber: lineNumber, 172 LineNumber: lineNumber,
133 FunctionName: functionName, 173 FunctionName: functionName,
134 } 174 }
135 } 175 }
136 176
137 func (f *StackTraceFrame) String() string { 177 func (f *StackTraceFrame) String() string {
138 return fmt.Sprintf("%s%s:%d %s", f.PackageName, f.FileName, f.LineNumber , f.FunctionName) 178 return fmt.Sprintf("%s%s:%d %s", f.PackageName, f.FileName, f.LineNumber , f.FunctionName)
139 } 179 }
140 180
141 func (st *StackTrace) String() string { 181 func (st *StackTrace) String() string {
142 s := fmt.Sprintf("StackTrace with %d frames:\n", len(st.Frames)) 182 s := fmt.Sprintf("StackTrace with %d frames:\n", len(st.Frames))
143 for _, f := range st.Frames { 183 for _, f := range st.Frames {
144 s += fmt.Sprintf("\t%s\n", f.String()) 184 s += fmt.Sprintf("\t%s\n", f.String())
145 } 185 }
146 return s 186 return s
147 } 187 }
148 188
149 func (st *StackTrace) IsEmpty() bool { 189 func (st *StackTrace) IsEmpty() bool {
150 return len(st.Frames) == 0 190 return len(st.Frames) == 0
151 } 191 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698