diff --git a/fuzz/fuzz_targets/fuzz_common.rs b/fuzz/fuzz_targets/fuzz_common.rs index a33d603f1..a94963ef0 100644 --- a/fuzz/fuzz_targets/fuzz_common.rs +++ b/fuzz/fuzz_targets/fuzz_common.rs @@ -5,6 +5,7 @@ use libc::{dup, dup2, STDOUT_FILENO}; use std::ffi::OsString; +use std::io; use std::process::Command; use std::sync::atomic::Ordering; use std::sync::{atomic::AtomicBool, Once}; @@ -31,7 +32,7 @@ pub fn is_gnu_cmd(cmd_path: &str) -> Result<(), std::io::Error> { } } -pub fn generate_and_run_uumain(args: &mut Vec, uumain_function: F) -> (String, i32) +pub fn generate_and_run_uumain(args: &[OsString], uumain_function: F) -> (String, i32) where F: FnOnce(std::vec::IntoIter) -> i32, { @@ -44,7 +45,7 @@ where { unsafe { dup2(pipe_fds[1], STDOUT_FILENO) }; - uumain_exit_status = uumain_function(args.clone().into_iter()); + uumain_exit_status = uumain_function(args.to_owned().into_iter()); unsafe { dup2(original_stdout_fd, STDOUT_FILENO) }; unsafe { libc::close(original_stdout_fd) }; } @@ -75,3 +76,32 @@ where (my_output, uumain_exit_status) } + +pub fn run_gnu_cmd( + cmd_path: &str, + args: &[OsString], + check_gnu: bool, +) -> Result<(String, i32), io::Error> { + if check_gnu { + is_gnu_cmd(cmd_path)?; // Check if it's a GNU implementation + } + + let mut command = Command::new(cmd_path); + for arg in args { + command.arg(arg); + } + + let output = command.output()?; + let exit_code = output.status.code().unwrap_or(-1); + if output.status.success() || !check_gnu { + Ok(( + String::from_utf8_lossy(&output.stdout).to_string(), + exit_code, + )) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + format!("GNU command execution failed with exit code {}", exit_code), + )) + } +} diff --git a/fuzz/fuzz_targets/fuzz_date.rs b/fuzz/fuzz_targets/fuzz_date.rs index 96c56cc6b..0f9cb262c 100644 --- a/fuzz/fuzz_targets/fuzz_date.rs +++ b/fuzz/fuzz_targets/fuzz_date.rs @@ -9,6 +9,6 @@ fuzz_target!(|data: &[u8]| { let args = data .split(|b| *b == delim) .filter_map(|e| std::str::from_utf8(e).ok()) - .map(|e| OsString::from(e)); + .map(OsString::from); uumain(args); }); diff --git a/fuzz/fuzz_targets/fuzz_expr.rs b/fuzz/fuzz_targets/fuzz_expr.rs index 28fded99e..fb7b17309 100644 --- a/fuzz/fuzz_targets/fuzz_expr.rs +++ b/fuzz/fuzz_targets/fuzz_expr.rs @@ -12,35 +12,11 @@ use rand::seq::SliceRandom; use rand::Rng; use std::ffi::OsString; -use std::process::Command; mod fuzz_common; -use crate::fuzz_common::generate_and_run_uumain; -use crate::fuzz_common::is_gnu_cmd; +use crate::fuzz_common::{generate_and_run_uumain, run_gnu_cmd}; static CMD_PATH: &str = "expr"; -fn run_gnu_expr(args: &[OsString]) -> Result<(String, i32), std::io::Error> { - is_gnu_cmd(CMD_PATH)?; // Check if it's a GNU implementation - - let mut command = Command::new(CMD_PATH); - for arg in args { - command.arg(arg); - } - let output = command.output()?; - let exit_code = output.status.code().unwrap_or(-1); - if output.status.success() { - Ok(( - String::from_utf8_lossy(&output.stdout).to_string(), - exit_code, - )) - } else { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - format!("GNU expr execution failed with exit code {}", exit_code), - )) - } -} - fn generate_random_string(max_length: usize) -> String { let mut rng = rand::thread_rng(); let valid_utf8: Vec = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" @@ -108,10 +84,10 @@ fuzz_target!(|_data: &[u8]| { let mut args = vec![OsString::from("expr")]; args.extend(expr.split_whitespace().map(OsString::from)); - let (rust_output, uumain_exit_code) = generate_and_run_uumain(&mut args, uumain); + let (rust_output, uumain_exit_code) = generate_and_run_uumain(&args, uumain); // Run GNU expr with the provided arguments and compare the output - match run_gnu_expr(&args[1..]) { + match run_gnu_cmd(CMD_PATH, &args[1..], true) { Ok((gnu_output, gnu_exit_code)) => { let gnu_output = gnu_output.trim().to_owned(); if uumain_exit_code != gnu_exit_code { @@ -120,16 +96,16 @@ fuzz_target!(|_data: &[u8]| { println!("GNU code: {}", gnu_exit_code); panic!("Different error codes"); } - if rust_output != gnu_output { - println!("Expression: {}", expr); - println!("Rust output: {}", rust_output); - println!("GNU output: {}", gnu_output); - panic!("Different output between Rust & GNU"); - } else { + if rust_output == gnu_output { println!( "Outputs matched for expression: {} => Result: {}", expr, rust_output ); + } else { + println!("Expression: {}", expr); + println!("Rust output: {}", rust_output); + println!("GNU output: {}", gnu_output); + panic!("Different output between Rust & GNU"); } } Err(_) => { diff --git a/fuzz/fuzz_targets/fuzz_parse_glob.rs b/fuzz/fuzz_targets/fuzz_parse_glob.rs index 061569bc4..e235c0c9d 100644 --- a/fuzz/fuzz_targets/fuzz_parse_glob.rs +++ b/fuzz/fuzz_targets/fuzz_parse_glob.rs @@ -5,6 +5,6 @@ use uucore::parse_glob; fuzz_target!(|data: &[u8]| { if let Ok(s) = std::str::from_utf8(data) { - _ = parse_glob::from_str(s) + _ = parse_glob::from_str(s); } }); diff --git a/fuzz/fuzz_targets/fuzz_test.rs b/fuzz/fuzz_targets/fuzz_test.rs index dbd2db54a..4805a41af 100644 --- a/fuzz/fuzz_targets/fuzz_test.rs +++ b/fuzz/fuzz_targets/fuzz_test.rs @@ -12,10 +12,8 @@ use rand::seq::SliceRandom; use rand::Rng; use std::ffi::OsString; -use std::process::Command; - mod fuzz_common; -use crate::fuzz_common::generate_and_run_uumain; +use crate::fuzz_common::{generate_and_run_uumain, run_gnu_cmd}; #[derive(PartialEq, Debug, Clone)] enum ArgType { @@ -30,20 +28,6 @@ enum ArgType { static CMD_PATH: &str = "test"; -fn run_gnu_test(args: &[OsString]) -> Result<(String, i32), std::io::Error> { - let mut command = Command::new(CMD_PATH); - - for arg in args { - command.arg(arg); - } - let output = command.output()?; - let exit_status = output.status.code().unwrap_or(-1); // Capture the exit status code - Ok(( - String::from_utf8_lossy(&output.stdout).to_string(), - exit_status, - )) -} - fn generate_random_string(max_length: usize) -> String { let mut rng = rand::thread_rng(); let valid_utf8: Vec = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" @@ -158,7 +142,7 @@ fn generate_test_arg() -> String { 0 => { arg.push_str(&rng.gen_range(-100..=100).to_string()); } - 1 | 2 | 3 => { + 1..=3 => { let test_arg = test_args .choose(&mut rng) .expect("Failed to choose a random test argument"); @@ -220,10 +204,10 @@ fuzz_target!(|_data: &[u8]| { args.push(OsString::from(generate_test_arg())); } - let (rust_output, uumain_exit_status) = generate_and_run_uumain(&mut args, uumain); + let (rust_output, uumain_exit_status) = generate_and_run_uumain(&args, uumain); // Run GNU test with the provided arguments and compare the output - match run_gnu_test(&args[1..]) { + match run_gnu_cmd(CMD_PATH, &args[1..], false) { Ok((gnu_output, gnu_exit_status)) => { let gnu_output = gnu_output.trim().to_owned(); println!("gnu_exit_status {}", gnu_exit_status);