Fix a crash when all corpus inputs have no feature. This can occur when features become "frequent" enough that they get removed from the corpus inputs' feature lists. PiperOrigin-RevId: 834769613
diff --git a/centipede/corpus.cc b/centipede/corpus.cc index 4363b24..c274691 100644 --- a/centipede/corpus.cc +++ b/centipede/corpus.cc
@@ -175,6 +175,13 @@ max_corpus_size, std::max(1UL, records_.size() - num_zero_weights)); auto subset_to_remove = weighted_distribution_.RemoveRandomWeightedSubset(target_size, rng); + if (subset_to_remove.size() == records_.size()) { + // This can happen only when all inputs have zero weights - keep random one. + FUZZTEST_CHECK(num_zero_weights == records_.size()); + subset_to_remove.erase( + subset_to_remove.begin() + + absl::Uniform<size_t>(rng, 0, subset_to_remove.size())); + } RemoveSubset(subset_to_remove, records_); weighted_distribution_.RecomputeInternalState();
diff --git a/centipede/corpus_test.cc b/centipede/corpus_test.cc index a75ddb0..f816f46 100644 --- a/centipede/corpus_test.cc +++ b/centipede/corpus_test.cc
@@ -194,6 +194,24 @@ EXPECT_GT(freq[1], freq[2] + 100); } +TEST(Corpus, PruneCorpusWithAllEmptyFeatureInputs) { + PCTable pc_table(100); + CFTable cf_table(100); + BinaryInfo bin_info{pc_table, {}, cf_table, {}, {}, {}}; + CoverageFrontier coverage_frontier(bin_info); + FeatureSet fs(1, {}); + Corpus corpus; + Rng rng; + size_t max_corpus_size = 1000; + + corpus.Add(/*data=*/{1}, /*fv=*/{}, /*metadata=*/{}, /*stats=*/{}, fs, + coverage_frontier); + corpus.Add(/*data=*/{2}, /*fv=*/{}, /*metadata=*/{}, /*stats=*/{}, fs, + coverage_frontier); + // Should not crash. + corpus.Prune(fs, coverage_frontier, max_corpus_size, rng); +} + // Regression test for a crash in Corpus::Prune(). TEST(Corpus, PruneRegressionTest1) { PCTable pc_table(100);