No public description

PiperOrigin-RevId: 785894200
diff --git a/centipede/runner.cc b/centipede/runner.cc
index d998350..416d8cb 100644
--- a/centipede/runner.cc
+++ b/centipede/runner.cc
@@ -386,8 +386,7 @@
 // If `full_clear==true` clear all coverage anyway - useful to remove the
 // coverage accumulated during startup.
 __attribute__((noinline))  // so that we see it in profile.
-static void
-PrepareCoverage(bool full_clear) {
+static void PrepareCoverage(bool full_clear) {
   state.CleanUpDetachedTls();
   if (state.run_time_flags.path_level != 0) {
     state.ForEachTls([](ThreadLocalRunnerState &tls) {
@@ -445,12 +444,14 @@
 // Adds a kPCs and/or k8bitCounters feature to `g_features` based on arguments.
 // `idx` is a pc_index.
 // `counter_value` (non-zero) is a counter value associated with that PC.
-static void AddPcIndxedAndCounterToFeatures(size_t idx, uint8_t counter_value) {
+static void AddPcIndxedAndCounterToFeatures(
+    size_t idx, uint8_t counter_value,
+    const std::function<void(feature_t)> &feature_handler) {
   if (state.run_time_flags.use_pc_features) {
-    MaybeAddFeature(feature_domains::kPCs.ConvertToMe(idx));
+    feature_handler(feature_domains::kPCs.ConvertToMe(idx));
   }
   if (state.run_time_flags.use_counter_features) {
-    MaybeAddFeature(feature_domains::k8bitCounters.ConvertToMe(
+    feature_handler(feature_domains::k8bitCounters.ConvertToMe(
         Convert8bitCounterToNumber(idx, counter_value)));
   }
 }
@@ -463,66 +464,72 @@
 // LibFuzzer supports this return value as of 2022-07:
 // https://llvm.org/docs/LibFuzzer.html#rejecting-unwanted-inputs
 __attribute__((noinline))  // so that we see it in profile.
-static void
-PostProcessCoverage(int target_return_value) {
+static void PostProcessCoverage(int target_return_value) {
   state.g_features.clear();
 
-  if (target_return_value == -1) return;
+  std::function<void(feature_t)> feature_handler = MaybeAddFeature;
+  if (target_return_value == -1) {
+    // When suppressing a test, still iterate through all of the features as a
+    // side effect of iteration is zeroing them out.  But don't write the
+    // features anywhere.
+    feature_handler = [](feature_t feature) {};
+  }
 
   // Convert counters to features.
   state.pc_counter_set.ForEachNonZeroByte(
-      [](size_t idx, uint8_t value) {
-        AddPcIndxedAndCounterToFeatures(idx, value);
+      [&feature_handler](size_t idx, uint8_t value) {
+        AddPcIndxedAndCounterToFeatures(idx, value, feature_handler);
       },
       0, state.actual_pc_counter_set_size_aligned);
 
   // Convert data flow bit set to features.
   if (state.run_time_flags.use_dataflow_features) {
-    state.data_flow_feature_set.ForEachNonZeroBit([](size_t idx) {
-      MaybeAddFeature(feature_domains::kDataFlow.ConvertToMe(idx));
-    });
+    state.data_flow_feature_set.ForEachNonZeroBit(
+        [&feature_handler](size_t idx) {
+          feature_handler(feature_domains::kDataFlow.ConvertToMe(idx));
+        });
   }
 
   // Convert cmp bit set to features.
   if (state.run_time_flags.use_cmp_features) {
     // TODO(kcc): remove cmp_feature_set.
-    state.cmp_feature_set.ForEachNonZeroBit([](size_t idx) {
-      MaybeAddFeature(feature_domains::kCMP.ConvertToMe(idx));
+    state.cmp_feature_set.ForEachNonZeroBit([&feature_handler](size_t idx) {
+      feature_handler(feature_domains::kCMP.ConvertToMe(idx));
     });
-    state.cmp_eq_set.ForEachNonZeroBit([](size_t idx) {
-      MaybeAddFeature(feature_domains::kCMPEq.ConvertToMe(idx));
+    state.cmp_eq_set.ForEachNonZeroBit([&feature_handler](size_t idx) {
+      feature_handler(feature_domains::kCMPEq.ConvertToMe(idx));
     });
-    state.cmp_moddiff_set.ForEachNonZeroBit([](size_t idx) {
-      MaybeAddFeature(feature_domains::kCMPModDiff.ConvertToMe(idx));
+    state.cmp_moddiff_set.ForEachNonZeroBit([&feature_handler](size_t idx) {
+      feature_handler(feature_domains::kCMPModDiff.ConvertToMe(idx));
     });
-    state.cmp_hamming_set.ForEachNonZeroBit([](size_t idx) {
-      MaybeAddFeature(feature_domains::kCMPHamming.ConvertToMe(idx));
+    state.cmp_hamming_set.ForEachNonZeroBit([&feature_handler](size_t idx) {
+      feature_handler(feature_domains::kCMPHamming.ConvertToMe(idx));
     });
-    state.cmp_difflog_set.ForEachNonZeroBit([](size_t idx) {
-      MaybeAddFeature(feature_domains::kCMPDiffLog.ConvertToMe(idx));
+    state.cmp_difflog_set.ForEachNonZeroBit([&feature_handler](size_t idx) {
+      feature_handler(feature_domains::kCMPDiffLog.ConvertToMe(idx));
     });
   }
 
   // Convert path bit set to features.
   if (state.run_time_flags.path_level != 0) {
-    state.path_feature_set.ForEachNonZeroBit([](size_t idx) {
-      MaybeAddFeature(feature_domains::kBoundedPath.ConvertToMe(idx));
+    state.path_feature_set.ForEachNonZeroBit([&feature_handler](size_t idx) {
+      feature_handler(feature_domains::kBoundedPath.ConvertToMe(idx));
     });
   }
 
   // Iterate all threads and get features from TLS data.
-  state.ForEachTls([](ThreadLocalRunnerState &tls) {
+  state.ForEachTls([&feature_handler](ThreadLocalRunnerState &tls) {
     if (state.run_time_flags.callstack_level != 0) {
       RunnerCheck(tls.top_frame_sp >= tls.lowest_sp,
                   "bad values of tls.top_frame_sp and tls.lowest_sp");
       size_t sp_diff = tls.top_frame_sp - tls.lowest_sp;
-      MaybeAddFeature(feature_domains::kCallStack.ConvertToMe(sp_diff));
+      feature_handler(feature_domains::kCallStack.ConvertToMe(sp_diff));
     }
   });
 
   if (state.run_time_flags.callstack_level != 0) {
-    state.callstack_set.ForEachNonZeroBit([](size_t idx) {
-      MaybeAddFeature(feature_domains::kCallStack.ConvertToMe(idx));
+    state.callstack_set.ForEachNonZeroBit([&feature_handler](size_t idx) {
+      feature_handler(feature_domains::kCallStack.ConvertToMe(idx));
     });
   }
 
@@ -538,7 +545,7 @@
       // available. If a user domain ID is out of range, alias it to an existing
       // domain. This is kinder than silently dropping the feature.
       user_domain_id %= std::size(feature_domains::kUserDomains);
-      MaybeAddFeature(feature_domains::kUserDomains[user_domain_id].ConvertToMe(
+      feature_handler(feature_domains::kUserDomains[user_domain_id].ConvertToMe(
           user_feature_id));
       *p = 0;  // cleanup for the next iteration.
     }
@@ -549,8 +556,8 @@
   if (state.run_time_flags.use_pc_features ||
       state.run_time_flags.use_counter_features) {
     state.sancov_objects.ForEachNonZeroInlineCounter(
-        [](size_t idx, uint8_t counter_value) {
-          AddPcIndxedAndCounterToFeatures(idx, counter_value);
+        [&feature_handler](size_t idx, uint8_t counter_value) {
+          AddPcIndxedAndCounterToFeatures(idx, counter_value, feature_handler);
         });
   }
 }
@@ -654,9 +661,8 @@
 // Runs one input provided in file `input_path`.
 // Produces coverage data in file `input_path`-features.
 __attribute__((noinline))  // so that we see it in profile.
-static void
-ReadOneInputExecuteItAndDumpCoverage(const char *input_path,
-                                     RunnerCallbacks &callbacks) {
+static void ReadOneInputExecuteItAndDumpCoverage(const char *input_path,
+                                                 RunnerCallbacks &callbacks) {
   // Read the input.
   auto data = ReadBytesFromFilePath<uint8_t>(input_path);