mirror of
https://github.com/uutils/diffutils.git
synced 2026-06-10 15:48:59 -07:00
Fuzzing
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
*.swp
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
target
|
||||
corpus
|
||||
artifacts
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
});
|
||||
|
||||
+43
-23
@@ -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,
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -220,14 +234,17 @@ 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;
|
||||
@@ -235,10 +252,13 @@ pub fn diff(
|
||||
}
|
||||
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,
|
||||
"@@ -{},{} +{},{} @@",
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ fn main() {
|
||||
&from.to_string_lossy(),
|
||||
&to_content,
|
||||
&to.to_string_lossy(),
|
||||
3,
|
||||
1,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user