Index: fuzzer/go/frontend/data/result.go |
diff --git a/fuzzer/go/frontend/data/result.go b/fuzzer/go/frontend/data/result.go |
deleted file mode 100644 |
index 7dfb7cb5a67996eea5ea8c785a7ec1175b71e559..0000000000000000000000000000000000000000 |
--- a/fuzzer/go/frontend/data/result.go |
+++ /dev/null |
@@ -1,252 +0,0 @@ |
-package data |
- |
-import ( |
- "fmt" |
- "regexp" |
- "sort" |
- "strings" |
- |
- "go.skia.org/infra/fuzzer/go/common" |
-) |
- |
-// Represents the metadata about a crash, hopefully easing debugging. |
-type FuzzResult struct { |
- Debug BuildData |
- Release BuildData |
-} |
- |
-// BuildData represents the results of parsing a given skia build's output. |
-type BuildData struct { |
- OutputFiles |
- StackTrace StackTrace |
- Flags FuzzFlag |
-} |
- |
-// OutputFiles are the files output by the analysis |
-type OutputFiles struct { |
- Asan string |
- Dump string |
- StdErr string |
-} |
- |
-// GCSPackage is a struct containing all the pieces of a fuzz that exist in Google Storage. |
-type GCSPackage struct { |
- Name string |
- FuzzCategory string |
- Debug OutputFiles |
- Release OutputFiles |
-} |
- |
-// A bit mask representing what happened when a fuzz ran against Skia. |
-type FuzzFlag int |
- |
-const ( |
- TerminatedGracefully FuzzFlag = 1 << iota |
- ClangCrashed |
- ASANCrashed |
- AssertionViolated |
- BadAlloc |
- NoStackTrace |
- SKAbortHit |
- TimedOut |
- Other |
- |
- ASAN_GlobalBufferOverflow |
- ASAN_HeapBufferOverflow |
- ASAN_StackBufferOverflow |
- ASAN_HeapUseAfterFree |
- |
- SKPICTURE_DuringRendering |
-) |
- |
-var flagNames = []string{ |
- "FailedGracefully", |
- "ClangCrashed", |
- "ASANCrashed", |
- "AssertionViolated", |
- "BadAlloc", |
- "NoStackTrace", |
- "SKAbortHit", |
- "TimedOut", |
- "Other", |
- |
- "ASAN_global-buffer-overflow", |
- "ASAN_heap-buffer-overflow", |
- "ASAN_stack-buffer-overflow", |
- "ASAN_heap-use-after-free", |
- |
- "SKPICTURE_DuringRendering", |
-} |
- |
-// ToHumanReadableFlags creates a sorted slice of strings that represents the flags. The slice |
-// is sorted by unicode points, as per sort.Strings(). |
-func (f FuzzFlag) ToHumanReadableFlags() []string { |
- flags := make([]string, 0) |
- i := 0 |
- for mask := 1; mask < (2 << 16); mask *= 2 { |
- if int(f)&mask != 0 { |
- flags = append(flags, flagNames[i]) |
- } |
- i++ |
- } |
- // Front end filtering logic will expect the flags to be in alphabetical order. |
- sort.Strings(flags) |
- return flags |
-} |
- |
-func (f FuzzFlag) String() string { |
- return fmt.Sprintf("FuzzFlag: %016b (%d) [%s]", f, f, strings.Join(f.ToHumanReadableFlags(), " | ")) |
-} |
- |
-// ParseGCSPackage parses the results of analysis of a fuzz and creates a FuzzResult with it. |
-// This includes parsing the stacktraces and computing the flags about the fuzz. |
-func ParseGCSPackage(g GCSPackage) FuzzResult { |
- result := FuzzResult{} |
- result.Debug.Asan = g.Debug.Asan |
- result.Debug.Dump = g.Debug.Dump |
- result.Debug.StdErr = g.Debug.StdErr |
- result.Debug.StackTrace = getStackTrace(g.Debug.Asan, g.Debug.Dump) |
- result.Release.Asan = g.Release.Asan |
- result.Release.Dump = g.Release.Dump |
- result.Release.StdErr = g.Release.StdErr |
- result.Release.StackTrace = getStackTrace(g.Release.Asan, g.Release.Dump) |
- result.computeFlags(g.FuzzCategory) |
- |
- return result |
-} |
- |
-// getStackTrace creates a StackTrace output from one of the two dumps given. It first tries to |
-// use the AddressSanitizer dump, with the Clang dump as a fallback. |
-func getStackTrace(asan, dump string) StackTrace { |
- if asanCrashed(asan) { |
- return parseASANStackTrace(asan) |
- } |
- return parseCatchsegvStackTrace(dump) |
-} |
- |
-// computeFlags parses the raw data to set both the Debug and Release flags. |
-func (r *FuzzResult) computeFlags(category string) { |
- r.Debug.Flags = parseAll(category, &r.Debug) |
- r.Release.Flags = parseAll(category, &r.Release) |
-} |
- |
-// parseAll looks at the three input files and parses the results, based on the category. The |
-// category allows for specialized flags, like SKPICTURE_DuringRendering. |
-func parseAll(category string, data *BuildData) FuzzFlag { |
- f := FuzzFlag(0) |
- // Check for SKAbort message |
- if strings.Contains(data.Asan, "fatal error") { |
- f |= ASANCrashed |
- f |= SKAbortHit |
- if data.StackTrace.IsEmpty() { |
- data.StackTrace = extractSkAbortTrace(data.StdErr) |
- } |
- } |
- if strings.Contains(data.StdErr, "fatal error") { |
- f |= ClangCrashed |
- f |= SKAbortHit |
- if data.StackTrace.IsEmpty() { |
- data.StackTrace = extractSkAbortTrace(data.StdErr) |
- } |
- } |
- // If no sk abort message and no evidence of crashes, we either terminated gracefully or |
- // timed out. |
- if f == 0 && !asanCrashed(data.Asan) && !clangDumped(data.Dump) { |
- if strings.Contains(data.Asan, "[terminated]") && strings.Contains(data.StdErr, "[terminated]") { |
- return TerminatedGracefully |
- } |
- return TimedOut |
- } |
- |
- // Look for clues from the various dumps. |
- f |= parseAsan(category, data.Asan) |
- f |= parseCatchsegv(category, data.Dump, data.StdErr) |
- if f == 0 { |
- // I don't know what this means (yet). |
- return Other |
- } |
- if data.StackTrace.IsEmpty() { |
- f |= NoStackTrace |
- } |
- return f |
-} |
- |
-// parseAsan returns the flags discovered while looking through the AddressSanitizer output. This |
-// includes things like ASAN_GlobalBufferOverflow. |
-func parseAsan(category, asan string) FuzzFlag { |
- f := FuzzFlag(0) |
- if !asanCrashed(asan) { |
- return f |
- } |
- f |= ASANCrashed |
- if strings.Contains(asan, "failed assertion") { |
- f |= AssertionViolated |
- } |
- if strings.Contains(asan, "global-buffer-overflow") { |
- f |= ASAN_GlobalBufferOverflow |
- } |
- if strings.Contains(asan, "heap-buffer-overflow") { |
- f |= ASAN_HeapBufferOverflow |
- } |
- if strings.Contains(asan, "stack-buffer-overflow") { |
- f |= ASAN_StackBufferOverflow |
- } |
- if strings.Contains(asan, "heap-use-after-free") { |
- f |= ASAN_HeapUseAfterFree |
- } |
- if strings.Contains(asan, "AddressSanitizer failed to allocate") { |
- f |= BadAlloc |
- } |
- |
- // Split off the stderr that happened before the crash. |
- errs := strings.Split(asan, "=================") |
- if len(errs) > 0 { |
- err := errs[0] |
- if category == "skpicture" && strings.Contains(err, "Rendering") { |
- f |= SKPICTURE_DuringRendering |
- } |
- } |
- return f |
-} |
- |
-// asanCrashed returns true if the asan output is consistent with a crash. |
-func asanCrashed(asan string) bool { |
- return strings.Contains(asan, "ERROR: AddressSanitizer:") |
-} |
- |
-// parseAsan returns the flags discovered while looking through the Clang dump and standard error. |
-// This includes things like |
-func parseCatchsegv(category, dump, err string) FuzzFlag { |
- f := FuzzFlag(0) |
- if !clangDumped(dump) && strings.Contains(err, "[terminated]") { |
- return f |
- } |
- f |= ClangCrashed |
- if strings.Contains(err, "failed assertion") { |
- f |= AssertionViolated |
- } |
- if category == "skpicture" && strings.Contains(err, "Rendering") { |
- f |= SKPICTURE_DuringRendering |
- } |
- if strings.Contains(err, "std::bad_alloc") { |
- f |= BadAlloc |
- } |
- return f |
-} |
- |
-// clangDumped returns true if the clang output is consistent with a crash, that is, non empty. |
-func clangDumped(dump string) bool { |
- return len(dump) != 0 |
-} |
- |
-var skAbortStackTraceLine = regexp.MustCompile(`(?:\.\./)+(?P<package>(?:\w+/)+)(?P<file>.+):(?P<line>\d+): fatal error`) |
- |
-// extractSkAbortTrace looks for the fatal error string indicative of the SKAbort termination |
-// and tries to pull out the stacktrace frame on which it happened. |
-func extractSkAbortTrace(err string) StackTrace { |
- st := StackTrace{} |
- if match := skAbortStackTraceLine.FindStringSubmatch(err); match != nil { |
- st.Frames = append(st.Frames, FullStackFrame(match[1], match[2], common.UNKNOWN_FUNCTION, safeParseInt(match[3]))) |
- } |
- return st |
-} |