#Centipede Add a flag to skip triaging inputs other than the suspect in a batch.

This makes the crash reporting faster when running a batch (of a single input) is very slow.

PiperOrigin-RevId: 639788747
diff --git a/centipede/centipede.cc b/centipede/centipede.cc
index fcc9827..812cc6e 100644
--- a/centipede/centipede.cc
+++ b/centipede/centipede.cc
@@ -833,17 +833,6 @@
       << log_prefix
       << "Reached --max_num_crash_reports: further reports will be suppressed";
 
-  // Determine the optimal order of the inputs to try to maximize the chances of
-  // finding the reproducer fast.
-  // TODO(b/274705740): When the bug is fixed, set `input_idxs_to_try`'s size to
-  //  `suspect_input_idx + 1`.
-  std::vector<size_t> input_idxs_to_try(input_vec.size() + 1);
-  // Prioritize the presumed crasher by inserting it in front of everything
-  // else. However, do keep it at the old location, too, in case the target was
-  // primed for a crash by the sequence of inputs that preceded the crasher.
-  input_idxs_to_try.front() = suspect_input_idx;
-  std::iota(input_idxs_to_try.begin() + 1, input_idxs_to_try.end(), 0);
-
   if (batch_result.failure_description() == kExecutionFailurePerBatchTimeout) {
     LOG(INFO) << log_prefix
               << "Failure applies to entire batch: not executing inputs "
@@ -851,6 +840,25 @@
     return;
   }
 
+  // Determine the optimal order of the inputs to try to maximize the chances of
+  // finding the reproducer fast.
+  std::vector<size_t> input_idxs_to_try;
+  // Prioritize the presumed crasher by inserting it in front of everything
+  // else.
+  input_idxs_to_try.push_back(suspect_input_idx);
+  if (!env_.batch_triage_suspect_only) {
+    // TODO(b/274705740): When the bug is fixed, set `input_idxs_to_try`'s size
+    // to `suspect_input_idx + 1`.
+    input_idxs_to_try.resize(input_vec.size() + 1);
+    // Keep the suspect at the old location, too, in case the target was
+    // primed for a crash by the sequence of inputs that preceded the crasher.
+    std::iota(input_idxs_to_try.begin() + 1, input_idxs_to_try.end(), 0);
+  } else {
+    LOG(INFO)
+        << log_prefix
+        << "Skip finding the reproducer from the inputs other than the suspect";
+  }
+
   // Try inputs one-by-one in the determined order.
   LOG(INFO) << log_prefix
             << "Executing inputs one-by-one, trying to find the reproducer";
diff --git a/centipede/centipede_test.cc b/centipede/centipede_test.cc
index d4d1adb..afc2e6c 100644
--- a/centipede/centipede_test.cc
+++ b/centipede/centipede_test.cc
@@ -696,11 +696,15 @@
   }
 
   // Doesn't execute anything.
