Skip to content

Commit

Permalink
Merge pull request #5332 from sylvestre/fuzz
Browse files Browse the repository at this point in the history
fuzz: move the common duplicated code into a function
  • Loading branch information
cakebaker authored Sep 28, 2023
2 parents 47a8730 + a17ede9 commit aa0437c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 98 deletions.
47 changes: 47 additions & 0 deletions fuzz/fuzz_targets/fuzz_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

use libc::{dup, dup2, STDOUT_FILENO};
use std::ffi::OsString;
use std::process::Command;
use std::sync::atomic::Ordering;
use std::sync::{atomic::AtomicBool, Once};
Expand All @@ -28,3 +30,48 @@ pub fn is_gnu_cmd(cmd_path: &str) -> Result<(), std::io::Error> {
panic!("Not the GNU implementation");
}
}

pub fn generate_and_run_uumain<F>(args: &mut Vec<OsString>, uumain_function: F) -> (String, i32)
where
F: FnOnce(std::vec::IntoIter<OsString>) -> i32,
{
let uumain_exit_status;

let original_stdout_fd = unsafe { dup(STDOUT_FILENO) };
println!("Running test {:?}", &args[1..]);
let mut pipe_fds = [-1; 2];
unsafe { libc::pipe(pipe_fds.as_mut_ptr()) };

{
unsafe { dup2(pipe_fds[1], STDOUT_FILENO) };
uumain_exit_status = uumain_function(args.clone().into_iter());
unsafe { dup2(original_stdout_fd, STDOUT_FILENO) };
unsafe { libc::close(original_stdout_fd) };
}
unsafe { libc::close(pipe_fds[1]) };

let mut captured_output = Vec::new();
let mut read_buffer = [0; 1024];
loop {
let bytes_read = unsafe {
libc::read(
pipe_fds[0],
read_buffer.as_mut_ptr() as *mut libc::c_void,
read_buffer.len(),
)
};
if bytes_read <= 0 {
break;
}
captured_output.extend_from_slice(&read_buffer[..bytes_read as usize]);
}

unsafe { libc::close(pipe_fds[0]) };

let my_output = String::from_utf8_lossy(&captured_output)
.to_string()
.trim()
.to_owned();

(my_output, uumain_exit_status)
}
49 changes: 2 additions & 47 deletions fuzz/fuzz_targets/fuzz_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ use rand::seq::SliceRandom;
use rand::Rng;
use std::ffi::OsString;

use libc::{dup, dup2, STDOUT_FILENO};
use std::process::Command;
mod fuzz_common;
use crate::fuzz_common::generate_and_run_uumain;
use crate::fuzz_common::is_gnu_cmd;

