No public description

PiperOrigin-RevId: 950952865
diff --git a/centipede/byte_array_mutator.cc b/centipede/byte_array_mutator.cc
index fc2597d..ee6b7e6 100644
--- a/centipede/byte_array_mutator.cc
+++ b/centipede/byte_array_mutator.cc
@@ -33,7 +33,7 @@
 //============= CmpDictionary ===============
 bool CmpDictionary::SetFromMetadata(const ExecutionMetadata &metadata) {
   dictionary_.clear();
-  if (!metadata.ForEachCmpEntry([&](ByteSpan a, ByteSpan b) {
+  if (!metadata.ForEachCmpEntry([&](ByteSpan a, ByteSpan b, bool) {
         auto size = a.size();
         if (size > DictEntry::kMaxEntrySize) return;
         if (size < kMinEntrySize) return;
diff --git a/centipede/byte_array_mutator_test.cc b/centipede/byte_array_mutator_test.cc
index e28dff3..ee4d35e 100644
--- a/centipede/byte_array_mutator_test.cc
+++ b/centipede/byte_array_mutator_test.cc
@@ -112,18 +112,23 @@
   CmpDictionary dict;
   ExecutionMetadata metadata{/*cmp_data=*/{
       2,               // size
+      0,               // is_integer
       1,  2,           // a
       3,  4,           // b
       3,               // size
+      0,               // is_integer
       5,  6,  7,       // a
       8,  9,  10,      // b
       4,               // size
+      0,               // is_integer
       11, 12, 13, 14,  // a
       15, 16, 17, 18,  // b
       3,               // size
+      0,               // is_integer
       20, 21, 22,      // a
       15, 16, 17,      // b
       3,               // size
+      0,               // is_integer
       15, 16, 20,      // a
       30, 40, 50,      // b
   }};
@@ -631,23 +636,23 @@
 }
 
 TEST(ByteArrayMutator, OverwriteFromCmpDictionary) {
-  TestMutatorFn(&ByteArrayMutator::OverwriteFromCmpDictionary,
-                {1, 2, 40, 50, 60},
-                /*expected_mutants=*/
-                {
-                    {3, 4, 40, 50, 60},
-                    {1, 2, 10, 20, 30},
-                },
-                /*unexpected_mutants=*/
-                {
-                    {3, 4, 10, 20, 30},
-                },
-                /*size_alignment=*/1,
-                /*max_len=*/std::numeric_limits<size_t>::max(),
-                /*dictionary=*/
-                {},
-                /*cmp_data=*/
-                {/*args1*/ 2, 1, 2, 3, 4, /*args2*/ 3, 10, 20, 30, 40, 50, 60});
+  TestMutatorFn(
+      &ByteArrayMutator::OverwriteFromCmpDictionary, {1, 2, 40, 50, 60},
+      /*expected_mutants=*/
+      {
+          {3, 4, 40, 50, 60},
+          {1, 2, 10, 20, 30},
+      },
+      /*unexpected_mutants=*/
+      {
+          {3, 4, 10, 20, 30},
+      },
+      /*size_alignment=*/1,
+      /*max_len=*/std::numeric_limits<size_t>::max(),
+      /*dictionary=*/
+      {},
+      /*cmp_data=*/
+      {/*args1*/ 2, 0, 1, 2, 3, 4, /*args2*/ 3, 0, 10, 20, 30, 40, 50, 60});
 }
 
 TEST(ByteArrayMutator, OverwriteFromCmpDictionaryAndSkipLongEntry) {
@@ -665,13 +670,13 @@
       /*dictionary=*/
       {},
       /*cmp_data=*/
-      {/*size*/ 20, /*lhs*/ 0, 1,   2,   3,   4,           5,
-       6,           7,         8,   9,   10,  11,          12,
-       13,          14,        15,  16,  17,  18,          19,
-       /*rhs*/ 100, 101,       102, 103, 104, 105,         106,
-       107,         108,       109, 110, 111, 112,         113,
-       114,         115,       116, 117, 118, 119,
-       /*size*/ 4,  /*lhs*/ 0, 1,   2,   3,   /*rhs*/ 100, 101,
+      {/*size*/ 20, 0,   /*lhs*/ 0, 1,   2,   3,   4,           5,
+       6,           7,   8,         9,   10,  11,  12,          13,
+       14,          15,  16,        17,  18,  19,
+       /*rhs*/ 100, 101, 102,       103, 104, 105, 106,         107,
+       108,         109, 110,       111, 112, 113, 114,         115,
+       116,         117, 118,       119,
+       /*size*/ 4,  0,   /*lhs*/ 0, 1,   2,   3,   /*rhs*/ 100, 101,
        102,         103});
 }
 
diff --git a/centipede/centipede_test.cc b/centipede/centipede_test.cc
index e242d2d..c215436 100644
--- a/centipede/centipede_test.cc
+++ b/centipede/centipede_test.cc
@@ -1010,7 +1010,7 @@
   ASSERT_EQ(batch_result.results().size(), 1);
   bool found_startup_cmp_entry = false;
   batch_result.results()[0].metadata().ForEachCmpEntry(
-      [&](ByteSpan a, ByteSpan b) {
+      [&](ByteSpan a, ByteSpan b, bool) {
         if (a == ByteArray{'F', 'u', 'z', 'z'}) found_startup_cmp_entry = true;
         if (b == ByteArray{'F', 'u', 'z', 'z'}) found_startup_cmp_entry = true;
       });
diff --git a/centipede/execution_metadata.cc b/centipede/execution_metadata.cc
index 4b96116..e1dabbd 100644
--- a/centipede/execution_metadata.cc
+++ b/centipede/execution_metadata.cc
@@ -22,11 +22,13 @@
 
 namespace fuzztest::internal {
 
-bool ExecutionMetadata::AppendCmpEntry(ByteSpan a, ByteSpan b) {
+bool ExecutionMetadata::AppendCmpEntry(ByteSpan a, ByteSpan b,
+                                       bool is_integer) {
   if (a.size() != b.size()) return false;
   // Size must fit in a byte.
   if (a.size() >= 256) return false;
-  cmp_data.push_back(a.size());
+  cmp_data.push_back(static_cast<uint8_t>(a.size()));
+  cmp_data.push_back(is_integer ? 1 : 0);
   cmp_data.insert(cmp_data.end(), a.begin(), a.end());
   cmp_data.insert(cmp_data.end(), b.begin(), b.end());
   return true;
@@ -42,15 +44,17 @@
 }
 
 bool ExecutionMetadata::ForEachCmpEntry(
-    std::function<void(ByteSpan, ByteSpan)> callback) const {
+    const std::function<void(ByteSpan, ByteSpan, bool)>& callback) const {
   size_t i = 0;
   while (i < cmp_data.size()) {
-    auto size = cmp_data[i];
-    if (i + 2 * size + 1 > cmp_data.size()) return false;
-    ByteSpan a(cmp_data.data() + i + 1, size);
-    ByteSpan b(cmp_data.data() + i + size + 1, size);
-    i += 1 + 2 * size;
-    callback(a, b);
+    if (i + 2 > cmp_data.size()) return false;
+    uint8_t size = cmp_data[i];
+    bool is_integer = cmp_data[i + 1] != 0;
+    if (i + 2 + 2 * size > cmp_data.size()) return false;
+    ByteSpan a(cmp_data.data() + i + 2, size);
+    ByteSpan b(cmp_data.data() + i + 2 + size, size);
+    i += 2 + 2 * size;
+    callback(a, b, is_integer);
   }
   return true;
 }
diff --git a/centipede/execution_metadata.h b/centipede/execution_metadata.h
index 1e28e60..0ebaaeb 100644
--- a/centipede/execution_metadata.h
+++ b/centipede/execution_metadata.h
@@ -30,12 +30,13 @@
 struct ExecutionMetadata {
   // Appends a CMP entry comparing `a` and `b` to the metadata. Returns false if
   // the entry cannot be appended. Return true otherwise.
-  bool AppendCmpEntry(ByteSpan a, ByteSpan b);
+  bool AppendCmpEntry(ByteSpan a, ByteSpan b, bool is_integer = false);
 
   // Enumerates through all CMP entries in the metadata by calling
   // `callback` on each of them. Returns false if there are invalid
   // entries. Returns true otherwise.
-  bool ForEachCmpEntry(std::function<void(ByteSpan, ByteSpan)> callback) const;
+  bool ForEachCmpEntry(
+      const std::function<void(ByteSpan, ByteSpan, bool)>& callback) const;
 
   // Writes the contents to `outputs_blobseq` with header `tag`. Returns true
   // iff successful.
@@ -50,6 +51,7 @@
   // CMP entries are stored in one large ByteArray to minimize RAM consumption.
   // One CMP arg pair is stored as
   //  * `size` (1-byte value)
+  //  * `is_integer` (1-byte value)
   //  * `value0` (`size` bytes)
   //  * `value1` (`size` bytes)
   ByteArray cmp_data;
diff --git a/centipede/execution_metadata_test.cc b/centipede/execution_metadata_test.cc
index 1bd0c42..f1b9cb7 100644
--- a/centipede/execution_metadata_test.cc
+++ b/centipede/execution_metadata_test.cc
@@ -33,16 +33,20 @@
   ExecutionMetadata metadata;
   metadata.cmp_data = {
       2,         // size
+      0,         // is_integer
       1, 2,      // a
       3, 4,      // b
       0,         // zero-sized entry
+      0,         // is_integer
       3,         // size
+      1,         // is_integer
       5, 6, 7,   // a
       8, 9, 10,  // b
   };
   std::vector<std::pair<ByteSpan, ByteSpan>> enumeration_result;
-  EXPECT_TRUE(metadata.ForEachCmpEntry(
-      [&](ByteSpan a, ByteSpan b) { enumeration_result.emplace_back(a, b); }));
+  EXPECT_TRUE(metadata.ForEachCmpEntry([&](ByteSpan a, ByteSpan b, bool) {
+    enumeration_result.emplace_back(a, b);
+  }));
 
   EXPECT_THAT(
       enumeration_result,
@@ -54,32 +58,42 @@
 }
 
 TEST(ExecutionMetadata, ForEachCmpEntryHandlesEmptyCmpData) {
-  auto noop_callback = [](ByteSpan, ByteSpan) {};
+  auto noop_callback = [](ByteSpan, ByteSpan, bool) {};
   EXPECT_TRUE(ExecutionMetadata{}.ForEachCmpEntry(noop_callback));
 }
 
 TEST(ExecutionMetadata,
      ForEachCmpEntryReturnsFalseOnCmpDataWithNotEnoughBytes) {
-  auto noop_callback = [](ByteSpan, ByteSpan) {};
+  auto noop_callback = [](ByteSpan, ByteSpan, bool) {};
   auto bad_metadata_1 = ExecutionMetadata{};
-  bad_metadata_1.cmp_data = {3, 1, 2, 3};
+  bad_metadata_1.cmp_data = {3, 0, 1, 2, 3};
   EXPECT_FALSE(bad_metadata_1.ForEachCmpEntry(noop_callback));
   auto bad_metadata_2 = ExecutionMetadata{};
-  bad_metadata_2.cmp_data = {3, 1, 2, 3, 4, 5};
+  bad_metadata_2.cmp_data = {3, 0, 1, 2, 3, 4, 5};
   EXPECT_FALSE(bad_metadata_2.ForEachCmpEntry(noop_callback));
 }
 
 TEST(ExecutionMetadata, ForEachCmpEntryEnumeratesEntriesFromAppendCmpEntry) {
   ExecutionMetadata metadata;
-  ASSERT_TRUE(metadata.AppendCmpEntry({1, 2}, {3, 4}));
-  std::vector<std::pair<ByteSpan, ByteSpan>> enumeration_result;
-  EXPECT_TRUE(metadata.ForEachCmpEntry(
-      [&](ByteSpan a, ByteSpan b) { enumeration_result.emplace_back(a, b); }));
-  EXPECT_THAT(
-      enumeration_result,
-      UnorderedElementsAreArray(std::vector<std::pair<ByteSpan, ByteSpan>>{
-          {{1, 2}, {3, 4}},
+  ASSERT_TRUE(metadata.AppendCmpEntry({1, 2}, {3, 4}, /*is_integer=*/true));
+  ASSERT_TRUE(metadata.AppendCmpEntry({5, 6}, {7, 8}, /*is_integer=*/false));
+  struct Entry {
+    ByteSpan a;
+    ByteSpan b;
+    bool is_integer;
+    bool operator==(const Entry& other) const {
+      return a == other.a && b == other.b && is_integer == other.is_integer;
+    }
+  };
+  std::vector<Entry> enumeration_result;
+  EXPECT_TRUE(
+      metadata.ForEachCmpEntry([&](ByteSpan a, ByteSpan b, bool is_integer) {
+        enumeration_result.push_back({a, b, is_integer});
       }));
+  EXPECT_THAT(enumeration_result, UnorderedElementsAreArray(std::vector<Entry>{
+                                      {{1, 2}, {3, 4}, true},
+                                      {{5, 6}, {7, 8}, false},
+                                  }));
 }
 
 TEST(ExecutionMetadata, AppendCmpEntryReturnsFalseAndSkipsOnBadArgs) {
@@ -88,18 +102,20 @@
   EXPECT_FALSE(metadata.AppendCmpEntry({}, {1}));
   ByteArray long_byte_array;
   long_byte_array.resize(256);
-  // Args too long.
+  // Args too long (>= 256).
   EXPECT_FALSE(metadata.AppendCmpEntry(long_byte_array, long_byte_array));
   // Should leave no entries and keep metadata well-formed.
   std::vector<std::pair<ByteSpan, ByteSpan>> enumeration_result;
-  EXPECT_TRUE(metadata.ForEachCmpEntry(
-      [&](ByteSpan a, ByteSpan b) { enumeration_result.emplace_back(a, b); }));
+  EXPECT_TRUE(metadata.ForEachCmpEntry([&](ByteSpan a, ByteSpan b, bool) {
+    enumeration_result.emplace_back(a, b);
+  }));
   EXPECT_THAT(enumeration_result, IsEmpty());
 }
 
 TEST(ExecutionMetadata, ReadAndWriteKeepsCmpEntries) {
   ExecutionMetadata metadata_in;
-  ASSERT_TRUE(metadata_in.AppendCmpEntry({1, 2}, {3, 4}));
+  ASSERT_TRUE(metadata_in.AppendCmpEntry({1, 2}, {3, 4}, /*is_integer=*/true));
+  ASSERT_TRUE(metadata_in.AppendCmpEntry({5, 6}, {7, 8}, /*is_integer=*/false));
   std::vector<uint8_t> blob_storage;
   blob_storage.resize(1024);
   BlobSequence blobseq(blob_storage.data(), blob_storage.size());
@@ -108,14 +124,23 @@
   Blob blob = blobseq.Read();
   ExecutionMetadata metadata_out;
   metadata_out.Read(blob);
-  std::vector<std::pair<ByteSpan, ByteSpan>> enumeration_result;
+  struct Entry {
+    ByteSpan a;
+    ByteSpan b;
+    bool is_integer;
+    bool operator==(const Entry& other) const {
+      return a == other.a && b == other.b && is_integer == other.is_integer;
+    }
+  };
+  std::vector<Entry> enumeration_result;
   EXPECT_TRUE(metadata_out.ForEachCmpEntry(
-      [&](ByteSpan a, ByteSpan b) { enumeration_result.emplace_back(a, b); }));
-  EXPECT_THAT(
-      enumeration_result,
-      UnorderedElementsAreArray(std::vector<std::pair<ByteSpan, ByteSpan>>{
-          {{1, 2}, {3, 4}},
+      [&](ByteSpan a, ByteSpan b, bool is_integer) {
+        enumeration_result.push_back({a, b, is_integer});
       }));
+  EXPECT_THAT(enumeration_result, UnorderedElementsAreArray(std::vector<Entry>{
+                                      {{1, 2}, {3, 4}, true},
+                                      {{5, 6}, {7, 8}, false},
+                                  }));
 }
 
 }  // namespace
diff --git a/centipede/fuzztest_mutator.cc b/centipede/fuzztest_mutator.cc
index 1af4e17..936419f 100644
--- a/centipede/fuzztest_mutator.cc
+++ b/centipede/fuzztest_mutator.cc
@@ -75,29 +75,33 @@
   size_t mem_sample_counter = 0;
 
   metadata.ForEachCmpEntry([&](fuzztest::internal::ByteSpan a,
-                               fuzztest::internal::ByteSpan b) {
+                               fuzztest::internal::ByteSpan b,
+                               bool is_integer) {
     FUZZTEST_CHECK(a.size() == b.size())
         << "cmp operands must have the same size";
     const size_t size = a.size();
     if (size < kMinCmpEntrySize) return;
     if (size > kMaxCmpEntrySize) return;
-    if (size == 2 && SampleInsert(cmp_tables.GetMutable<sizeof(uint16_t)>(),
-                                  uint16_sample_counter)) {
-      InsertCmpEntryIntoIntegerDictionary<uint16_t>(a.data(), b.data(),
-                                                    cmp_tables);
-    } else if (size == 4 &&
-               SampleInsert(cmp_tables.GetMutable<sizeof(uint32_t)>(),
-                            uint32_sample_counter)) {
-      InsertCmpEntryIntoIntegerDictionary<uint32_t>(a.data(), b.data(),
-                                                    cmp_tables);
-    } else if (size == 8 &&
-               SampleInsert(cmp_tables.GetMutable<sizeof(uint64_t)>(),
-                            uint64_sample_counter)) {
-      InsertCmpEntryIntoIntegerDictionary<uint64_t>(a.data(), b.data(),
-                                                    cmp_tables);
-    }
-    if (SampleInsert(cmp_tables.GetMutable<0>(), mem_sample_counter)) {
-      cmp_tables.GetMutable<0>().Insert(a.data(), b.data(), size);
+    if (is_integer) {
+      if (size == 2 && SampleInsert(cmp_tables.GetMutable<sizeof(uint16_t)>(),
+                                    uint16_sample_counter)) {
+        InsertCmpEntryIntoIntegerDictionary<uint16_t>(a.data(), b.data(),
+                                                      cmp_tables);
+      } else if (size == 4 &&
+                 SampleInsert(cmp_tables.GetMutable<sizeof(uint32_t)>(),
+                              uint32_sample_counter)) {
+        InsertCmpEntryIntoIntegerDictionary<uint32_t>(a.data(), b.data(),
+                                                      cmp_tables);
+      } else if (size == 8 &&
+                 SampleInsert(cmp_tables.GetMutable<sizeof(uint64_t)>(),
+                              uint64_sample_counter)) {
+        InsertCmpEntryIntoIntegerDictionary<uint64_t>(a.data(), b.data(),
+                                                      cmp_tables);
+      }
+    } else {
+      if (SampleInsert(cmp_tables.GetMutable<0>(), mem_sample_counter)) {
+        cmp_tables.GetMutable<0>().Insert(a.data(), b.data(), size);
+      }
     }
   });
 }
diff --git a/centipede/fuzztest_mutator_test.cc b/centipede/fuzztest_mutator_test.cc
index a732bca..53c9108 100644
--- a/centipede/fuzztest_mutator_test.cc
+++ b/centipede/fuzztest_mutator_test.cc
@@ -240,9 +240,11 @@
                                {1, 2, 10, 20, 30},
                            };
                            params.cmp_data = {2,            // size
+                                              0,            // is_integer
                                               1,  2,        // lhs
                                               3,  4,        // rhs
                                               3,            // size
+                                              0,            // is_integer
                                               10, 20, 30,   // lhs
                                               40, 50, 60};  // rhs
                            return params;
@@ -274,9 +276,11 @@
                                {1, 6, 7, 8, 2, 3}, {6, 7, 8, 1, 2, 3},
                            };
                            params.cmp_data = {2,         // size
+                                              0,         // is_integer
                                               4, 5,      // lhs
                                               4, 5,      // rhs
                                               3,         // size
+                                              0,         // is_integer
                                               6, 7, 8,   // lhs
                                               6, 7, 8};  // rhs
                            return params;
@@ -300,6 +304,7 @@
                                long_entry,
                            };
                            params.cmp_data.push_back(short_entry.size());
+                           params.cmp_data.push_back(0);  // is_integer
                            params.cmp_data.insert(params.cmp_data.end(),
                                                   short_entry.begin(),
                                                   short_entry.end());  // lhs
@@ -307,6 +312,7 @@
                                                   short_entry.begin(),
                                                   short_entry.end());  // rhs
                            params.cmp_data.push_back(long_entry.size());
+                           params.cmp_data.push_back(0);  // is_integer
                            params.cmp_data.insert(params.cmp_data.end(),
                                                   long_entry.begin(),
                                                   long_entry.end());  // lhs
diff --git a/centipede/runner_result_test.cc b/centipede/runner_result_test.cc
index 20ce433..cb2ed29 100644
--- a/centipede/runner_result_test.cc
+++ b/centipede/runner_result_test.cc
@@ -82,6 +82,7 @@
   EXPECT_EQ(batch_result.results()[1].stats(), stats2);
   EXPECT_THAT(batch_result.results()[1].metadata().cmp_data,
               ElementsAre(3,        // size
+                          0,        // is_integer
                           1, 2, 3,  // cmp0
                           4, 5, 6   // cmp1
                           ));
@@ -162,6 +163,7 @@
   EXPECT_EQ(batch_result.results()[1].stats(), stats2);
   EXPECT_THAT(batch_result.results()[1].metadata().cmp_data,
               ElementsAre(3,        // size
+                          0,        // is_integer
                           1, 2, 3,  // cmp0
                           4, 5, 6   // cmp1
                           ));
@@ -292,7 +294,7 @@
   EXPECT_EQ(batch_result.results()[0].metadata().cmp_data, bytes);
   // `ForEachEntry()` should fail but not crash.
   EXPECT_FALSE(batch_result.results()[0].metadata().ForEachCmpEntry(
-      [](ByteSpan, ByteSpan) {}));
+      [](ByteSpan, ByteSpan, bool) {}));
 }
 
 }  // namespace
diff --git a/centipede/sancov_state.cc b/centipede/sancov_state.cc
index c5bbaf3..83d7e6c 100644
--- a/centipede/sancov_state.cc
+++ b/centipede/sancov_state.cc
@@ -379,10 +379,11 @@
 // "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) {
+                                                ExecutionMetadata& metadata,
+                                                bool is_integer) {
   cmp_trace.ForEachNonZero(
       [&](uint8_t size, const uint8_t* v0, const uint8_t* v1) {
-        (void)metadata.AppendCmpEntry({v0, size}, {v1, size});
+        (void)metadata.AppendCmpEntry({v0, size}, {v1, size}, is_integer);
       });
 }
 
@@ -392,10 +393,14 @@
 
   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);
+      AppendCmpEntries(tls.cmp_trace2, sancov_state->metadata,
+                       /*is_integer=*/true);
+      AppendCmpEntries(tls.cmp_trace4, sancov_state->metadata,
+                       /*is_integer=*/true);
+      AppendCmpEntries(tls.cmp_trace8, sancov_state->metadata,
+                       /*is_integer=*/true);
+      AppendCmpEntries(tls.cmp_traceN, sancov_state->metadata,
+                       /*is_integer=*/false);
     });
   }