mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
fuzzing: provide a better error management
This commit is contained in:
parent
8ab20c4673
commit
104e707b07
3 changed files with 89 additions and 88 deletions
|
@ -38,8 +38,6 @@ pub fn generate_and_run_uumain<F>(args: &[OsString], uumain_function: F) -> (Str
|
||||||
where
|
where
|
||||||
F: FnOnce(std::vec::IntoIter<OsString>) -> i32,
|
F: FnOnce(std::vec::IntoIter<OsString>) -> i32,
|
||||||
{
|
{
|
||||||
let uumain_exit_status;
|
|
||||||
|
|
||||||
// Duplicate the stdout and stderr file descriptors
|
// Duplicate the stdout and stderr file descriptors
|
||||||
let original_stdout_fd = unsafe { dup(STDOUT_FILENO) };
|
let original_stdout_fd = unsafe { dup(STDOUT_FILENO) };
|
||||||
let original_stderr_fd = unsafe { dup(STDERR_FILENO) };
|
let original_stderr_fd = unsafe { dup(STDERR_FILENO) };
|
||||||
|
@ -78,7 +76,8 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
uumain_exit_status = uumain_function(args.to_owned().into_iter());
|
let uumain_exit_status = uumain_function(args.to_owned().into_iter());
|
||||||
|
|
||||||
io::stdout().flush().unwrap();
|
io::stdout().flush().unwrap();
|
||||||
io::stderr().flush().unwrap();
|
io::stderr().flush().unwrap();
|
||||||
|
|
||||||
|
@ -102,8 +101,8 @@ where
|
||||||
let captured_stdout = read_from_fd(pipe_stdout_fds[0]).trim().to_string();
|
let captured_stdout = read_from_fd(pipe_stdout_fds[0]).trim().to_string();
|
||||||
let captured_stderr = read_from_fd(pipe_stderr_fds[0]).to_string();
|
let captured_stderr = read_from_fd(pipe_stderr_fds[0]).to_string();
|
||||||
let captured_stderr = captured_stderr
|
let captured_stderr = captured_stderr
|
||||||
.splitn(2, ':')
|
.split_once(':')
|
||||||
.nth(1)
|
.map(|x| x.1)
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.trim()
|
.trim()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
@ -168,8 +167,8 @@ pub fn run_gnu_cmd(
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
|
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
|
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
|
||||||
let stderr = stderr
|
let stderr = stderr
|
||||||
.splitn(2, ':')
|
.split_once(':')
|
||||||
.nth(1)
|
.map(|x| x.1)
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.trim()
|
.trim()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
@ -180,3 +179,56 @@ pub fn run_gnu_cmd(
|
||||||
Err((stdout, stderr, exit_code))
|
Err((stdout, stderr, exit_code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compare_result(
|
||||||
|
test_type: &str,
|
||||||
|
input: &str,
|
||||||
|
rust_stdout: &str,
|
||||||
|
gnu_stdout: &str,
|
||||||
|
rust_stderr: &str,
|
||||||
|
gnu_stderr: &str,
|
||||||
|
rust_exit_code: i32,
|
||||||
|
gnu_exit_code: i32,
|
||||||
|
fail_on_stderr_diff: bool,
|
||||||
|
) {
|
||||||
|
println!("Test Type: {}", test_type);
|
||||||
|
println!("Input: {}", input);
|
||||||
|
|
||||||
|
let mut discrepancies = Vec::new();
|
||||||
|
let mut should_panic = false;
|
||||||
|
|
||||||
|
if rust_stdout.trim() != gnu_stdout.trim() {
|
||||||
|
discrepancies.push("stdout differs");
|
||||||
|
println!("Rust stdout: {}", rust_stdout);
|
||||||
|
println!("GNU stdout: {}", gnu_stdout);
|
||||||
|
should_panic = true;
|
||||||
|
}
|
||||||
|
if rust_stderr.trim() != gnu_stderr.trim() {
|
||||||
|
discrepancies.push("stderr differs");
|
||||||
|
println!("Rust stderr: {}", rust_stderr);
|
||||||
|
println!("GNU stderr: {}", gnu_stderr);
|
||||||
|
if fail_on_stderr_diff {
|
||||||
|
should_panic = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rust_exit_code != gnu_exit_code {
|
||||||
|
discrepancies.push("exit code differs");
|
||||||
|
println!("Rust exit code: {}", rust_exit_code);
|
||||||
|
println!("GNU exit code: {}", gnu_exit_code);
|
||||||
|
should_panic = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if discrepancies.is_empty() {
|
||||||
|
println!("All outputs and exit codes matched.");
|
||||||
|
} else {
|
||||||
|
println!("Discrepancy detected: {}", discrepancies.join(", "));
|
||||||
|
if should_panic {
|
||||||
|
panic!("Test failed for {}: {}", test_type, input);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"Test completed with discrepancies for {}: {}",
|
||||||
|
test_type, input
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use rand::Rng;
|
||||||
use std::{env, ffi::OsString};
|
use std::{env, ffi::OsString};
|
||||||
|
|
||||||
mod fuzz_common;
|
mod fuzz_common;
|
||||||
use crate::fuzz_common::{generate_and_run_uumain, run_gnu_cmd};
|
use crate::fuzz_common::{compare_result, generate_and_run_uumain, run_gnu_cmd};
|
||||||
|
|
||||||
static CMD_PATH: &str = "expr";
|
static CMD_PATH: &str = "expr";
|
||||||
|
|
||||||
|
@ -84,52 +84,25 @@ fuzz_target!(|_data: &[u8]| {
|
||||||
let mut args = vec![OsString::from("expr")];
|
let mut args = vec![OsString::from("expr")];
|
||||||
args.extend(expr.split_whitespace().map(OsString::from));
|
args.extend(expr.split_whitespace().map(OsString::from));
|
||||||
|
|
||||||
let (rust_stdout, rust_stderr, uumain_exit_code) = generate_and_run_uumain(&args, uumain);
|
|
||||||
|
|
||||||
// Use C locale to avoid false positives, like in https://github.com/uutils/coreutils/issues/5378,
|
// Use C locale to avoid false positives, like in https://github.com/uutils/coreutils/issues/5378,
|
||||||
// because uutils expr doesn't support localization yet
|
// because uutils expr doesn't support localization yet
|
||||||
// TODO remove once uutils expr supports localization
|
// TODO remove once uutils expr supports localization
|
||||||
env::set_var("LC_COLLATE", "C");
|
env::set_var("LC_COLLATE", "C");
|
||||||
|
|
||||||
// Run GNU expr with the provided arguments and compare the output
|
let (rust_stdout, rust_stderr, uumain_exit_code) = generate_and_run_uumain(&args, uumain);
|
||||||
match run_gnu_cmd(CMD_PATH, &args[1..], true) {
|
|
||||||
Ok((gnu_stdout, gnu_stderr, gnu_exit_code)) => {
|
|
||||||
let gnu_stdout = gnu_stdout.trim().to_owned();
|
|
||||||
if uumain_exit_code != gnu_exit_code {
|
|
||||||
println!("Expression: {}", expr);
|
|
||||||
|
|
||||||
println!("GNU stderr: {}", gnu_stderr);
|
let (gnu_stdout, gnu_stderr, gnu_exit_code) =
|
||||||
println!("Rust stderr: {}", rust_stderr);
|
run_gnu_cmd(CMD_PATH, &args[1..], false).unwrap_or_else(|e| e);
|
||||||
|
|
||||||
println!("Rust code: {}", uumain_exit_code);
|
compare_result(
|
||||||
println!("GNU code: {}", gnu_exit_code);
|
"expr",
|
||||||
panic!("Different error codes");
|
&format!("{:?}", &args[1..]),
|
||||||
}
|
&rust_stdout,
|
||||||
if rust_stdout == gnu_stdout {
|
&gnu_stdout,
|
||||||
println!(
|
&rust_stderr,
|
||||||
"Outputs matched for expression: {} => Result: {}",
|
&gnu_stderr,
|
||||||
expr, rust_stdout
|
uumain_exit_code,
|
||||||
);
|
gnu_exit_code,
|
||||||
} else {
|
false, // Set to true if you want to fail on stderr diff
|
||||||
println!("Expression: {}", expr);
|
);
|
||||||
println!("Rust output: {}", rust_stdout);
|
|
||||||
println!("GNU output: {}", gnu_stdout);
|
|
||||||
panic!("Different output between Rust & GNU");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err((_gnu_stdout, gnu_stderr, _gnu_exit_code)) => {
|
|
||||||
if rust_stderr == gnu_stderr {
|
|
||||||
println!(
|
|
||||||
"GNU execution failed for input: {} stderr: {}",
|
|
||||||
expr, rust_stderr
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!("Input: {}", expr);
|
|
||||||
println!("Rust stderr: {}", rust_stderr);
|
|
||||||
println!("GNU stderr: {}", gnu_stderr);
|
|
||||||
panic!("Different stderr between Rust & GNU");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@ use rand::Rng;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
|
||||||
mod fuzz_common;
|
mod fuzz_common;
|
||||||
use crate::fuzz_common::{generate_and_run_uumain, run_gnu_cmd};
|
use crate::fuzz_common::{compare_result, generate_and_run_uumain, run_gnu_cmd};
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
enum ArgType {
|
enum ArgType {
|
||||||
|
@ -204,44 +204,20 @@ fuzz_target!(|_data: &[u8]| {
|
||||||
args.push(OsString::from(generate_test_arg()));
|
args.push(OsString::from(generate_test_arg()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (rust_stdout, rust_stderr, uumain_exit_status) = generate_and_run_uumain(&args, uumain);
|
let (rust_stdout, rust_stderr, uumain_exit_code) = generate_and_run_uumain(&args, uumain);
|
||||||
|
|
||||||
// Run GNU test with the provided arguments and compare the output
|
let (gnu_stdout, gnu_stderr, gnu_exit_code) =
|
||||||
match run_gnu_cmd(CMD_PATH, &args[1..], false) {
|
run_gnu_cmd(CMD_PATH, &args[1..], false).unwrap_or_else(|e| e);
|
||||||
Ok((gnu_stdout, gnu_stderr, gnu_exit_status)) => {
|
|
||||||
let gnu_stdout = gnu_stdout.trim().to_owned();
|
|
||||||
println!("gnu_exit_status {}", gnu_exit_status);
|
|
||||||
println!("uumain_exit_status {}", uumain_exit_status);
|
|
||||||
if rust_stdout != gnu_stdout || uumain_exit_status != gnu_exit_status {
|
|
||||||
println!("Discrepancy detected!");
|
|
||||||
println!("Test: {:?}", &args[1..]);
|
|
||||||
println!("Rust output: {}", rust_stdout);
|
|
||||||
println!("GNU output: {}", gnu_stdout);
|
|
||||||
|
|
||||||
println!("Rust stderr: {}", rust_stderr);
|
compare_result(
|
||||||
println!("GNU stderr: {}", gnu_stderr);
|
"test",
|
||||||
println!("My exit status: {}", uumain_exit_status);
|
&format!("{:?}", &args[1..]),
|
||||||
println!("GNU exit status: {}", gnu_exit_status);
|
&rust_stdout,
|
||||||
panic!();
|
&gnu_stdout,
|
||||||
} else {
|
&rust_stderr,
|
||||||
println!(
|
&gnu_stderr,
|
||||||
"Outputs and exit statuses matched for expression {:?}",
|
uumain_exit_code,
|
||||||
&args[1..]
|
gnu_exit_code,
|
||||||
);
|
false, // Set to true if you want to fail on stderr diff
|
||||||
}
|
);
|
||||||
}
|
|
||||||
Err((_gnu_stdout, gnu_stderr, _gnu_exit_code)) => {
|
|
||||||
if rust_stderr == gnu_stderr {
|
|
||||||
println!(
|
|
||||||
"GNU execution failed for input: {:?} stderr: {}",
|
|
||||||
args, rust_stderr
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!("Input: {:?}", args);
|
|
||||||
println!("Rust stderr: {}", rust_stderr);
|
|
||||||
println!("GNU stderr: {}", gnu_stderr);
|
|
||||||
panic!("Different stderr between Rust & GNU");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue