| 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)
|
| + }
|
| +}
|
|
|