1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
// 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.
use rand::Rng;
use std::ffi::OsString;
use uufuzz::{generate_and_run_uumain, generate_random_string, run_gnu_cmd};
// Mock echo implementation with some bugs for demonstration
fn mock_buggy_echo_main(args: std::vec::IntoIter<OsString>) -> i32 {
let args: Vec<OsString> = args.collect();
let mut should_add_newline = true;
let mut enable_escapes = false;
let mut start_index = 1;
// Parse arguments (simplified)
for arg in args.iter().skip(1) {
let arg_str = arg.to_string_lossy();
if arg_str == "-n" {
should_add_newline = false;
start_index += 1;
} else if arg_str == "-e" {
enable_escapes = true;
start_index += 1;
} else {
break;
}
}
// Print arguments
for (i, arg) in args.iter().skip(start_index).enumerate() {
if i > 0 {
print!(" ");
}
let arg_str = arg.to_string_lossy();
if enable_escapes {
// Simulate a bug: incomplete escape sequence handling
let processed = arg_str.replace("\\n", "\n").replace("\\t", "\t");
print!("{}", processed);
} else {
print!("{}", arg_str);
}
}
if should_add_newline {
println!();
}
0
}
// Generate test arguments for echo command
fn generate_echo_args() -> Vec<OsString> {
let mut rng = rand::rng();
let mut args = vec![OsString::from("echo")];
// Randomly add flags
if rng.random_bool(0.3) {
// 30% chance
args.push(OsString::from("-n"));
}
if rng.random_bool(0.2) {
// 20% chance
args.push(OsString::from("-e"));
}
// Add 1-3 random string arguments
let num_args = rng.random_range(1..=3);
for _ in 0..num_args {
let arg = generate_random_string(rng.random_range(1..=15));
args.push(OsString::from(arg));
}
args
}
fn main() {
println!("=== Fuzzing Simulation uufuzz Example ===");
println!("This simulates how libFuzzer would test our echo implementation");
println!("against GNU echo with random inputs.\n");
let num_tests = 10;
let mut passed = 0;
let mut failed = 0;
for i in 1..=num_tests {
println!("--- Fuzz Test {} ---", i);
let args = generate_echo_args();
println!(
"Testing with args: {:?}",
args.iter().map(|s| s.to_string_lossy()).collect::<Vec<_>>()
);
// Run our implementation
let rust_result = generate_and_run_uumain(&args, mock_buggy_echo_main, None);
// Run GNU implementation
match run_gnu_cmd("echo", &args[1..], false, None) {
Ok(gnu_result) => {
// Check if results match
let stdout_match = rust_result.stdout.trim() == gnu_result.stdout.trim();
let exit_code_match = rust_result.exit_code == gnu_result.exit_code;
if stdout_match && exit_code_match {
println!("✓ PASS: Implementations match");
passed += 1;
} else {
println!("✗ FAIL: Implementations differ");
failed += 1;
// Show the difference in a controlled way (not panicking like compare_result)
if !stdout_match {
println!(" Stdout difference:");
println!(
" Ours: '{}'",
rust_result.stdout.trim().replace('\n', "\\n")
);
println!(
" GNU: '{}'",
gnu_result.stdout.trim().replace('\n', "\\n")
);
}
if !exit_code_match {
println!(
" Exit code difference: {} vs {}",
rust_result.exit_code, gnu_result.exit_code
);
}
}
}
Err(error_result) => {
println!("⚠ GNU echo not available: {}", error_result.stderr);
println!(" Our result: '{}'", rust_result.stdout.trim());
// Don't count this as pass or fail
continue;
}
}
println!();
}
println!("=== Fuzzing Results ===");
println!("Total tests: {}", num_tests);
println!("Passed: {}", passed);
println!("Failed: {}", failed);
if failed > 0 {
println!(
"\n⚠ Found {} discrepancies! In real fuzzing, these would be investigated.",
failed
);
println!("This demonstrates how differential fuzzing can find bugs in implementations.");
} else {
println!("\n✓ All tests passed! The implementations appear compatible.");
}
println!("\nIn a real libfuzzer setup, this would run thousands of iterations");
println!("automatically with more sophisticated input generation.");
}
|