feat: add configurable collision-free EVM edge coverage#14853
Merged
grandizzy merged 14 commits intoMay 26, 2026
Conversation
DaniPopes
reviewed
May 20, 2026
| /// Whether EVM edge coverage should use collision-free dense IDs. | ||
| pub evm_edge_coverage_collision_free: bool, | ||
| /// Whether EVM edge coverage IDs should include call-frame depth. | ||
| pub evm_edge_coverage_include_call_depth: bool, |
Member
There was a problem hiding this comment.
why even have the configs? why not just switch it out directly?
Collaborator
Author
There was a problem hiding this comment.
it makes it easier to experiment. there's a couple more things to get in, and then i'd like to search for the best defaults or let some threads run with non-default features enabled
Collaborator
Author
There was a problem hiding this comment.
if there's a better way to avoid these be user-facing, i suppose that'd be good to avoid churn
mablr
reviewed
May 21, 2026
Collaborator
Benchmark: 1h Aave v4 SCFuzzBench campaign (seed=42)I ran a 4-way comparison of edge-coverage modes against the Recon-Fuzz/aave-v4-scfuzzbench suite (
Results
Unique bugs by config
Key findings
|
…onfig # Conflicts: # crates/evm/evm/src/executors/mod.rs
Vec::push already grows via the same amortized doubling path (RawVec::grow_amortized) as Vec::reserve(1), so pre-reserving a single slot adds no headroom -- only an extra capacity check.
The fixed-size hash bitmap is only used by EdgeCovKind::Hash. In CollisionFree mode (the new default) it stayed allocated and got memcpy'd on every per-call inspector clone for no benefit.
Previously into_coverage(self) borrowed via dense_hits(&self) and cloned every dense entry despite consuming the inspector. Replace with a single From impl that destructures and moves the HashMap, and use it from both into_hitcount and into_parts.
merge_edge_coverage doesn't need ordered hits, so paying sort_by_key on every per-call inspector drain was wasted work on the new default path. Move the sort into snapshot_edge_fingerprint, which is gated on handler assertion failure -- cold path -- and is the only consumer that needs a deterministic order across HashMap iterations.
Once From<EdgeCovInspector> for EdgeCoverage landed, into_hitcount was just a thin wrapper around self.into() with a misleading name (it returns EdgeCoverage, not a hitcount). No callers exist.
Without a tag byte, an EdgeKey with depth=None serializes identically to depth=Some(0) when include_call_depth is toggled, so fingerprints collide across configs sharing a corpus. Push a 1-byte is_some tag ahead of the depth bytes. Cold path; no impact on default config.
The method took (yes: bool, kind: bool, include_call_depth: bool) and runner.rs sourced all three from the same FuzzCorpusConfig. Replace with collect_edge_coverage_with_config(&FuzzCorpusConfig) that derives both the gate and EdgeCovConfig from one corpus reference, backed by a From<&FuzzCorpusConfig> for EdgeCovConfig impl.
mablr
reviewed
May 26, 2026
mablr
reviewed
May 26, 2026
mablr
reviewed
May 26, 2026
- drop stale TODO in collect_edge_coverage - collapse with_capacity/with_capacity_and_config into with_config - drop tests-only get_hitcount/get_dense_hits; cfg(test)-gate dense_hits - remove vacuous hitcount==0 assertions in collision-free tests - start WorkerCorpus history maps empty; merge paths resize on demand - still preallocate Hash-mode history_map to keep first merge alloc-free
grandizzy
previously approved these changes
May 26, 2026
Amp-Thread-ID: https://ampcode.com/threads/T-019e64ab-e0ea-73df-802c-beb11f0ee1e0 Co-authored-by: Amp <amp@ampcode.com>
grandizzy
approved these changes
May 26, 2026
stevencartavia
approved these changes
May 26, 2026
mablr
approved these changes
May 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
in the OG implementation, it is possible for edge IDs to collide which can lose some signal
OSS-249
Solution
implement and make
evm_edge_coverage_collision_freethe defaultPR Checklist