[fuzz] Handle missing fuzzing passes in '-triage' If the tool is unable to determine the fuzzing pass the failure is in, just report what it can, instead of bailing. Fixes: 524008579 Change-Id: I0766e974718b4489fb1bf350450284b75f944a51 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/316996 Commit-Queue: Ryan Harrison <rharrison@chromium.org> Auto-Submit: Ryan Harrison <rharrison@chromium.org> Reviewed-by: James Price <jrprice@google.com> Commit-Queue: James Price <jrprice@google.com> Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/tools/src/cmd/fuzz/triage.go b/tools/src/cmd/fuzz/triage.go index 9335c77..3408056 100644 --- a/tools/src/cmd/fuzz/triage.go +++ b/tools/src/cmd/fuzz/triage.go
@@ -112,7 +112,7 @@ fmt.Println("determining failing pass...") failingPass, err := determineFailingPass(fuzzerOutput) if err != nil { - return err + fmt.Printf("warning: %v\n", err) } tc.failingPass = failingPass @@ -240,10 +240,17 @@ // failing pass with verbose logging and IR dumping enabled. The output is captured and written // to a log file. Returns the verbose output, the filter argument used, and any error. func runSpecificPassAndLog(tc *triageConfig) error { - tc.filterArg = "--filter=" + tc.failingPass + args := []string{"--verbose", "--dump-ir=true"} + if tc.failingPass != "" { + tc.filterArg = "--filter=" + tc.failingPass + args = append(args, tc.filterArg) + } else { + tc.filterArg = "" + } + args = append(args, tc.reproFile) // Ignore command exit status issues (command is expected to crash) - tc.verboseOut, _ = tc.runCmd(tc.fuzzer, "--verbose", "--dump-ir=true", tc.filterArg, tc.reproFile) + tc.verboseOut, _ = tc.runCmd(tc.fuzzer, args...) if err := tc.osWrapper.WriteFile(tc.logFile, tc.verboseOut, 0644); err != nil { return fmt.Errorf("failed to write log file: %w", err) @@ -299,6 +306,33 @@ irDumpDisplay = "```\n" + irDump + "```" } + failingPassDisplay := tc.failingPass + if failingPassDisplay == "" { + failingPassDisplay = "Unknown (failed to identify from fuzzer output)" + } + + failingTransformDisplay := failingTransform + if failingTransformDisplay == "" { + failingTransformDisplay = "Unknown" + } + + transformsRunDisplay := strings.Join(transformsRun, "\n") + if transformsRunDisplay == "" { + transformsRunDisplay = "None" + } + + reproCmdParts := []string{tc.fuzzer, "--verbose", "--dump-ir=true"} + if tc.filterArg != "" { + reproCmdParts = append(reproCmdParts, tc.filterArg) + } + reproCmdParts = append(reproCmdParts, tc.reproFile) + reproCmd := strings.Join(reproCmdParts, " ") + + stackTraceDisplay := stackTrace + if stackTraceDisplay == "" { + stackTraceDisplay = "Unknown (failed to extract stack trace)" + } + report := fmt.Sprintf(`# Triage Report for %s ## Status @@ -316,7 +350,7 @@ %s ## Reproduction Instructions `+"```"+` -%s --verbose --dump-ir=true %s %s +%s `+"```"+` ## Failing Pass @@ -345,13 +379,13 @@ tc.triageFile, tc.reproFile, tc.reproStatus.NoteString(), tc.inputsDisplay, - tc.fuzzer, tc.filterArg, tc.reproFile, - tc.failingPass, - strings.Join(transformsRun, "\n"), - failingTransform, + reproCmd, + failingPassDisplay, + transformsRunDisplay, + failingTransformDisplay, irDumpStatus, irDumpDisplay, - stackTrace) + stackTraceDisplay) fmt.Println("\n--- TRIAGE REPORT ---") fmt.Println(report)
diff --git a/tools/src/cmd/fuzz/triage_test.go b/tools/src/cmd/fuzz/triage_test.go index 7192b28..c079aed 100644 --- a/tools/src/cmd/fuzz/triage_test.go +++ b/tools/src/cmd/fuzz/triage_test.go
@@ -157,3 +157,46 @@ require.Contains(t, reportStr, "## IR Dump before failure\n\n```\n$B1: {\n # Root block - modified\n}\n```") require.Contains(t, reportStr, "## Crash Stack\n```\n#0 0x12345 in __sanitizer_print_stack_trace\n") } + +func TestGenerateTriageReportResilience(t *testing.T) { + wrapper := oswrapper.CreateFSTestOSWrapper() + + tc := &triageConfig{ + taskConfig: &taskConfig{ + mainConfig: mainConfig{ + osWrapper: wrapper, + triageFile: "some-crash-file", + fuzzMode: FuzzModeIr, + }, + fuzzer: "tint_ir_fuzzer", + }, + inputBase: "some-crash-file", + reproFile: "some-crash-file.repro", + logFile: "some-crash-file.triage.log", + reportFile: "some-crash-file.triage.md", + reproStatus: ReproStatusIdentical, + inputsDisplay: "## IR Input\n```\n$B1: { ... }\n```\n", + irInput: "$B1: { ... }", + failingPass: "", // Empty failing pass + verboseOut: []byte(`just some random logs without ir dump or backtrace`), + filterArg: "", // Empty filterArg + } + + err := generateTriageReport(tc) + require.NoError(t, err) + + // Verify that the report file was created + content, err := wrapper.ReadFile("some-crash-file.triage.md") + require.NoError(t, err) + reportStr := string(content) + + // Check for key resilience features of our triage report structure + require.Contains(t, reportStr, "# Triage Report for some-crash-file") + require.Contains(t, reportStr, "## Reproduction Instructions") + // Should not have --filter, and should have single spaces + require.Contains(t, reportStr, "tint_ir_fuzzer --verbose --dump-ir=true some-crash-file.repro") + require.Contains(t, reportStr, "## Failing Pass\n`Unknown (failed to identify from fuzzer output)`") + require.Contains(t, reportStr, "## Transforms Run\n```\nNone\n```") + require.Contains(t, reportStr, "## Failing Transform\n`Unknown`") + require.Contains(t, reportStr, "## Crash Stack\n```\nUnknown (failed to extract stack trace)\n```") +}