[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```")
+}