Skip to content

Commit 9542e15

Browse files
authored
Merge pull request #7281 from RenjiSann/renji/improve-fuzzer-log
Improve fuzzer logging
2 parents a3c5b8c + 6afa515 commit 9542e15

File tree

5 files changed

+145
-28
lines changed

5 files changed

+145
-28
lines changed

fuzz/Cargo.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fuzz/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2021"
88
cargo-fuzz = true
99

1010
[dependencies]
11+
console = "0.15.0"
1112
libfuzzer-sys = "0.4.7"
1213
libc = "0.2.153"
1314
tempfile = "3.15.0"

fuzz/fuzz_targets/fuzz_cksum.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use uu_cksum::uumain;
1111
mod fuzz_common;
1212
use crate::fuzz_common::{
1313
compare_result, generate_and_run_uumain, generate_random_file, generate_random_string,
14-
run_gnu_cmd, CommandResult,
14+
pretty_print::{print_or_empty, print_test_begin},
15+
replace_fuzz_binary_name, run_gnu_cmd, CommandResult,
1516
};
1617
use rand::Rng;
1718
use std::env::temp_dir;
@@ -129,13 +130,15 @@ fuzz_target!(|_data: &[u8]| {
129130
if let Ok(checksum_file_path) =
130131
generate_checksum_file(algo, &file_path, &selected_digest_opts)
131132
{
133+
print_test_begin(format!("cksum {:?}", args));
134+
132135
if let Ok(content) = fs::read_to_string(&checksum_file_path) {
133-
println!("File content: {checksum_file_path}={content}");
136+
println!("File content ({})", checksum_file_path);
137+
print_or_empty(&content);
134138
} else {
135139
eprintln!("Error reading the checksum file.");
136140
}
137-
println!("args: {:?}", args);
138-
let rust_result = generate_and_run_uumain(&args, uumain, None);
141+
let mut rust_result = generate_and_run_uumain(&args, uumain, None);
139142

140143
let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false, None) {
141144
Ok(result) => result,
@@ -151,6 +154,9 @@ fuzz_target!(|_data: &[u8]| {
151154
}
152155
};
153156

157+
// Lower the number of false positives caused by binary names
158+
replace_fuzz_binary_name("cksum", &mut rust_result);
159+
154160
compare_result(
155161
"cksum",
156162
&format!("{:?}", &args[1..]),
Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6+
use console::Style;
67
use libc::STDIN_FILENO;
78
use libc::{close, dup, dup2, pipe, STDERR_FILENO, STDOUT_FILENO};
9+
use pretty_print::{
10+
print_diff, print_end_with_status, print_or_empty, print_section, print_with_style,
11+
};
812
use rand::prelude::IndexedRandom;
913
use rand::Rng;
10-
use similar::TextDiff;
1114
use std::env::temp_dir;
1215
use std::ffi::OsString;
1316
use std::fs::File;
@@ -18,6 +21,8 @@ use std::sync::atomic::Ordering;
1821
use std::sync::{atomic::AtomicBool, Once};
1922
use std::{io, thread};
2023

24+
pub mod pretty_print;
25+
2126
/// Represents the result of running a command, including its standard output,
2227
/// standard error, and exit code.
2328
pub struct CommandResult {
@@ -315,8 +320,8 @@ pub fn compare_result(
315320
gnu_result: &CommandResult,
316321
fail_on_stderr_diff: bool,
317322
) {
318-
println!("Test Type: {}", test_type);
319-
println!("Input: {}", input);
323+
print_section(format!("Compare result for: {} {}", test_type, input));
324+
320325
if let Some(pipe) = pipe_input {
321326
println!("Pipe: {}", pipe);
322327
}
@@ -326,49 +331,58 @@ pub fn compare_result(
326331

327332
if rust_result.stdout.trim() != gnu_result.stdout.trim() {
328333
discrepancies.push("stdout differs");
329-
println!("Rust stdout: {}", rust_result.stdout);
330-
println!("GNU stdout: {}", gnu_result.stdout);
334+
println!("Rust stdout:",);
335+
print_or_empty(rust_result.stdout.as_str());
336+
println!("GNU stdout:",);
337+
print_or_empty(gnu_result.stdout.as_ref());
331338
print_diff(&rust_result.stdout, &gnu_result.stdout);
332339
should_panic = true;
333340
}
341+
334342
if rust_result.stderr.trim() != gnu_result.stderr.trim() {
335343
discrepancies.push("stderr differs");
336-
println!("Rust stderr: {}", rust_result.stderr);
337-
println!("GNU stderr: {}", gnu_result.stderr);
344+
println!("Rust stderr:",);
345+
print_or_empty(rust_result.stderr.as_str());
346+
println!("GNU stderr:",);
347+
print_or_empty(gnu_result.stderr.as_str());
338348
print_diff(&rust_result.stderr, &gnu_result.stderr);
339349
if fail_on_stderr_diff {
340350
should_panic = true;
341351
}
342352
}
353+
343354
if rust_result.exit_code != gnu_result.exit_code {
344355
discrepancies.push("exit code differs");
345-
println!("Rust exit code: {}", rust_result.exit_code);
346-
println!("GNU exit code: {}", gnu_result.exit_code);
356+
println!(
357+
"Different exit code: (Rust: {}, GNU: {})",
358+
rust_result.exit_code, gnu_result.exit_code
359+
);
347360
should_panic = true;
348361
}
349362

350363
if discrepancies.is_empty() {
351-
println!("All outputs and exit codes matched.");
364+
print_end_with_status("Same behavior", true);
352365
} else {
353-
println!("Discrepancy detected: {}", discrepancies.join(", "));
366+
print_with_style(
367+
format!("Discrepancies detected: {}", discrepancies.join(", ")),
368+
Style::new().red(),
369+
);
354370
if should_panic {
355-
panic!("Test failed for {}: {}", test_type, input);
371+
print_end_with_status(
372+
format!("Test failed and will panic for: {} {}", test_type, input),
373+
false,
374+
);
375+
panic!("Test failed for: {} {}", test_type, input);
356376
} else {
357-
println!(
358-
"Test completed with discrepancies for {}: {}",
359-
test_type, input
377+
print_end_with_status(
378+
format!(
379+
"Test completed with discrepancies for: {} {}",
380+
test_type, input
381+
),
382+
false,
360383
);
361384
}
362385
}
363-
}
364-
365-
/// When we have different outputs, print the diff
366-
fn print_diff(rust_output: &str, gnu_output: &str) {
367-
println!("Diff=");
368-
let diff = TextDiff::from_lines(rust_output, gnu_output);
369-
for change in diff.iter_all_changes() {
370-
print!("{}{}", change.tag(), change);
371-
}
372386
println!();
373387
}
374388

@@ -414,3 +428,10 @@ pub fn generate_random_file() -> Result<String, std::io::Error> {
414428

415429
Ok(file_path.to_str().unwrap().to_string())
416430
}
431+
432+
pub fn replace_fuzz_binary_name(cmd: &str, result: &mut CommandResult) {
433+
let fuzz_bin_name = format!("fuzz/target/x86_64-unknown-linux-gnu/release/fuzz_{cmd}");
434+
435+
result.stdout = result.stdout.replace(&fuzz_bin_name, cmd);
436+
result.stderr = result.stderr.replace(&fuzz_bin_name, cmd);
437+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// This file is part of the uutils coreutils package.
2+
//
3+
// For the full copyright and license information, please view the LICENSE
4+
// file that was distributed with this source code.
5+
6+
use std::fmt;
7+
8+
use console::{style, Style};
9+
use similar::TextDiff;
10+
11+
pub fn print_section<S: fmt::Display>(s: S) {
12+
println!("{}", style(format!("=== {}", s)).bold());
13+
}
14+
15+
pub fn print_subsection<S: fmt::Display>(s: S) {
16+
println!("{}", style(format!("--- {}", s)).bright());
17+
}
18+
19+
pub fn print_test_begin<S: fmt::Display>(msg: S) {
20+
println!(
21+
"{} {} {}",
22+
style("===").bold(), // Kind of gray
23+
style("TEST").black().on_yellow().bold(),
24+
style(msg).bold()
25+
);
26+
}
27+
28+
pub fn print_end_with_status<S: fmt::Display>(msg: S, ok: bool) {
29+
let ok = if ok {
30+
style(" OK ").black().on_green().bold()
31+
} else {
32+
style(" KO ").black().on_red().bold()
33+
};
34+
35+
println!(
36+
"{} {} {}",
37+
style("===").bold(), // Kind of gray
38+
ok,
39+
style(msg).bold()
40+
);
41+
}
42+
43+
pub fn print_or_empty(s: &str) {
44+
let to_print = if s.is_empty() { "(empty)" } else { s };
45+
46+
println!("{}", style(to_print).dim());
47+
}
48+
49+
pub fn print_with_style<S: fmt::Display>(msg: S, style: Style) {
50+
println!("{}", style.apply_to(msg));
51+
}
52+
53+
pub fn print_diff<'a, 'b>(got: &'a str, expected: &'b str) {
54+
let diff = TextDiff::from_lines(got, expected);
55+
56+
print_subsection("START diff");
57+
58+
for change in diff.iter_all_changes() {
59+
let (sign, style) = match change.tag() {
60+
similar::ChangeTag::Equal => (" ", Style::new().dim()),
61+
similar::ChangeTag::Delete => ("-", Style::new().red()),
62+
similar::ChangeTag::Insert => ("+", Style::new().green()),
63+
};
64+
print!("{}{}", style.apply_to(sign).bold(), style.apply_to(change));
65+
}
66+
67+
print_subsection("END diff");
68+
println!();
69+
}

0 commit comments

Comments
 (0)