Index: fuzzer/go/frontend/data/stacktrace_test.go |
diff --git a/fuzzer/go/frontend/data/stacktrace_test.go b/fuzzer/go/frontend/data/stacktrace_test.go |
index 0ece3f6c6d98e1187e008094a6d7e5c940786b2e..65f1f6d45dc19265469c1f920d2f7c799c9c276f 100644 |
--- a/fuzzer/go/frontend/data/stacktrace_test.go |
+++ b/fuzzer/go/frontend/data/stacktrace_test.go |
@@ -3,14 +3,16 @@ package data |
import ( |
"path/filepath" |
"reflect" |
+ "strings" |
"testing" |
+ "go.skia.org/infra/fuzzer/go/common" |
"go.skia.org/infra/go/testutils" |
) |
func TestParseReleaseDump(t *testing.T) { |
testInput := testutils.MustReadFile("parse-catchsegv-release.dump") |
- trace := ParseStackTrace(testInput) |
+ trace := parseCatchsegvStackTrace(testInput) |
expected := StackTrace{ |
Frames: []StackTraceFrame{ |
FullStackFrame("src/core/", "SkReadBuffer.cpp", "readFlattenable", 344), |
@@ -33,7 +35,7 @@ func TestParseReleaseDump(t *testing.T) { |
func TestParseDebugDump(t *testing.T) { |
testInput := testutils.MustReadFile("parse-catchsegv-debug.dump") |
- trace := ParseStackTrace(testInput) |
+ trace := parseCatchsegvStackTrace(testInput) |
expected := StackTrace{ |
Frames: []StackTraceFrame{ |
@@ -64,7 +66,7 @@ func TestParseDebugDump(t *testing.T) { |
func TestParsingEdgeCases(t *testing.T) { |
// This is a made up dump that has the edge cases for parsing function names. |
testInput := testutils.MustReadFile("parse-catchsegv-edge.dump") |
- trace := ParseStackTrace(testInput) |
+ trace := parseCatchsegvStackTrace(testInput) |
expected := StackTrace{ |
Frames: []StackTraceFrame{ |
FullStackFrame("src/codec/", "SkMasks.cpp", "convert_to_8", 54), |
@@ -84,8 +86,54 @@ func TestParsingEdgeCases(t *testing.T) { |
} |
} |
+func TestParseASANSingle(t *testing.T) { |
+ testInput := testutils.MustReadFile("parse-asan-single.asan") |
+ |
+ trace := parseASANStackTrace(testInput) |
+ |
+ expected := StackTrace{ |
+ Frames: []StackTraceFrame{ |
+ FullStackFrame("src/codec/", "SkMasks.cpp", "convert_to_8", 54), |
+ FullStackFrame("src/codec/", "SkMaskSwizzler.cpp", "swizzle_mask24_to_n32_opaque", 93), |
+ FullStackFrame("src/codec/", "SkBmpMaskCodec.cpp", "SkBmpMaskCodec::decodeRows", 103), |
+ FullStackFrame("src/codec/", "SkBmpMaskCodec.cpp", "SkBmpMaskCodec::onGetPixels", 53), |
+ FullStackFrame("src/codec/", "SkCodec.cpp", "SkCodec::getPixels", 204), |
+ FullStackFrame("fuzz/", "fuzz.cpp", "fuzz_img", 119), |
+ FullStackFrame("fuzz/", "fuzz.cpp", "main", 53), |
+ }, |
+ } |
+ |
+ if !reflect.DeepEqual(expected, trace) { |
+ t.Errorf("Expected %#v\nbut was %#v", expected, trace) |
+ t.Errorf("Expected %s \n but was %s", expected.String(), trace.String()) |
+ } |
+} |
+ |
+func TestParseASANDouble(t *testing.T) { |
+ testInput := testutils.MustReadFile("parse-asan-double.asan") |
+ |
+ trace := parseASANStackTrace(testInput) |
+ |
+ expected := StackTrace{ |
+ Frames: []StackTraceFrame{ |
+ FullStackFrame("src/core/", "SkReader32.h", "SkReader32::readInt_asan", 57), |
+ FullStackFrame("src/core/", "SkPicturePlayback.cpp", "SkPicturePlayback::handleOp", 151), |
+ FullStackFrame("src/core/", "SkPicturePlayback.cpp", "SkPicturePlayback::draw", 111), |
+ FullStackFrame("src/core/", "SkPicture.cpp", "SkPicture::Forwardport", 137), |
+ FullStackFrame("src/core/", "SkPicture.cpp", "SkPicture::CreateFromStream", 154), |
+ FullStackFrame("fuzz/", "fuzz.cpp", "fuzz_skp", 143), |
+ FullStackFrame("fuzz/", "fuzz.cpp", "main", 54), |
+ }, |
+ } |
+ |
+ if !reflect.DeepEqual(expected, trace) { |
+ t.Errorf("Expected %#v\nbut was %#v", expected, trace) |
+ t.Errorf("Expected %s \n but was %s", expected.String(), trace.String()) |
+ } |
+} |
+ |
func TestParseEmptyStackTrace(t *testing.T) { |
- trace := ParseStackTrace("") |
+ trace := parseCatchsegvStackTrace("") |
if !trace.IsEmpty() { |
t.Errorf("Expected stacktrace to be empty but was %#v", trace) |
@@ -95,3 +143,294 @@ func TestParseEmptyStackTrace(t *testing.T) { |
func stacktrace(file string) string { |
return filepath.Join("stacktrace", file) |
} |
+ |
+func TestParseGCSPackage_Grey(t *testing.T) { |
+ // Everything was successful or partially successful |
+ g := GCSPackage{ |
+ Debug: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("0grey_debug.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("0grey_debug.err")), |
+ }, |
+ Release: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("0grey_release.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("0grey_release.err")), |
+ }, |
+ FuzzCategory: "skcodec", |
+ } |
+ |
+ result := ParseGCSPackage(g) |
+ expectedDebugFlags := TerminatedGracefully |
+ expectedReleaseFlags := TerminatedGracefully |
+ if result.Debug.Flags != expectedDebugFlags { |
+ t.Errorf("Parsed Debug flags were wrong. Expected %s, but was %s", expectedDebugFlags.String(), result.Debug.Flags.String()) |
+ } |
+ if result.Release.Flags != expectedReleaseFlags { |
+ t.Errorf("Parsed Release flags were wrong. Expected %s, but was %s", expectedReleaseFlags.String(), result.Release.Flags.String()) |
+ } |
+ if !result.Debug.StackTrace.IsEmpty() { |
+ t.Errorf("Should have had empty debug stacktrace, but was %s", result.Debug.StackTrace.String()) |
+ } |
+ if !result.Release.StackTrace.IsEmpty() { |
+ t.Errorf("Should have had empty release stacktrace, but was %s", result.Release.StackTrace.String()) |
+ } |
+} |
+ |
+// For the following tests, I added the suffix _asan and _dump to the top stacktrace line in the |
+// raw files, so we can tell where the stacktrace is being parsed from easily, if there are two |
+// possibilities. The analysis should try to reason about the AddressSanitizer output, with a |
+// fallback to the catchsegv debug/err output. |
+ |
+func TestParseGCSPackage_GlobalStackOverflow(t *testing.T) { |
+ // Both debug/release crashed with a stackoverflow. |
+ g := GCSPackage{ |
+ Debug: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("1bad_debug.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("1grey_debug.err")), |
+ }, |
+ Release: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("1bad_release.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("1grey_release.err")), |
+ }, |
+ FuzzCategory: "skcodec", |
+ } |
+ |
+ result := ParseGCSPackage(g) |
+ expectedDebugFlags := ASANCrashed | ASAN_GlobalBufferOverflow |
+ expectedReleaseFlags := ASANCrashed | ASAN_GlobalBufferOverflow |
+ if result.Debug.Flags != expectedDebugFlags { |
+ t.Errorf("Parsed Debug flags were wrong. Expected %s, but was %s", expectedDebugFlags.String(), result.Debug.Flags.String()) |
+ } |
+ if result.Release.Flags != expectedReleaseFlags { |
+ t.Errorf("Parsed Release flags were wrong. Expected %s, but was %s", expectedReleaseFlags.String(), result.Release.Flags.String()) |
+ } |
+ // There was no catchsegv dump, so only one possibility for stacktrace for both of these. |
+ if result.Debug.StackTrace.IsEmpty() { |
+ t.Errorf("Should not have had empty debug stacktrace") |
+ } |
+ if result.Release.StackTrace.IsEmpty() { |
+ t.Errorf("Should not have had empty release stacktrace") |
+ } |
+} |
+ |
+func TestParseGCSPackage_AssertDuringRendering(t *testing.T) { |
+ // Debug assert hit. Release heap buffer overflow |
+ g := GCSPackage{ |
+ Debug: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("2bad_debug.asan")), |
+ Dump: testutils.MustReadFile(stacktrace("2bad_debug.dump")), |
+ StdErr: testutils.MustReadFile(stacktrace("2bad_debug.err")), |
+ }, |
+ Release: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("2bad_release.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("2grey_release.err")), |
+ }, |
+ FuzzCategory: "skpicture", |
+ } |
+ |
+ result := ParseGCSPackage(g) |
+ expectedDebugFlags := ASANCrashed | ClangCrashed | AssertionViolated |
+ expectedReleaseFlags := ASANCrashed | ASAN_HeapBufferOverflow | SKPICTURE_DuringRendering |
+ if result.Debug.Flags != expectedDebugFlags { |
+ t.Errorf("Parsed Debug flags were wrong. Expected %s, but was %s", expectedDebugFlags.String(), result.Debug.Flags.String()) |
+ } |
+ if result.Release.Flags != expectedReleaseFlags { |
+ t.Errorf("Parsed Release flags were wrong. Expected %s, but was %s", expectedReleaseFlags.String(), result.Release.Flags.String()) |
+ } |
+ stack := result.Debug.StackTrace |
+ if stack.IsEmpty() { |
+ t.Errorf("Should not have had empty debug stacktrace") |
+ } else { |
+ if !strings.HasSuffix(stack.Frames[0].FunctionName, "_asan") { |
+ t.Errorf("Should have parsed stacktrace from asan: \n%s", stack.String()) |
+ } |
+ } |
+ // There was no catchsegv dump, so only one possibility for stacktrace. |
+ if result.Release.StackTrace.IsEmpty() { |
+ t.Errorf("Should not have had empty release stacktrace") |
+ } |
+} |
+ |
+func TestParseGCSPackage_UseAfterFree(t *testing.T) { |
+ // Debug ClangCrashed. Release heap use after free. |
+ g := GCSPackage{ |
+ Debug: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("3grey_debug.asan")), |
+ Dump: testutils.MustReadFile(stacktrace("3bad_debug.dump")), |
+ StdErr: "", |
+ }, |
+ Release: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("3bad_release.asan")), |
+ Dump: testutils.MustReadFile(stacktrace("3bad_release.dump")), |
+ StdErr: "", |
+ }, |
+ FuzzCategory: "skpicture", |
+ } |
+ |
+ result := ParseGCSPackage(g) |
+ expectedDebugFlags := ClangCrashed |
+ expectedReleaseFlags := ASANCrashed | ClangCrashed | ASAN_HeapUseAfterFree |
+ if result.Debug.Flags != expectedDebugFlags { |
+ t.Errorf("Parsed Debug flags were wrong. Expected %s, but was %s", expectedDebugFlags.String(), result.Debug.Flags.String()) |
+ } |
+ if result.Release.Flags != expectedReleaseFlags { |
+ t.Errorf("Parsed Release flags were wrong. Expected %s, but was %s", expectedReleaseFlags.String(), result.Release.Flags.String()) |
+ } |
+ stack := result.Debug.StackTrace |
+ // There was no asan dump, so only one possibility for stacktrace. |
+ if stack.IsEmpty() { |
+ t.Errorf("Should not have had empty debug stacktrace") |
+ } |
+ stack = result.Release.StackTrace |
+ if stack.IsEmpty() { |
+ t.Errorf("Should not have had empty release stacktrace") |
+ } else { |
+ if !strings.HasSuffix(stack.Frames[0].FunctionName, "_asan") { |
+ t.Errorf("Should have parsed stacktrace from asan: \n%s", stack.String()) |
+ } |
+ } |
+} |
+ |
+func TestParseGCSPackage_TimeOut(t *testing.T) { |
+ // Everything timed out on analysis |
+ g := GCSPackage{ |
+ Debug: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("4bad_debug.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("4bad_debug.err")), |
+ }, |
+ Release: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("4bad_release.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("4bad_release.err")), |
+ }, |
+ FuzzCategory: "skcodec", |
+ } |
+ |
+ result := ParseGCSPackage(g) |
+ expectedDebugFlags := TimedOut |
+ expectedReleaseFlags := TimedOut |
+ if result.Debug.Flags != expectedDebugFlags { |
+ t.Errorf("Parsed Debug flags were wrong. Expected %s, but was %s", expectedDebugFlags.String(), result.Debug.Flags.String()) |
+ } |
+ if result.Release.Flags != expectedReleaseFlags { |
+ t.Errorf("Parsed Release flags were wrong. Expected %s, but was %s", expectedReleaseFlags.String(), result.Release.Flags.String()) |
+ } |
+ if !result.Debug.StackTrace.IsEmpty() { |
+ t.Errorf("Should have had empty debug stacktrace, but was %s", result.Debug.StackTrace.String()) |
+ } |
+ if !result.Release.StackTrace.IsEmpty() { |
+ t.Errorf("Should have had empty release stacktrace, but was %s", result.Release.StackTrace.String()) |
+ } |
+} |
+ |
+func TestParseGCSPackage_BadAlloc(t *testing.T) { |
+ // Everything was a bad:alloc |
+ g := GCSPackage{ |
+ Debug: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("5bad_debug.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("5bad_debug.err")), |
+ }, |
+ Release: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("5bad_release.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("5bad_release.err")), |
+ }, |
+ FuzzCategory: "skcodec", |
+ } |
+ |
+ result := ParseGCSPackage(g) |
+ expectedDebugFlags := BadAlloc | ASANCrashed | ClangCrashed |
+ expectedReleaseFlags := BadAlloc | ASANCrashed | ClangCrashed |
+ if result.Debug.Flags != expectedDebugFlags { |
+ t.Errorf("Parsed Debug flags were wrong. Expected %s, but was %s", expectedDebugFlags.String(), result.Debug.Flags.String()) |
+ } |
+ if result.Release.Flags != expectedReleaseFlags { |
+ t.Errorf("Parsed Release flags were wrong. Expected %s, but was %s", expectedReleaseFlags.String(), result.Release.Flags.String()) |
+ } |
+ if result.Debug.StackTrace.IsEmpty() { |
+ t.Errorf("Should not have had empty debug stacktrace") |
+ } |
+ if result.Release.StackTrace.IsEmpty() { |
+ t.Errorf("Should not have had empty release stacktrace") |
+ } |
+} |
+ |
+func TestParseGCSPackage_EmptyStacktrace(t *testing.T) { |
+ // According to AddressSanitizer, both crashed while trying to report a bug. |
+ g := GCSPackage{ |
+ Debug: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("6bad_debug.asan")), |
+ Dump: testutils.MustReadFile(stacktrace("6bad_debug.dump")), |
+ StdErr: testutils.MustReadFile(stacktrace("6bad_debug.err")), |
+ }, |
+ Release: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("6bad_release.asan")), |
+ Dump: testutils.MustReadFile(stacktrace("6bad_release.dump")), |
+ StdErr: testutils.MustReadFile(stacktrace("6bad_release.err")), |
+ }, |
+ FuzzCategory: "skcodec", |
+ } |
+ |
+ result := ParseGCSPackage(g) |
+ expectedDebugFlags := NoStackTrace | ASANCrashed | ClangCrashed |
+ expectedReleaseFlags := NoStackTrace | ASANCrashed | ClangCrashed |
+ if result.Debug.Flags != expectedDebugFlags { |
+ t.Errorf("Parsed Debug flags were wrong. Expected %s, but was %s", expectedDebugFlags.String(), result.Debug.Flags.String()) |
+ } |
+ if result.Release.Flags != expectedReleaseFlags { |
+ t.Errorf("Parsed Release flags were wrong. Expected %s, but was %s", expectedReleaseFlags.String(), result.Release.Flags.String()) |
+ } |
+ if !result.Debug.StackTrace.IsEmpty() { |
+ t.Errorf("Should have had empty debug stacktrace") |
+ } |
+ if !result.Release.StackTrace.IsEmpty() { |
+ t.Errorf("Should have had empty release stacktrace") |
+ } |
+} |
+ |
+func TestParseGCSPackage_SKAbort(t *testing.T) { |
+ // Both hit SK_ABORT somewhere. |
+ g := GCSPackage{ |
+ Debug: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("7bad_debug.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("7bad_debug.err")), |
+ }, |
+ Release: OutputFiles{ |
+ Asan: testutils.MustReadFile(stacktrace("7bad_release.asan")), |
+ Dump: "", |
+ StdErr: testutils.MustReadFile(stacktrace("7bad_release.err")), |
+ }, |
+ FuzzCategory: "skpicture", |
+ } |
+ |
+ result := ParseGCSPackage(g) |
+ expectedDebugFlags := SKAbortHit | ASANCrashed | ClangCrashed |
+ expectedReleaseFlags := SKAbortHit | ASANCrashed | ClangCrashed |
+ if result.Debug.Flags != expectedDebugFlags { |
+ t.Errorf("Parsed Debug flags were wrong. Expected %s, but was %s", expectedDebugFlags.String(), result.Debug.Flags.String()) |
+ } |
+ if result.Release.Flags != expectedReleaseFlags { |
+ t.Errorf("Parsed Release flags were wrong. Expected %s, but was %s", expectedReleaseFlags.String(), result.Release.Flags.String()) |
+ } |
+ if len(result.Debug.StackTrace.Frames) != 1 { |
+ t.Fatalf("Should have filled in top frame of trace") |
+ } |
+ expected := FullStackFrame("src/core/", "SkPictureData.cpp", common.UNKNOWN_FUNCTION, 360) |
+ if frame := result.Debug.StackTrace.Frames[0]; frame.LineNumber != expected.LineNumber || frame.FunctionName != expected.FunctionName || frame.FileName != expected.FileName || frame.PackageName != expected.PackageName { |
+ t.Errorf("Top frame was wrong. Expected: %#v, but was %#v", expected, frame) |
+ } |
+ |
+ if len(result.Release.StackTrace.Frames) != 1 { |
+ t.Errorf("Should not have had empty release stacktrace") |
+ } |
+ if frame := result.Release.StackTrace.Frames[0]; frame.LineNumber != expected.LineNumber || frame.FunctionName != expected.FunctionName || frame.FileName != expected.FileName || frame.PackageName != expected.PackageName { |
+ t.Errorf("Top frame was wrong. Expected: %#v, but was %#v", expected, frame) |
+ } |
+} |