Process the execution metadata when finalizing coverage.

This avoids noise (from the framework integration) between finalizing coverage and sending it out.

PiperOrigin-RevId: 791691734
diff --git a/centipede/runner.cc b/centipede/runner.cc
index ff98a27..2e73d85 100644
--- a/centipede/runner.cc
+++ b/centipede/runner.cc
@@ -454,9 +454,10 @@
     return false;
   }
 
-  ExecutionMetadata metadata;
-  if (!CopyCmpTracesToMetadata(&metadata)) return false;
-  if (!BatchResult::WriteMetadata(metadata, outputs_blobseq)) return false;
+  if (!BatchResult::WriteMetadata(SanCovRuntimeGetExecutionMetadata(),
+                                  outputs_blobseq)) {
+    return false;
+  }
 
   // Write the stats.
   if (!BatchResult::WriteStats(state->stats, outputs_blobseq)) return false;
diff --git a/centipede/sancov_state.cc b/centipede/sancov_state.cc
index 5360ba8..25bcd73 100644
--- a/centipede/sancov_state.cc
+++ b/centipede/sancov_state.cc
@@ -356,8 +356,31 @@
   }
 }
 
+// Calls ExecutionMetadata::AppendCmpEntry for every CMP arg pair
+// found in `cmp_trace`.
+// Returns true if all appending succeeded.
+// "noinline" so that we see it in a profile, if it becomes hot.
+template <typename CmpTrace>
+__attribute__((noinline)) void AppendCmpEntries(CmpTrace& cmp_trace,
+                                                ExecutionMetadata& metadata) {
+  cmp_trace.ForEachNonZero(
+      [&](uint8_t size, const uint8_t* v0, const uint8_t* v1) {
+        (void)metadata.AppendCmpEntry({v0, size}, {v1, size});
+      });
+}
+
 void PostProcessSancov(bool reject_input) {
   sancov_state->g_features.clear();
+  sancov_state->metadata.cmp_data.clear();
+
+  if (sancov_state->flags.use_auto_dictionary && !reject_input) {
+    sancov_state->ForEachTls([](ThreadLocalSancovState& tls) {
+      AppendCmpEntries(tls.cmp_trace2, sancov_state->metadata);
+      AppendCmpEntries(tls.cmp_trace4, sancov_state->metadata);
+      AppendCmpEntries(tls.cmp_trace8, sancov_state->metadata);
+      AppendCmpEntries(tls.cmp_traceN, sancov_state->metadata);
+    });
+  }
 
   std::function<void(feature_t)> feature_handler = MaybeAddFeature;
   if (reject_input) {
@@ -461,46 +484,15 @@
   }
 }
 
-// Calls ExecutionMetadata::AppendCmpEntry for every CMP arg pair
-// found in `cmp_trace`.
-// Returns true if all appending succeeded.
-// "noinline" so that we see it in a profile, if it becomes hot.
-template <typename CmpTrace>
-__attribute__((noinline)) bool AppendCmpEntries(CmpTrace &cmp_trace,
-                                                ExecutionMetadata &metadata) {
-  bool append_failed = false;
-  cmp_trace.ForEachNonZero(
-      [&](uint8_t size, const uint8_t *v0, const uint8_t *v1) {
-        if (!metadata.AppendCmpEntry({v0, size}, {v1, size}))
-          append_failed = true;
-      });
-  return !append_failed;
-}
-
-bool CopyCmpTracesToMetadata(ExecutionMetadata *metadata) {
-  if (sancov_state->flags.use_auto_dictionary) {
-    bool append_failed = false;
-    sancov_state->ForEachTls(
-        [&metadata, &append_failed](ThreadLocalSancovState& tls) {
-          if (!AppendCmpEntries(tls.cmp_trace2, *metadata))
-            append_failed = true;
-          if (!AppendCmpEntries(tls.cmp_trace4, *metadata))
-            append_failed = true;
-          if (!AppendCmpEntries(tls.cmp_trace8, *metadata))
-            append_failed = true;
-          if (!AppendCmpEntries(tls.cmp_traceN, *metadata))
-            append_failed = true;
-        });
-    if (append_failed) return false;
-  }
-  return true;
-}
-
 SanCovRuntimeRawFeatureParts SanCovRuntimeGetFeatures() {
   return {fuzztest::internal::sancov_state->g_features.data(),
           fuzztest::internal::sancov_state->g_features.size()};
 }
 
+const ExecutionMetadata& SanCovRuntimeGetExecutionMetadata() {
+  return fuzztest::internal::sancov_state->metadata;
+}
+
 }  // namespace fuzztest::internal
 
 // Can be overridden to not depend explicitly on CENTIPEDE_RUNNER_FLAGS.
diff --git a/centipede/sancov_state.h b/centipede/sancov_state.h
index 8df1c1d..3afb6c4 100644
--- a/centipede/sancov_state.h
+++ b/centipede/sancov_state.h
@@ -251,6 +251,10 @@
   static const size_t kMaxFeatures = 1 << 20;
   // FeatureArray used to accumulate features from all sources.
   FeatureArray<kMaxFeatures> g_features;
+  // Execution metadata gathered by `PostProcessSancov`.
+  //
+  // TODO: b/443264359 - export it in the runtime interface.
+  ExecutionMetadata metadata;
 
   // Features that were seen before.
   static constexpr size_t kSeenFeatureSetSize =
@@ -262,8 +266,6 @@
   feature_t *user_defined_end;
 };
 
-bool CopyCmpTracesToMetadata(ExecutionMetadata *metadata);
-
 // Clears all the thread-local data updated during execution.
 __attribute__((noinline))  // so that we see it in profile.
 void CleanUpSancovTls();
@@ -291,6 +293,9 @@
 // Returns a pointer to `g_features` and its length.
 SanCovRuntimeRawFeatureParts SanCovRuntimeGetFeatures();
 
+// Gets the execution metadata gathered in `PostProcessSancov`.
+const ExecutionMetadata& SanCovRuntimeGetExecutionMetadata();
+
 // Check for stack limit for the stack pointer `sp` in the current thread.
 __attribute__((weak)) void CheckStackLimit(uintptr_t sp);