Skip to content

Commit f43a29d

Browse files
committed
Auto merge of #6849 - johnbartholomew:issue-2511-cargo-non-utf8-args, r=alexcrichton
Pass OsStr/OsString args through to the process spawned by cargo run. This is intended to fix #2511, allowing non-UTF8 arguments to be passed through from cargo run to the spawned process. I was not sure whether the interface of cargo::ops needs to remain unchanged - I assume it does, so I added cargo::ops::run_os() taking &[OsString], and retained cargo::ops::run() with its current signature. If it's ok to change the internal cargo API then it may be better to just pass &[OsString] to run(). I have not tried to pass through OsStr/OsString to other places that could reasonably use them. Just one test added covering this path. It is restricted to `cfg(unix)` due to use of `std::os::unix::ffi::OsStrExt`. This is my first pull request so I expect there will be changes needed to make this mergeable.
2 parents 156cd3e + 6d066a6 commit f43a29d

File tree

4 files changed

+49
-2
lines changed

4 files changed

+49
-2
lines changed

src/bin/cargo/commands/run.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
7272
};
7373
}
7474
};
75-
match ops::run(&ws, &compile_opts, &values(args, "args"))? {
75+
match ops::run(&ws, &compile_opts, &values_os(args, "args"))? {
7676
None => Ok(()),
7777
Some(err) => {
7878
// If we never actually spawned the process then that sounds pretty

src/cargo/ops/cargo_run.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::ffi::OsString;
12
use std::iter;
23
use std::path::Path;
34

@@ -8,7 +9,7 @@ use crate::util::{CargoResult, ProcessError};
89
pub fn run(
910
ws: &Workspace<'_>,
1011
options: &ops::CompileOptions<'_>,
11-
args: &[String],
12+
args: &[OsString],
1213
) -> CargoResult<Option<ProcessError>> {
1314
let config = ws.config();
1415

src/cargo/util/command_prelude.rs

+20
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::ffi::{OsStr, OsString};
12
use std::fs;
23
use std::path::PathBuf;
34

@@ -463,6 +464,10 @@ about this warning.";
463464

464465
fn _values_of(&self, name: &str) -> Vec<String>;
465466

467+
fn _value_of_os(&self, name: &str) -> Option<&OsStr>;
468+
469+
fn _values_of_os(&self, name: &str) -> Vec<OsString>;
470+
466471
fn _is_present(&self, name: &str) -> bool;
467472
}
468473

@@ -471,13 +476,24 @@ impl<'a> ArgMatchesExt for ArgMatches<'a> {
471476
self.value_of(name)
472477
}
473478

479+
fn _value_of_os(&self, name: &str) -> Option<&OsStr> {
480+
self.value_of_os(name)
481+
}
482+
474483
fn _values_of(&self, name: &str) -> Vec<String> {
475484
self.values_of(name)
476485
.unwrap_or_default()
477486
.map(|s| s.to_string())
478487
.collect()
479488
}
480489

490+
fn _values_of_os(&self, name: &str) -> Vec<OsString> {
491+
self.values_of_os(name)
492+
.unwrap_or_default()
493+
.map(|s| s.to_os_string())
494+
.collect()
495+
}
496+
481497
fn _is_present(&self, name: &str) -> bool {
482498
self.is_present(name)
483499
}
@@ -487,6 +503,10 @@ pub fn values(args: &ArgMatches<'_>, name: &str) -> Vec<String> {
487503
args._values_of(name)
488504
}
489505

506+
pub fn values_os(args: &ArgMatches<'_>, name: &str) -> Vec<OsString> {
507+
args._values_of_os(name)
508+
}
509+
490510
#[derive(PartialEq, PartialOrd, Eq, Ord)]
491511
pub enum CommandInfo {
492512
BuiltIn { name: String, about: Option<String> },

tests/testsuite/run.rs

+26
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,32 @@ fn simple_with_args() {
7575
p.cargo("run hello world").run();
7676
}
7777

78+
#[cfg(unix)]
79+
#[test]
80+
fn simple_with_non_utf8_args() {
81+
use std::os::unix::ffi::OsStrExt;
82+
83+
let p = project()
84+
.file(
85+
"src/main.rs",
86+
r#"
87+
use std::ffi::OsStr;
88+
use std::os::unix::ffi::OsStrExt;
89+
90+
fn main() {
91+
assert_eq!(std::env::args_os().nth(1).unwrap(), OsStr::from_bytes(b"hello"));
92+
assert_eq!(std::env::args_os().nth(2).unwrap(), OsStr::from_bytes(b"ab\xffcd"));
93+
}
94+
"#,
95+
)
96+
.build();
97+
98+
p.cargo("run")
99+
.arg("hello")
100+
.arg(std::ffi::OsStr::from_bytes(b"ab\xFFcd"))
101+
.run();
102+
}
103+
78104
#[test]
79105
fn exit_code() {
80106
let p = project()

0 commit comments

Comments
 (0)