Skip to content

Commit 7afcf51

Browse files
committed
Always quote program name in Command::spawn on Windows
`CreateProcess` will interpret args as part of the binary name if it doesn't find the binary using just the unquoted name. For example if `foo.exe` doesn't exist, `Command::new("foo").arg("bar").spawn()` will try to launch `foo bar.exe` which is clearly not desired.
1 parent 0da9721 commit 7afcf51

File tree

1 file changed

+10
-8
lines changed

1 file changed

+10
-8
lines changed

src/libstd/sys/windows/process.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -427,20 +427,22 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
427427
// Encode the command and arguments in a command line string such
428428
// that the spawned process may recover them using CommandLineToArgvW.
429429
let mut cmd: Vec<u16> = Vec::new();
430-
append_arg(&mut cmd, prog)?;
430+
// Always quote the program name so CreateProcess doesn't interpret args as
431+
// part of the name if the binary wasn't found first time.
432+
append_arg(&mut cmd, prog, true)?;
431433
for arg in args {
432434
cmd.push(' ' as u16);
433-
append_arg(&mut cmd, arg)?;
435+
append_arg(&mut cmd, arg, false)?;
434436
}
435437
return Ok(cmd);
436438

437-
fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr) -> io::Result<()> {
439+
fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> io::Result<()> {
438440
// If an argument has 0 characters then we need to quote it to ensure
439441
// that it actually gets passed through on the command line or otherwise
440442
// it will be dropped entirely when parsed on the other end.
441443
ensure_no_nuls(arg)?;
442444
let arg_bytes = &arg.as_inner().inner.as_inner();
443-
let quote = arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t')
445+
let quote = force_quotes || arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t')
444446
|| arg_bytes.is_empty();
445447
if quote {
446448
cmd.push('"' as u16);
@@ -526,7 +528,7 @@ mod tests {
526528

527529
assert_eq!(
528530
test_wrapper("prog", &["aaa", "bbb", "ccc"]),
529-
"prog aaa bbb ccc"
531+
"\"prog\" aaa bbb ccc"
530532
);
531533

532534
assert_eq!(
@@ -539,15 +541,15 @@ mod tests {
539541
);
540542
assert_eq!(
541543
test_wrapper("echo", &["a b c"]),
542-
"echo \"a b c\""
544+
"\"echo\" \"a b c\""
543545
);
544546
assert_eq!(
545547
test_wrapper("echo", &["\" \\\" \\", "\\"]),
546-
"echo \"\\\" \\\\\\\" \\\\\" \\"
548+
"\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
547549
);
548550
assert_eq!(
549551
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
550-
"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}"
552+
"\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
551553
);
552554
}
553555
}

0 commit comments

Comments
 (0)