-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new fuzzers: cut, sort, split and wc (#5760)
* fuzz: use thread to bypass the limitation of output Closes: #5724 many thanks to @samueltardieu * fuzz: enable seq as the stalled issue is fixed * fuzz: add 4 more fuzzers * fuzz: enable the 4 new fuzzers in the CI * remove old import Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * remove comment Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * remove comment Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * add more flags Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * add space Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * add a comment about sort local Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * wrong copy/paste Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * fuzz: import "std::env" --------- Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
- Loading branch information
Showing
6 changed files
with
409 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// This file is part of the uutils coreutils package. | ||
// | ||
// For the full copyright and license information, please view the LICENSE | ||
// file that was distributed with this source code. | ||
// spell-checker:ignore parens | ||
|
||
#![no_main] | ||
use libfuzzer_sys::fuzz_target; | ||
use uu_cut::uumain; | ||
|
||
use rand::Rng; | ||
use std::ffi::OsString; | ||
|
||
mod fuzz_common; | ||
use crate::fuzz_common::{ | ||
compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd, CommandResult, | ||
}; | ||
static CMD_PATH: &str = "cut"; | ||
|
||
fn generate_cut_args() -> String { | ||
let mut rng = rand::thread_rng(); | ||
let arg_count = rng.gen_range(1..=6); | ||
let mut args = Vec::new(); | ||
|
||
for _ in 0..arg_count { | ||
if rng.gen_bool(0.1) { | ||
args.push(generate_random_string(rng.gen_range(1..=20))); | ||
} else { | ||
match rng.gen_range(0..=4) { | ||
0 => args.push(String::from("-b") + &rng.gen_range(1..=10).to_string()), | ||
1 => args.push(String::from("-c") + &rng.gen_range(1..=10).to_string()), | ||
2 => args.push(String::from("-d,") + &generate_random_string(1)), // Using a comma as a default delimiter | ||
3 => args.push(String::from("-f") + &rng.gen_range(1..=5).to_string()), | ||
_ => (), | ||
} | ||
} | ||
} | ||
|
||
args.join(" ") | ||
} | ||
|
||
fn generate_delimited_data(count: usize) -> String { | ||
let mut rng = rand::thread_rng(); | ||
let mut lines = Vec::new(); | ||
|
||
for _ in 0..count { | ||
let fields = (0..rng.gen_range(1..=5)) | ||
.map(|_| generate_random_string(rng.gen_range(1..=10))) | ||
.collect::<Vec<_>>() | ||
.join(","); | ||
lines.push(fields); | ||
} | ||
|
||
lines.join("\n") | ||
} | ||
|
||
fuzz_target!(|_data: &[u8]| { | ||
let cut_args = generate_cut_args(); | ||
let mut args = vec![OsString::from("cut")]; | ||
args.extend(cut_args.split_whitespace().map(OsString::from)); | ||
|
||
let input_lines = generate_delimited_data(10); | ||
|
||
let rust_result = generate_and_run_uumain(&args, uumain, Some(&input_lines)); | ||
let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false, Some(&input_lines)) { | ||
Ok(result) => result, | ||
Err(error_result) => { | ||
eprintln!("Failed to run GNU command:"); | ||
eprintln!("Stderr: {}", error_result.stderr); | ||
eprintln!("Exit Code: {}", error_result.exit_code); | ||
CommandResult { | ||
stdout: String::new(), | ||
stderr: error_result.stderr, | ||
exit_code: error_result.exit_code, | ||
} | ||
} | ||
}; | ||
|
||
compare_result( | ||
"cut", | ||
&format!("{:?}", &args[1..]), | ||
Some(&input_lines), | ||
&rust_result, | ||
&gnu_result, | ||
false, // Set to true if you want to fail on stderr diff | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// This file is part of the uutils coreutils package. | ||
// | ||
// For the full copyright and license information, please view the LICENSE | ||
// file that was distributed with this source code. | ||
// spell-checker:ignore parens | ||
|
||
#![no_main] | ||
use libfuzzer_sys::fuzz_target; | ||
use uu_sort::uumain; | ||
|
||
use rand::Rng; | ||
use std::env; | ||
use std::ffi::OsString; | ||
|
||
mod fuzz_common; | ||
use crate::fuzz_common::CommandResult; | ||
use crate::fuzz_common::{ | ||
compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd, | ||
}; | ||
static CMD_PATH: &str = "sort"; | ||
|
||
fn generate_sort_args() -> String { | ||
let mut rng = rand::thread_rng(); | ||
|
||
let arg_count = rng.gen_range(1..=5); | ||
let mut args = Vec::new(); | ||
|
||
for _ in 0..arg_count { | ||
match rng.gen_range(0..=4) { | ||
0 => args.push(String::from("-r")), // Reverse the result of comparisons | ||
1 => args.push(String::from("-n")), // Compare according to string numerical value | ||
2 => args.push(String::from("-f")), // Fold lower case to upper case characters | ||
3 => args.push(generate_random_string(rng.gen_range(1..=10))), // Random string (to simulate file names) | ||
_ => args.push(String::from("-k") + &rng.gen_range(1..=5).to_string()), // Sort via a specified field | ||
} | ||
} | ||
|
||
args.join(" ") | ||
} | ||
|
||
fn generate_random_lines(count: usize) -> String { | ||
let mut rng = rand::thread_rng(); | ||
let mut lines = Vec::new(); | ||
|
||
for _ in 0..count { | ||
lines.push(generate_random_string(rng.gen_range(1..=20))); | ||
} | ||
|
||
lines.join("\n") | ||
} | ||
|
||
fuzz_target!(|_data: &[u8]| { | ||
let sort_args = generate_sort_args(); | ||
let mut args = vec![OsString::from("sort")]; | ||
args.extend(sort_args.split_whitespace().map(OsString::from)); | ||
|
||
// Generate random lines to sort | ||
let input_lines = generate_random_lines(10); | ||
|
||
let rust_result = generate_and_run_uumain(&args, uumain, Some(&input_lines)); | ||
|
||
// TODO remove once uutils sort supports localization | ||
env::set_var("LC_COLLATE", "C"); | ||
let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false, Some(&input_lines)) { | ||
Ok(result) => result, | ||
Err(error_result) => { | ||
eprintln!("Failed to run GNU command:"); | ||
eprintln!("Stderr: {}", error_result.stderr); | ||
eprintln!("Exit Code: {}", error_result.exit_code); | ||
CommandResult { | ||
stdout: String::new(), | ||
stderr: error_result.stderr, | ||
exit_code: error_result.exit_code, | ||
} | ||
} | ||
}; | ||
|
||
compare_result( | ||
"sort", | ||
&format!("{:?}", &args[1..]), | ||
None, | ||
&rust_result, | ||
&gnu_result, | ||
false, // Set to true if you want to fail on stderr diff | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// This file is part of the uutils coreutils package. | ||
// | ||
// For the full copyright and license information, please view the LICENSE | ||
// file that was distributed with this source code. | ||
// spell-checker:ignore parens | ||
|
||
#![no_main] | ||
use libfuzzer_sys::fuzz_target; | ||
use uu_split::uumain; | ||
|
||
use rand::Rng; | ||
use std::ffi::OsString; | ||
|
||
mod fuzz_common; | ||
use crate::fuzz_common::{ | ||
compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd, CommandResult, | ||
}; | ||
static CMD_PATH: &str = "split"; | ||
|
||
fn generate_split_args() -> String { | ||
let mut rng = rand::thread_rng(); | ||
let mut args = Vec::new(); | ||
|
||
match rng.gen_range(0..=9) { | ||
0 => { | ||
args.push(String::from("-a")); // Suffix length | ||
args.push(rng.gen_range(1..=8).to_string()); | ||
} | ||
1 => { | ||
args.push(String::from("--additional-suffix")); | ||
args.push(generate_random_string(5)); // Random suffix | ||
} | ||
2 => { | ||
args.push(String::from("-b")); // Bytes per output file | ||
args.push(rng.gen_range(1..=1024).to_string() + "K"); | ||
} | ||
3 => { | ||
args.push(String::from("-C")); // Line bytes | ||
args.push(rng.gen_range(1..=1024).to_string()); | ||
} | ||
4 => args.push(String::from("-d")), // Use numeric suffixes | ||
5 => args.push(String::from("-x")), // Use hex suffixes | ||
6 => { | ||
args.push(String::from("-l")); // Number of lines per output file | ||
args.push(rng.gen_range(1..=1000).to_string()); | ||
} | ||
7 => { | ||
args.push(String::from("--filter")); | ||
args.push(String::from("cat > /dev/null")); // Example filter command | ||
} | ||
8 => { | ||
args.push(String::from("-t")); // Separator | ||
args.push(String::from("\n")); // Newline as separator | ||
} | ||
9 => args.push(String::from("--verbose")), // Verbose | ||
_ => (), | ||
} | ||
|
||
args.join(" ") | ||
} | ||
|
||
// Function to generate a random string of lines | ||
fn generate_random_lines(count: usize) -> String { | ||
let mut rng = rand::thread_rng(); | ||
let mut lines = Vec::new(); | ||
|
||
for _ in 0..count { | ||
lines.push(generate_random_string(rng.gen_range(1..=20))); | ||
} | ||
|
||
lines.join("\n") | ||
} | ||
|
||
fuzz_target!(|_data: &[u8]| { | ||
let split_args = generate_split_args(); | ||
let mut args = vec![OsString::from("split")]; | ||
args.extend(split_args.split_whitespace().map(OsString::from)); | ||
|
||
let input_lines = generate_random_lines(10); | ||
|
||
let rust_result = generate_and_run_uumain(&args, uumain, Some(&input_lines)); | ||
|
||
let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false, Some(&input_lines)) { | ||
Ok(result) => result, | ||
Err(error_result) => { | ||
eprintln!("Failed to run GNU command:"); | ||
eprintln!("Stderr: {}", error_result.stderr); | ||
eprintln!("Exit Code: {}", error_result.exit_code); | ||
CommandResult { | ||
stdout: String::new(), | ||
stderr: error_result.stderr, | ||
exit_code: error_result.exit_code, | ||
} | ||
} | ||
}; | ||
|
||
compare_result( | ||
"split", | ||
&format!("{:?}", &args[1..]), | ||
None, | ||
&rust_result, | ||
&gnu_result, | ||
false, // Set to true if you want to fail on stderr diff | ||
); | ||
}); |
Oops, something went wrong.