Skip to content

Commit

Permalink
Fuzzing
Browse files Browse the repository at this point in the history
  • Loading branch information
notriddle committed Feb 25, 2021
1 parent fe5ec13 commit e7e8a91
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
Cargo.lock
*.swp
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,7 @@ but it implements a different format.
+
+[dependencies]
+diff = "0.1.10"
~/unified-diff$ rustup override set nightly
~/unified-diff$ cargo fuzz run fuzz_patch
```

4 changes: 4 additions & 0 deletions fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

target
corpus
artifacts
27 changes: 27 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

[package]
name = "unified-diff-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
edition = "2018"

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.3"

[dependencies.unified-diff]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzz_patch"
path = "fuzz_targets/fuzz_patch.rs"
test = false
doc = false

55 changes: 55 additions & 0 deletions fuzz/fuzz_targets/fuzz_patch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate unified_diff;

use std::fs::{self, File};
use std::io::Write;
use std::process::Command;

fuzz_target!(|x: (Vec<u8>, Vec<u8>, u8)| {
let (from, to, context) = x;
if let Ok(s) = String::from_utf8(from.clone()) {
if !s.is_ascii() { return }
if s.find(|x| x < ' ' && x != '\n').is_some() { return }
} else {
return
}
if let Ok(s) = String::from_utf8(to.clone()) {
if !s.is_ascii() { return }
if s.find(|x| x < ' ' && x != '\n').is_some() { return }
} else {
return
}
let diff = unified_diff::diff(&from, "a/fuzz.file", &to, "target/fuzz.file", context as usize);
File::create("target/fuzz.file.original")
.unwrap()
.write_all(&from)
.unwrap();
File::create("target/fuzz.file.expected")
.unwrap()
.write_all(&to)
.unwrap();
File::create("target/fuzz.file")
.unwrap()
.write_all(&from)
.unwrap();
File::create("target/fuzz.diff")
.unwrap()
.write_all(&diff)
.unwrap();
let output = Command::new("patch")
.arg("-p0")
.arg("--binary")
.arg("--fuzz=0")
.stdin(File::open("target/fuzz.diff").unwrap())
.output()
.unwrap();
if !output.status.success() {
panic!("STDOUT:\n{}\nSTDERR:\n{}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
}
let result = fs::read("target/fuzz.file").unwrap();
if result != to {
panic!("STDOUT:\n{}\nSTDERR:\n{}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
}
});

66 changes: 43 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,24 @@ fn make_diff(expected: &[u8], actual: &[u8], context_size: usize) -> Vec<Mismatc
lines_since_mismatch = 0;
}
diff::Result::Both(str, _) => {

// if one of them is missing a newline and the other isn't, then they don't actually match
if (line_number_actual > actual_lines_count)
|| (line_number_expected > expected_lines_count)
&& (line_number_expected > expected_lines_count)
{
// if one of them is missing a newline and the other isn't, then they don't actually match
if lines_since_mismatch >= context_size
&& lines_since_mismatch > 0
&& (line_number_actual > actual_lines_count)
!= (line_number_expected > expected_lines_count)
{
if context_queue.len() < context_size {
while let Some(line) = context_queue.pop_front() {
assert!(mismatch.lines.last() != Some(&DiffLine::MissingNL));
mismatch.lines.push(DiffLine::Context(line.to_vec()));
}
if lines_since_mismatch < context_size {
mismatch.lines.push(DiffLine::Context(str.to_vec()));
mismatch.lines.push(DiffLine::MissingNL);
}
}
lines_since_mismatch = 0;
} else if line_number_actual > actual_lines_count {
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
results.push(mismatch);
mismatch = Mismatch::new(
line_number_expected - context_queue.len() as u32,
Expand All @@ -131,22 +140,28 @@ fn make_diff(expected: &[u8], actual: &[u8], context_size: usize) -> Vec<Mismatc
assert!(mismatch.lines.last() != Some(&DiffLine::MissingNL));
mismatch.lines.push(DiffLine::Context(line.to_vec()));
}
mismatch.lines.push(DiffLine::Expected(str.to_vec()));
mismatch.lines.push(DiffLine::Actual(str.to_vec()));
mismatch.lines.push(DiffLine::MissingNL);
lines_since_mismatch = 0;
if line_number_actual > actual_lines_count
&& line_number_expected > expected_lines_count
{
mismatch.lines.push(DiffLine::Context(str.to_vec()));
mismatch.lines.push(DiffLine::MissingNL);
} else if line_number_expected > expected_lines_count {
mismatch.lines.push(DiffLine::Expected(str.to_vec()));
mismatch.lines.push(DiffLine::MissingNL);
mismatch.lines.push(DiffLine::Actual(str.to_vec()));
} else if line_number_actual > actual_lines_count {
mismatch.lines.push(DiffLine::Expected(str.to_vec()));
mismatch.lines.push(DiffLine::Actual(str.to_vec()));
mismatch.lines.push(DiffLine::MissingNL);
} else if line_number_expected > expected_lines_count {
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
results.push(mismatch);
mismatch = Mismatch::new(
line_number_expected - context_queue.len() as u32,
line_number_actual - context_queue.len() as u32,
);
}
while let Some(line) = context_queue.pop_front() {
assert!(mismatch.lines.last() != Some(&DiffLine::MissingNL));
mismatch.lines.push(DiffLine::Context(line.to_vec()));
}
mismatch.lines.push(DiffLine::Expected(str.to_vec()));
mismatch.lines.push(DiffLine::MissingNL);
mismatch.lines.push(DiffLine::Actual(str.to_vec()));
lines_since_mismatch = 0;
} else {
assert!(context_queue.len() <= context_size);
if context_queue.len() >= context_size {
let _ = context_queue.pop_front();
}
Expand All @@ -157,7 +172,6 @@ fn make_diff(expected: &[u8], actual: &[u8], context_size: usize) -> Vec<Mismatc
}
lines_since_mismatch += 1;
}

line_number_expected += 1;
line_number_actual += 1;
}
Expand Down Expand Up @@ -220,25 +234,31 @@ pub fn diff(
return Vec::new();
};
for result in diff_results {
let line_number_expected = result.line_number_expected;
let line_number_actual = result.line_number_actual;
let mut line_number_expected = result.line_number_expected;
let mut line_number_actual = result.line_number_actual;
let mut expected_count = 0;
let mut actual_count = 0;
let mut has_expected = false;
let mut has_actual = false;
for line in &result.lines {
match line {
DiffLine::Expected(_) => {
expected_count += 1;
has_expected = true;
}
DiffLine::Context(_) => {
expected_count += 1;
actual_count += 1;
}
DiffLine::Actual(_) => {
actual_count += 1;
has_actual = true;
}
DiffLine::MissingNL => {}
}
}
if expected_count == 0 { line_number_expected -= 1 }
if actual_count == 0 { line_number_actual -= 1 }
writeln!(
output,
"@@ -{},{} +{},{} @@",
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn main() {
&from.to_string_lossy(),
&to_content,
&to.to_string_lossy(),
3,
1,
))
.unwrap();
}

0 comments on commit e7e8a91

Please sign in to comment.