diff --git a/src/bin/cargo/commands/run.rs b/src/bin/cargo/commands/run.rs index 540513ca12a..f30e8570d01 100644 --- a/src/bin/cargo/commands/run.rs +++ b/src/bin/cargo/commands/run.rs @@ -72,7 +72,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { }; } }; - match ops::run(&ws, &compile_opts, &values(args, "args"))? { + match ops::run(&ws, &compile_opts, &values_os(args, "args"))? { None => Ok(()), Some(err) => { // If we never actually spawned the process then that sounds pretty diff --git a/src/cargo/ops/cargo_run.rs b/src/cargo/ops/cargo_run.rs index fe3bcea952d..7fc99211505 100644 --- a/src/cargo/ops/cargo_run.rs +++ b/src/cargo/ops/cargo_run.rs @@ -1,3 +1,4 @@ +use std::ffi::OsString; use std::iter; use std::path::Path; @@ -8,7 +9,7 @@ use crate::util::{CargoResult, ProcessError}; pub fn run( ws: &Workspace<'_>, options: &ops::CompileOptions<'_>, - args: &[String], + args: &[OsString], ) -> CargoResult> { let config = ws.config(); diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 21be7e86f4b..8d6963c6d9a 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -1,3 +1,4 @@ +use std::ffi::{OsStr, OsString}; use std::fs; use std::path::PathBuf; @@ -463,6 +464,10 @@ about this warning."; fn _values_of(&self, name: &str) -> Vec; + fn _value_of_os(&self, name: &str) -> Option<&OsStr>; + + fn _values_of_os(&self, name: &str) -> Vec; + fn _is_present(&self, name: &str) -> bool; } @@ -471,6 +476,10 @@ impl<'a> ArgMatchesExt for ArgMatches<'a> { self.value_of(name) } + fn _value_of_os(&self, name: &str) -> Option<&OsStr> { + self.value_of_os(name) + } + fn _values_of(&self, name: &str) -> Vec { self.values_of(name) .unwrap_or_default() @@ -478,6 +487,13 @@ impl<'a> ArgMatchesExt for ArgMatches<'a> { .collect() } + fn _values_of_os(&self, name: &str) -> Vec { + self.values_of_os(name) + .unwrap_or_default() + .map(|s| s.to_os_string()) + .collect() + } + fn _is_present(&self, name: &str) -> bool { self.is_present(name) } @@ -487,6 +503,10 @@ pub fn values(args: &ArgMatches<'_>, name: &str) -> Vec { args._values_of(name) } +pub fn values_os(args: &ArgMatches<'_>, name: &str) -> Vec { + args._values_of_os(name) +} + #[derive(PartialEq, PartialOrd, Eq, Ord)] pub enum CommandInfo { BuiltIn { name: String, about: Option }, diff --git a/tests/testsuite/run.rs b/tests/testsuite/run.rs index 38ae8fe728c..e596dede15f 100644 --- a/tests/testsuite/run.rs +++ b/tests/testsuite/run.rs @@ -75,6 +75,32 @@ fn simple_with_args() { p.cargo("run hello world").run(); } +#[cfg(unix)] +#[test] +fn simple_with_non_utf8_args() { + use std::os::unix::ffi::OsStrExt; + + let p = project() + .file( + "src/main.rs", + r#" + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt; + + fn main() { + assert_eq!(std::env::args_os().nth(1).unwrap(), OsStr::from_bytes(b"hello")); + assert_eq!(std::env::args_os().nth(2).unwrap(), OsStr::from_bytes(b"ab\xffcd")); + } + "#, + ) + .build(); + + p.cargo("run") + .arg("hello") + .arg(std::ffi::OsStr::from_bytes(b"ab\xFFcd")) + .run(); +} + #[test] fn exit_code() { let p = project()