From e6f9e358d4f3365ea62ef86ddbe5b5b3f71a3dbf Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Thu, 28 Sep 2023 21:48:34 +0200 Subject: [PATCH 1/2] fuzz: create a function run_gnu_cmd to deduplicate the code --- fuzz/fuzz_targets/fuzz_common.rs | 30 ++++++++++++++++++++++++++++++ fuzz/fuzz_targets/fuzz_expr.rs | 28 ++-------------------------- fuzz/fuzz_targets/fuzz_test.rs | 20 ++------------------ 3 files changed, 34 insertions(+), 44 deletions(-) diff --git a/fuzz/fuzz_targets/fuzz_common.rs b/fuzz/fuzz_targets/fuzz_common.rs index a33d603f130..351a7e8e8af 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}; @@ -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_expr.rs b/fuzz/fuzz_targets/fuzz_expr.rs index 28fded99e07..6344c052575 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" @@ -111,7 +87,7 @@ fuzz_target!(|_data: &[u8]| { let (rust_output, uumain_exit_code) = generate_and_run_uumain(&mut 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 { diff --git a/fuzz/fuzz_targets/fuzz_test.rs b/fuzz/fuzz_targets/fuzz_test.rs index dbd2db54ab0..bfde25246d9 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" @@ -223,7 +207,7 @@ fuzz_target!(|_data: &[u8]| { let (rust_output, uumain_exit_status) = generate_and_run_uumain(&mut 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); From a576054d42373ee3e502f015ffb998cc232df824 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Thu, 28 Sep 2023 21:52:26 +0200 Subject: [PATCH 2/2] fuzz: fix clippy warnings --- fuzz/fuzz_targets/fuzz_common.rs | 4 ++-- fuzz/fuzz_targets/fuzz_date.rs | 2 +- fuzz/fuzz_targets/fuzz_expr.rs | 14 +++++++------- fuzz/fuzz_targets/fuzz_parse_glob.rs | 2 +- fuzz/fuzz_targets/fuzz_test.rs | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fuzz/fuzz_targets/fuzz_common.rs b/fuzz/fuzz_targets/fuzz_common.rs index 351a7e8e8af..a94963ef024 100644 --- a/fuzz/fuzz_targets/fuzz_common.rs +++ b/fuzz/fuzz_targets/fuzz_common.rs @@ -32,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, { @@ -45,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) }; } diff --git a/fuzz/fuzz_targets/fuzz_date.rs b/fuzz/fuzz_targets/fuzz_date.rs index 96c56cc6bf2..0f9cb262c06 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 6344c052575..fb7b1730956 100644 --- a/fuzz/fuzz_targets/fuzz_expr.rs +++ b/fuzz/fuzz_targets/fuzz_expr.rs @@ -84,7 +84,7 @@ 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_cmd(CMD_PATH, &args[1..], true) { @@ -96,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 061569bc418..e235c0c9d89 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 bfde25246d9..4805a41af16 100644 --- a/fuzz/fuzz_targets/fuzz_test.rs +++ b/fuzz/fuzz_targets/fuzz_test.rs @@ -142,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"); @@ -204,7 +204,7 @@ 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_cmd(CMD_PATH, &args[1..], false) {