Skip to content

Commit

Permalink
make Command.argv Send on unix platforms
Browse files Browse the repository at this point in the history
Implementing Send for a specific field rather than the whole struct is
safer: if a field is changed/modified and becomes non-Send, we can catch
it.
  • Loading branch information
little-dude committed Jan 26, 2018
1 parent 831ff77 commit 9e6ed17
Showing 1 changed file with 11 additions and 10 deletions.
21 changes: 11 additions & 10 deletions src/libstd/sys/unix/process/process_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub struct Command {
// other keys.
program: CString,
args: Vec<CString>,
argv: Vec<*const c_char>,
argv: Argv,
env: CommandEnv<DefaultEnvKey>,

cwd: Option<CString>,
Expand All @@ -58,6 +58,12 @@ pub struct Command {
stderr: Option<Stdio>,
}

// Create a new type for argv, so that we can make it `Send`
struct Argv(Vec<*const c_char>);

// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
unsafe impl Send for Argv {}

// passed back to std::process with the pipes connected to the child, if any
// were requested
pub struct StdioPipes {
Expand Down Expand Up @@ -87,17 +93,12 @@ pub enum Stdio {
Fd(FileDesc),
}

// Command is not Send by default due to the Command.argv field containing a raw pointers. However
// it is safe to implement Send, because anyway, these pointers point to memory owned by the
// Command.args field.
unsafe impl Send for Command {}

impl Command {
pub fn new(program: &OsStr) -> Command {
let mut saw_nul = false;
let program = os2c(program, &mut saw_nul);
Command {
argv: vec![program.as_ptr(), ptr::null()],
argv: Argv(vec![program.as_ptr(), ptr::null()]),
program,
args: Vec::new(),
env: Default::default(),
Expand All @@ -116,8 +117,8 @@ impl Command {
// Overwrite the trailing NULL pointer in `argv` and then add a new null
// pointer.
let arg = os2c(arg, &mut self.saw_nul);
self.argv[self.args.len() + 1] = arg.as_ptr();
self.argv.push(ptr::null());
self.argv.0[self.args.len() + 1] = arg.as_ptr();
self.argv.0.push(ptr::null());

// Also make sure we keep track of the owned value to schedule a
// destructor for this memory.
Expand All @@ -138,7 +139,7 @@ impl Command {
self.saw_nul
}
pub fn get_argv(&self) -> &Vec<*const c_char> {
&self.argv
&self.argv.0
}

#[allow(dead_code)]
Expand Down

0 comments on commit 9e6ed17

Please sign in to comment.