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

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

Issue 1691893002: Fuzzer now deduplicates on the analysis side instead of the download side (Closed) Base URL: https://skia.googlesource.com/buildbot@metrics
Patch Set: 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
« no previous file with comments | « fuzzer/go/frontend/data/report_test.go ('k') | fuzzer/go/frontend/data/stacktrace.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 package data
2
3 import (
4 "fmt"
5 "regexp"
6 "sort"
7 "strings"
8
9 "go.skia.org/infra/fuzzer/go/common"
10 )
11
12 // Represents the metadata about a crash, hopefully easing debugging.
13 type FuzzResult struct {
14 Debug BuildData
15 Release BuildData
16 }
17
18 // BuildData represents the results of parsing a given skia build's output.
19 type BuildData struct {
20 OutputFiles
21 StackTrace StackTrace
22 Flags FuzzFlag
23 }
24
25 // OutputFiles are the files output by the analysis
26 type OutputFiles struct {
27 Asan string
28 Dump string
29 StdErr string
30 }
31
32 // GCSPackage is a struct containing all the pieces of a fuzz that exist in Goog le Storage.
33 type GCSPackage struct {
34 Name string
35 FuzzCategory string
36 Debug OutputFiles
37 Release OutputFiles
38 }
39
40 // A bit mask representing what happened when a fuzz ran against Skia.
41 type FuzzFlag int
42
43 const (
44 TerminatedGracefully FuzzFlag = 1 << iota
45 ClangCrashed
46 ASANCrashed
47 AssertionViolated
48 BadAlloc
49 NoStackTrace
50 SKAbortHit
51 TimedOut
52 Other
53
54 ASAN_GlobalBufferOverflow
55 ASAN_HeapBufferOverflow
56 ASAN_StackBufferOverflow
57 ASAN_HeapUseAfterFree
58
59 SKPICTURE_DuringRendering
60 )
61
62 var flagNames = []string{
63 "FailedGracefully",
64 "ClangCrashed",
65 "ASANCrashed",
66 "AssertionViolated",
67 "BadAlloc",
68 "NoStackTrace",
69 "SKAbortHit",
70 "TimedOut",
71 "Other",
72
73 "ASAN_global-buffer-overflow",
74 "ASAN_heap-buffer-overflow",
75 "ASAN_stack-buffer-overflow",
76 "ASAN_heap-use-after-free",
77
78 "SKPICTURE_DuringRendering",
79 }
80
81 // ToHumanReadableFlags creates a sorted slice of strings that represents the fl ags. The slice
82 // is sorted by unicode points, as per sort.Strings().
83 func (f FuzzFlag) ToHumanReadableFlags() []string {
84 flags := make([]string, 0)
85 i := 0
86 for mask := 1; mask < (2 << 16); mask *= 2 {
87 if int(f)&mask != 0 {
88 flags = append(flags, flagNames[i])
89 }
90 i++
91 }
92 // Front end filtering logic will expect the flags to be in alphabetical order.
93 sort.Strings(flags)
94 return flags
95 }
96
97 func (f FuzzFlag) String() string {
98 return fmt.Sprintf("FuzzFlag: %016b (%d) [%s]", f, f, strings.Join(f.ToH umanReadableFlags(), " | "))
99 }
100
101 // ParseGCSPackage parses the results of analysis of a fuzz and creates a FuzzRe sult with it.
102 // This includes parsing the stacktraces and computing the flags about the fuzz.
103 func ParseGCSPackage(g GCSPackage) FuzzResult {
104 result := FuzzResult{}
105 result.Debug.Asan = g.Debug.Asan
106 result.Debug.Dump = g.Debug.Dump
107 result.Debug.StdErr = g.Debug.StdErr
108 result.Debug.StackTrace = getStackTrace(g.Debug.Asan, g.Debug.Dump)
109 result.Release.Asan = g.Release.Asan
110 result.Release.Dump = g.Release.Dump
111 result.Release.StdErr = g.Release.StdErr
112 result.Release.StackTrace = getStackTrace(g.Release.Asan, g.Release.Dump )
113 result.computeFlags(g.FuzzCategory)
114
115 return result
116 }
117
118 // getStackTrace creates a StackTrace output from one of the two dumps given. I t first tries to
119 // use the AddressSanitizer dump, with the Clang dump as a fallback.
120 func getStackTrace(asan, dump string) StackTrace {
121 if asanCrashed(asan) {
122 return parseASANStackTrace(asan)
123 }
124 return parseCatchsegvStackTrace(dump)
125 }
126
127 // computeFlags parses the raw data to set both the Debug and Release flags.
128 func (r *FuzzResult) computeFlags(category string) {
129 r.Debug.Flags = parseAll(category, &r.Debug)
130 r.Release.Flags = parseAll(category, &r.Release)
131 }
132
133 // parseAll looks at the three input files and parses the results, based on the category. The
134 // category allows for specialized flags, like SKPICTURE_DuringRendering.
135 func parseAll(category string, data *BuildData) FuzzFlag {
136 f := FuzzFlag(0)
137 // Check for SKAbort message
138 if strings.Contains(data.Asan, "fatal error") {
139 f |= ASANCrashed
140 f |= SKAbortHit
141 if data.StackTrace.IsEmpty() {
142 data.StackTrace = extractSkAbortTrace(data.StdErr)
143 }
144 }
145 if strings.Contains(data.StdErr, "fatal error") {
146 f |= ClangCrashed
147 f |= SKAbortHit
148 if data.StackTrace.IsEmpty() {
149 data.StackTrace = extractSkAbortTrace(data.StdErr)
150 }
151 }
152 // If no sk abort message and no evidence of crashes, we either terminat ed gracefully or
153 // timed out.
154 if f == 0 && !asanCrashed(data.Asan) && !clangDumped(data.Dump) {
155 if strings.Contains(data.Asan, "[terminated]") && strings.Contai ns(data.StdErr, "[terminated]") {
156 return TerminatedGracefully
157 }
158 return TimedOut
159 }
160
161 // Look for clues from the various dumps.
162 f |= parseAsan(category, data.Asan)
163 f |= parseCatchsegv(category, data.Dump, data.StdErr)
164 if f == 0 {
165 // I don't know what this means (yet).
166 return Other
167 }
168 if data.StackTrace.IsEmpty() {
169 f |= NoStackTrace
170 }
171 return f
172 }
173
174 // parseAsan returns the flags discovered while looking through the AddressSanit izer output. This
175 // includes things like ASAN_GlobalBufferOverflow.
176 func parseAsan(category, asan string) FuzzFlag {
177 f := FuzzFlag(0)
178 if !asanCrashed(asan) {
179 return f
180 }
181 f |= ASANCrashed
182 if strings.Contains(asan, "failed assertion") {
183 f |= AssertionViolated
184 }
185 if strings.Contains(asan, "global-buffer-overflow") {
186 f |= ASAN_GlobalBufferOverflow
187 }
188 if strings.Contains(asan, "heap-buffer-overflow") {
189 f |= ASAN_HeapBufferOverflow
190 }
191 if strings.Contains(asan, "stack-buffer-overflow") {
192 f |= ASAN_StackBufferOverflow
193 }
194 if strings.Contains(asan, "heap-use-after-free") {
195 f |= ASAN_HeapUseAfterFree
196 }
197 if strings.Contains(asan, "AddressSanitizer failed to allocate") {
198 f |= BadAlloc
199 }
200
201 // Split off the stderr that happened before the crash.
202 errs := strings.Split(asan, "=================")
203 if len(errs) > 0 {
204 err := errs[0]
205 if category == "skpicture" && strings.Contains(err, "Rendering") {
206 f |= SKPICTURE_DuringRendering
207 }
208 }
209 return f
210 }
211
212 // asanCrashed returns true if the asan output is consistent with a crash.
213 func asanCrashed(asan string) bool {
214 return strings.Contains(asan, "ERROR: AddressSanitizer:")
215 }
216
217 // parseAsan returns the flags discovered while looking through the Clang dump a nd standard error.
218 // This includes things like
219 func parseCatchsegv(category, dump, err string) FuzzFlag {
220 f := FuzzFlag(0)
221 if !clangDumped(dump) && strings.Contains(err, "[terminated]") {
222 return f
223 }
224 f |= ClangCrashed
225 if strings.Contains(err, "failed assertion") {
226 f |= AssertionViolated
227 }
228 if category == "skpicture" && strings.Contains(err, "Rendering") {
229 f |= SKPICTURE_DuringRendering
230 }
231 if strings.Contains(err, "std::bad_alloc") {
232 f |= BadAlloc
233 }
234 return f
235 }
236
237 // clangDumped returns true if the clang output is consistent with a crash, that is, non empty.
238 func clangDumped(dump string) bool {
239 return len(dump) != 0
240 }
241
242 var skAbortStackTraceLine = regexp.MustCompile(`(?:\.\./)+(?P<package>(?:\w+/)+) (?P<file>.+):(?P<line>\d+): fatal error`)
243
244 // extractSkAbortTrace looks for the fatal error string indicative of the SKAbor t termination
245 // and tries to pull out the stacktrace frame on which it happened.
246 func extractSkAbortTrace(err string) StackTrace {
247 st := StackTrace{}
248 if match := skAbortStackTraceLine.FindStringSubmatch(err); match != nil {
249 st.Frames = append(st.Frames, FullStackFrame(match[1], match[2], common.UNKNOWN_FUNCTION, safeParseInt(match[3])))
250 }
251 return st
252 }
OLDNEW
« no previous file with comments | « fuzzer/go/frontend/data/report_test.go ('k') | fuzzer/go/frontend/data/stacktrace.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698