-  // Crash when 0th char of input to binary b1 equals 10, but only on 1st exec.
+  // Crash when 0th char of input to binary b1 equals `crashing_input_idx_`, but
+  // only on 1st exec.
   bool Execute(std::string_view binary, const std::vector<ByteArray> &inputs,
                BatchResult &batch_result) override {
     batch_result.ClearAndResize(inputs.size());
     bool res = true;
+    if (!first_pass_) {
+      num_inputs_triaged_ += inputs.size();
+    }
     for (const auto &input : inputs) {
       CHECK_EQ(input.size(), 1);  // By construction in `Mutate()`.
       // The contents of each mutant is its sequential number.
@@ -739,9 +743,12 @@
   // Gets the input that triggered the crash.
   ByteArray crashing_input() const { return crashing_input_; }
 
+  size_t num_inputs_triaged() const { return num_inputs_triaged_; }
+
  private:
   const size_t crashing_input_idx_;
   size_t curr_input_idx_ = 0;
+  size_t num_inputs_triaged_ = 0;
   ByteArray crashing_input_ = {};
   bool first_pass_ = true;
 };
@@ -768,6 +775,7 @@
   env.batch_size = kBatchSize;
   // No real binary: prevent attempts by Centipede to read a PCtable from it.
   env.require_pc_table = false;
+  env.exit_on_crash = true;
 
   UndetectedCrashingInputMock mock(env, kCrashingInputIdx);
   MockFactory factory(mock);
@@ -783,14 +791,28 @@
                                     .append("crashes")
                                     .append("crashing_batch-")
                                     .concat(crashing_input_hash);
-  ASSERT_TRUE(std::filesystem::exists(crashes_dir_path)) << crashes_dir_path;
+  EXPECT_TRUE(std::filesystem::exists(crashes_dir_path)) << crashes_dir_path;
   std::vector<std::string> found_crash_file_names;
   for (auto const &dir_ent :
        std::filesystem::directory_iterator(crashes_dir_path)) {
     found_crash_file_names.push_back(dir_ent.path().filename());
   }
   // TODO(ussuri): Verify exact names/contents of the files, not just count.
-  ASSERT_EQ(found_crash_file_names.size(), kCrashingInputIdxInBatch + 1);
+  EXPECT_EQ(found_crash_file_names.size(), kCrashingInputIdxInBatch + 1);
+  // Suspected input first, then every input in the batch (including the
+  // suspected input again).
+  EXPECT_EQ(mock.num_inputs_triaged(), kBatchSize + 1);
+
+  // Verify that when `env.batch_triage_suspect_only` is set, only triage the
+  // suspect.
+  TempDir suspect_only_temp_dir{test_info_->name()};
+  env.workdir = suspect_only_temp_dir.path();
+  env.batch_triage_suspect_only = true;
+  UndetectedCrashingInputMock suspect_only_mock(env, kCrashingInputIdx);
+  MockFactory suspect_only_factory(suspect_only_mock);
+  CentipedeMain(env, suspect_only_factory);
+
+  EXPECT_EQ(suspect_only_mock.num_inputs_triaged(), 1);
 }
 
 TEST(Centipede, GetsSeedInputs) {
diff --git a/centipede/environment.h b/centipede/environment.h
index 391ded1..47f4db6 100644
--- a/centipede/environment.h
+++ b/centipede/environment.h
@@ -96,6 +96,7 @@
   bool exit_on_crash = false;
   size_t max_num_crash_reports = 5;
   std::string minimize_crash_file_path;
+  bool batch_triage_suspect_only = false;
   size_t shmem_size_mb = 1024;
   bool use_posix_shmem = false;
   bool dry_run = false;
diff --git a/centipede/environment_flags.cc b/centipede/environment_flags.cc
index a571d4c..8e3701a 100644
--- a/centipede/environment_flags.cc
+++ b/centipede/environment_flags.cc
@@ -311,6 +311,10 @@
           " inputs in workdir/crashes/."
           " --num_runs and --num_threads apply. "
           " Assumes local workdir.");
+ABSL_FLAG(bool, batch_triage_suspect_only,
+          default_env->batch_triage_suspect_only,
+          "If set, triage the crash on only the suspected input in a crashing "
+          "batch. Otherwise, triage on all the executed inputs");
 ABSL_FLAG(std::string, input_filter, default_env->input_filter,
           "Path to a tool that filters bad inputs. The tool is invoked as "
           "`input_filter INPUT_FILE` and should return 0 if the input is good "
@@ -506,6 +510,8 @@
       .exit_on_crash = absl::GetFlag(FLAGS_exit_on_crash),
       .max_num_crash_reports = absl::GetFlag(FLAGS_num_crash_reports),
       .minimize_crash_file_path = absl::GetFlag(FLAGS_minimize_crash),
+      .batch_triage_suspect_only =
+          absl::GetFlag(FLAGS_batch_triage_suspect_only),
       .shmem_size_mb = absl::GetFlag(FLAGS_shmem_size_mb),
       .use_posix_shmem = absl::GetFlag(FLAGS_use_posix_shmem),
       .dry_run = absl::GetFlag(FLAGS_dry_run),