Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions fuzz/fuzz_targets/fuzz_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,36 @@

static CMD_PATH: &str = "env";

/// A non-empty variable name. `env "=value"` is a known divergence: GNU injects
/// the empty name into environ via putenv(), we reject it on purpose.

Check warning on line 21 in fuzz/fuzz_targets/fuzz_env.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'putenv' (file:'fuzz/fuzz_targets/fuzz_env.rs', line:21)
fn generate_env_name() -> String {
let mut rng = rand::rng();
loop {
let name = generate_random_string(rng.random_range(1..10));
if !name.is_empty() {
return name;
}
}
}

fn generate_env_args() -> Vec<String> {
let mut rng = rand::rng();
let mut args = Vec::new();

let opts = ["-i", "-0", "-v", "-vv"];
for opt in &opts {
if rng.random_bool(0.2) {
args.push(opt.to_string());
}
// -i is mandatory: we run uumain in-process, so without it the Rust side
// sees the fuzzer's environment plus set_var leftovers from earlier
// iterations, while GNU runs as a child.
let mut args = vec![String::from("-i")];

if rng.random_bool(0.2) {
args.push(String::from("-0"));
}

// -v/-vv skipped: we don't print GNU's "cleaning environ"/"setenv:"/"unset:".
// https://github.com/uutils/coreutils/issues/14171

if rng.random_bool(0.3) {
args.push(format!(
"-u={}",
generate_random_string(rng.random_range(3..10))
));
args.push(String::from("-u"));
args.push(generate_env_name());
}

if rng.random_bool(0.2) {
Expand All @@ -55,7 +69,7 @@
for _ in 0..rng.random_range(0..3) {
args.push(format!(
"{}={}",
generate_random_string(5),
generate_env_name(),
generate_random_string(5)
));
}
Expand Down
25 changes: 25 additions & 0 deletions tests/by-util/test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,31 @@ fn test_empty_name() {
.stderr_only("env: warning: no name specified for value 'xyz'\n");
}

// An empty name is dropped with a warning (GNU injects it via putenv, we
// can't with set_var); the other assignments must still go through.
#[test]
fn test_empty_name_does_not_affect_other_assignments() {
let result = new_ucmd!()
.args(&["-i", "MOTOR=idle", "=zap", "GEARBOX=locked"])
.succeeds();
result.stderr_is("env: warning: no name specified for value 'zap'\n");

// Windows sorts the environment block, so don't depend on the order.
let mut vars: Vec<_> = result.stdout_str().lines().collect();
vars.sort_unstable();
assert_eq!(vars, ["GEARBOX=locked", "MOTOR=idle"]);
}

// "=" alone is name and value both empty; still just a warning, exit 0.
#[test]
fn test_empty_name_and_empty_value() {
new_ucmd!()
.args(&["-i", "="])
.succeeds()
.no_stdout()
.stderr_is("env: warning: no name specified for value ''\n");
}

#[test]
fn test_null_delimiter() {
let out = new_ucmd!()
Expand Down
Loading