This directory contains fuzzing infrastructure for the lintdiff project. Fuzz targets are kept out of the main workspace to avoid pulling nightly tooling into normal CI.
# Install the cargo-fuzz tool (requires nightly Rust)
cargo install cargo-fuzz
# Ensure you have the nightly toolchain installed
rustup install nightly| Target | Description | Corpus Directory |
|---|---|---|
diff_parser |
Tests unified diff parsing | corpus/diff_parser/ |
diagnostics_parser |
Tests JSONL diagnostic parsing | corpus/diagnostics_parser/ |
finding_fingerprint |
Tests fingerprint generation | corpus/finding_fingerprint/ |
cd fuzz
# Run each target for 60 seconds (default)
cargo fuzz run diff_parser
cargo fuzz run diagnostics_parser
cargo fuzz run finding_fingerprint# Run for 5 minutes (300 seconds)
cargo fuzz run diff_parser -- -max_total_time=300
# Run for a specific number of iterations
cargo fuzz run diff_parser -- -runs=100000The corpus directories provide structured test cases that seed the fuzzer with known inputs:
# The fuzzer automatically uses corpus/<target>/ if it exists
cargo fuzz run diff_parser
# You can also specify corpus directories explicitly
cargo fuzz run diff_parser -- corpus/diff_parser/# Limit memory usage to 2GB
cargo fuzz run diff_parser -- -rss_limit_mb=2048# Run only a specific corpus file
cargo fuzz run diff_parser -- corpus/diff_parser/simple_addition.diffLocated in corpus/diff_parser/, contains sample diff files:
| File | Description |
|---|---|
simple_addition.diff |
Basic single-line addition |
multi_file.diff |
Changes across multiple files |
deletion.diff |
Line removal |
rename.diff |
File rename with similarity |
moved_code.diff |
Code moved between files |
empty_hunk.diff |
Empty diff hunk |
large_hunk.diff |
Many lines changed |
binary_file.diff |
Binary file handling |
mode_change.diff |
File permission change |
empty_file.diff |
Empty file creation |
Located in corpus/diagnostics_parser/, contains JSONL diagnostic files:
| File | Description |
|---|---|
simple_warning.jsonl |
Basic clippy warning |
multi_span.jsonl |
Diagnostic with multiple spans |
error_message.jsonl |
Compiler error |
no_span.jsonl |
Diagnostic without location |
note_help.jsonl |
Diagnostic with children |
macro_expanded.jsonl |
Macro expansion span |
generated_file.jsonl |
Generated code location |
multiple_messages.jsonl |
Multiple diagnostics |
unicode_message.jsonl |
Unicode in message |
long_path.jsonl |
Deeply nested file path |
Located in corpus/finding_fingerprint/, contains binary files with null-separated fields:
Format: code\0path\0line\0message
| File | Description |
|---|---|
simple_fingerprint.bin |
Standard fingerprint |
no_location.bin |
Fingerprint without path |
unicode_message.bin |
Unicode in message |
long_code.bin |
Very long lint code |
empty_parts.bin |
All empty fields |
error_fingerprint.bin |
Error-level lint |
multi_part.bin |
Multiple entries |
- Create a new
.difffile incorpus/diff_parser/ - Use standard unified diff format:
diff --git a/src/example.rs b/src/example.rs
--- a/src/example.rs
+++ b/src/example.rs
@@ -1,1 +1,2 @@
existing line
+new line- Create a new
.jsonlfile incorpus/diagnostics_parser/ - Use cargo/rustc JSON message format:
{"reason":"compiler-message","message":{"level":"warning","message":"description","code":{"code":"lint-name"},"spans":[{"file_name":"path","line_start":1,"line_end":1,"column_start":1,"column_end":10,"is_primary":true}]}}- Create binary files with null-separated fields
- Format:
code\0path\0line\0message - Use PowerShell on Windows:
$bytes = [System.Text.Encoding]::UTF8.GetBytes('code') + [byte]0 + [System.Text.Encoding]::UTF8.GetBytes('path') + [byte]0 + [System.Text.Encoding]::UTF8.GetBytes('line') + [byte]0 + [System.Text.Encoding]::UTF8.GetBytes('message'); [System.IO.File]::WriteAllBytes('corpus/finding_fingerprint/name.bin', $bytes)Or on Unix:
printf 'code\0path\0line\0message' > corpus/finding_fingerprint/name.binWhen a fuzzer finds a crash, it saves the crashing input to artifacts/<target>/.
# List crash artifacts
ls -la artifacts/diff_parser/
# View the crashing input (if text)
cat artifacts/diff_parser/crash-<hash># Run the fuzzer with the crashing input
cargo fuzz run diff_parser -- artifacts/diff_parser/crash-<hash>
# For better stack traces, build with debug info
RUST_BACKTRACE=1 cargo fuzz run diff_parser -- artifacts/diff_parser/crash-<hash># Build with debug symbols
cargo fuzz build --debug
# Run under debugger
rust-lldb -- ./fuzz/target/x86_64-unknown-linux-gnu/debug/diff_parser artifacts/diff_parser/crash-<hash>To find the smallest input that triggers a crash:
cargo fuzz tmin diff_parser -- artifacts/diff_parser/crash-<hash>After running fuzzing, merge new interesting inputs back to the corpus:
# Merge findings from a fuzzing session
cargo fuzz cmin diff_parserFuzzing runs automatically in CI:
- Schedule: Weekly on Sundays at 00:00 UTC
- Push: When fuzz-related files change on
main - Manual: Via workflow dispatch with configurable duration
- Go to Actions → Fuzzing
- Click "Run workflow"
- Optionally specify:
- Duration per target (seconds)
- Specific targets (comma-separated)
- Crash artifacts are uploaded and retained for 30 days
- Corpus artifacts are uploaded and retained for 7 days
- Check the workflow run logs for details
- Add corpus entries for edge cases: When you find a bug, add a corpus entry
- Keep corpus files small: Smaller files help the fuzzer explore faster
- Cover different code paths: Include various diff formats, diagnostic types
- Test invariants: Fuzz targets can include assertions for properties
- Don't ignore crashes: Every crash indicates a potential vulnerability
Make sure you're running from the workspace root, not inside fuzz/:
cd /path/to/lintdiff
cargo fuzz run diff_parserrustup install nightly
rustup component add rust-src --toolchain nightlyReduce the memory limit or input size:
cargo fuzz run diff_parser -- -rss_limit_mb=1024 -max_len=1024Increase parallelism or use a dictionary:
# Use all available cores
cargo fuzz run diff_parser -- -jobs=0
# Use a dictionary (if available)
cargo fuzz run diff_parser -- -dict=dictionary.txt