static CMD_PATH: &str = "expr";
Expand Down Expand Up @@ -108,52 +108,7 @@ fuzz_target!(|_data: &[u8]| {
let mut args = vec![OsString::from("expr")];
args.extend(expr.split_whitespace().map(OsString::from));

// Save the original stdout file descriptor
let original_stdout_fd = unsafe { dup(STDOUT_FILENO) };

// Create a pipe to capture stdout
let mut pipe_fds = [-1; 2];
unsafe { libc::pipe(pipe_fds.as_mut_ptr()) };
let uumain_exit_code;
{
// Redirect stdout to the write end of the pipe
unsafe { dup2(pipe_fds[1], STDOUT_FILENO) };

// Run uumain with the provided arguments
uumain_exit_code = uumain(args.clone().into_iter());

// Restore original stdout
unsafe { dup2(original_stdout_fd, STDOUT_FILENO) };
unsafe { libc::close(original_stdout_fd) };
}
// Close the write end of the pipe
unsafe { libc::close(pipe_fds[1]) };

// Read captured output from the read end of the pipe
let mut captured_output = Vec::new();
let mut read_buffer = [0; 1024];
loop {
let bytes_read = unsafe {
libc::read(
pipe_fds[0],
read_buffer.as_mut_ptr() as *mut libc::c_void,
read_buffer.len(),
)
};
if bytes_read <= 0 {
break;
}
captured_output.extend_from_slice(&read_buffer[..bytes_read as usize]);
}

// Close the read end of the pipe
unsafe { libc::close(pipe_fds[0]) };

// Convert captured output to a string
let rust_output = String::from_utf8_lossy(&captured_output)
.to_string()
.trim()
.to_owned();
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..]) {
Expand Down
61 changes: 10 additions & 51 deletions fuzz/fuzz_targets/fuzz_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ use rand::seq::SliceRandom;
use rand::Rng;
use std::ffi::OsString;

use libc::{dup, dup2, STDOUT_FILENO};
use std::process::Command;

mod fuzz_common;
use crate::fuzz_common::generate_and_run_uumain;

#[derive(PartialEq, Debug, Clone)]
enum ArgType {
STRING,
Expand All @@ -26,8 +28,11 @@ enum ArgType {
// Add any other types as needed
}

static CMD_PATH: &str = "test";

fn run_gnu_test(args: &[OsString]) -> Result<(String, i32), std::io::Error> {
let mut command = Command::new("test");
let mut command = Command::new(CMD_PATH);

for arg in args {
command.arg(arg);
}
Expand Down Expand Up @@ -210,69 +215,23 @@ fuzz_target!(|_data: &[u8]| {
let mut rng = rand::thread_rng();
let max_args = rng.gen_range(1..=6);
let mut args = vec![OsString::from("test")];
let uumain_exit_status;

for _ in 0..max_args {
args.push(OsString::from(generate_test_arg()));
}

// Save the original stdout file descriptor
let original_stdout_fd = unsafe { dup(STDOUT_FILENO) };
println!("Running test {:?}", &args[1..]);
// Create a pipe to capture stdout
let mut pipe_fds = [-1; 2];
unsafe { libc::pipe(pipe_fds.as_mut_ptr()) };

{
// Redirect stdout to the write end of the pipe
unsafe { dup2(pipe_fds[1], STDOUT_FILENO) };

// Run uumain with the provided arguments
uumain_exit_status = uumain(args.clone().into_iter());

// Restore original stdout
unsafe { dup2(original_stdout_fd, STDOUT_FILENO) };
unsafe { libc::close(original_stdout_fd) };
}
// Close the write end of the pipe
unsafe { libc::close(pipe_fds[1]) };

// Read captured output from the read end of the pipe
let mut captured_output = Vec::new();
let mut read_buffer = [0; 1024];
loop {
let bytes_read = unsafe {
libc::read(
pipe_fds[0],
read_buffer.as_mut_ptr() as *mut libc::c_void,
read_buffer.len(),
)
};
if bytes_read <= 0 {
break;
}
captured_output.extend_from_slice(&read_buffer[..bytes_read as usize]);
}

// Close the read end of the pipe
unsafe { libc::close(pipe_fds[0]) };

// Convert captured output to a string
let my_output = String::from_utf8_lossy(&captured_output)
.to_string()
.trim()
.to_owned();
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..]) {
Ok((gnu_output, gnu_exit_status)) => {
let gnu_output = gnu_output.trim().to_owned();
println!("gnu_exit_status {}", gnu_exit_status);
println!("uumain_exit_status {}", uumain_exit_status);
if my_output != gnu_output || uumain_exit_status != gnu_exit_status {
if rust_output != gnu_output || uumain_exit_status != gnu_exit_status {
println!("Discrepancy detected!");
println!("Test: {:?}", &args[1..]);
println!("My output: {}", my_output);
println!("My output: {}", rust_output);
println!("GNU output: {}", gnu_output);
println!("My exit status: {}", uumain_exit_status);
println!("GNU exit status: {}", gnu_exit_status);
Expand Down

0 comments on commit aa0437c

Please sign in to comment.