Skip to content

Commit 5a6bfd5

Browse files
committed
Revert "Fixes #46775 -- don't mutate the process's environment in Command::exec"
This reverts commit 36fe3b6.
1 parent 9fefb67 commit 5a6bfd5

File tree

3 files changed

+8
-111
lines changed

3 files changed

+8
-111
lines changed

src/libstd/sys/unix/process/process_common.rs

-8
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,6 @@ impl Command {
141141
pub fn get_argv(&self) -> &Vec<*const c_char> {
142142
&self.argv.0
143143
}
144-
#[cfg(not(target_os = "fuchsia"))]
145-
pub fn get_program(&self) -> &CString {
146-
return &self.program;
147-
}
148144

149145
#[allow(dead_code)]
150146
pub fn get_cwd(&self) -> &Option<CString> {
@@ -248,10 +244,6 @@ impl CStringArray {
248244
pub fn as_ptr(&self) -> *const *const c_char {
249245
self.ptrs.as_ptr()
250246
}
251-
#[cfg(not(target_os = "fuchsia"))]
252-
pub fn get_items(&self) -> &[CString] {
253-
return &self.items;
254-
}
255247
}
256248

257249
fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {

src/libstd/sys/unix/process/process_unix.rs

+8-91
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use env;
12-
use ffi::CString;
1311
use io::{self, Error, ErrorKind};
1412
use libc::{self, c_int, gid_t, pid_t, uid_t};
1513
use ptr;
@@ -41,15 +39,13 @@ impl Command {
4139
return Ok((ret, ours))
4240
}
4341

44-
let possible_paths = self.compute_possible_paths(envp.as_ref());
45-
4642
let (input, output) = sys::pipe::anon_pipe()?;
4743

4844
let pid = unsafe {
4945
match cvt(libc::fork())? {
5046
0 => {
5147
drop(input);
52-
let err = self.do_exec(theirs, envp.as_ref(), possible_paths);
48+
let err = self.do_exec(theirs, envp.as_ref());
5349
let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
5450
let bytes = [
5551
(errno >> 24) as u8,
@@ -117,48 +113,12 @@ impl Command {
117113
"nul byte found in provided data")
118114
}
119115

120-
let possible_paths = self.compute_possible_paths(envp.as_ref());
121116
match self.setup_io(default, true) {
122-
Ok((_, theirs)) => unsafe { self.do_exec(theirs, envp.as_ref(), possible_paths) },
117+
Ok((_, theirs)) => unsafe { self.do_exec(theirs, envp.as_ref()) },
123118
Err(e) => e,
124119
}
125120
}
126121

127-
fn compute_possible_paths(&self, maybe_envp: Option<&CStringArray>) -> Option<Vec<CString>> {
128-
let program = self.get_program().as_bytes();
129-
if program.contains(&b'/') {
130-
return None;
131-
}
132-
// Outside the match so we can borrow it for the lifetime of the function.
133-
let parent_path = env::var("PATH").ok();
134-
let paths = match maybe_envp {
135-
Some(envp) => {
136-
match envp.get_items().iter().find(|var| var.as_bytes().starts_with(b"PATH=")) {
137-
Some(p) => &p.as_bytes()[5..],
138-
None => return None,
139-
}
140-
},
141-
// maybe_envp is None if the process isn't changing the parent's env at all.
142-
None => {
143-
match parent_path.as_ref() {
144-
Some(p) => p.as_bytes(),
145-
None => return None,
146-
}
147-
},
148-
};
149-
150-
let mut possible_paths = vec![];
151-
for path in paths.split(|p| *p == b':') {
152-
let mut binary_path = Vec::with_capacity(program.len() + path.len() + 1);
153-
binary_path.extend_from_slice(path);
154-
binary_path.push(b'/');
155-
binary_path.extend_from_slice(program);
156-
let c_binary_path = CString::new(binary_path).unwrap();
157-
possible_paths.push(c_binary_path);
158-
}
159-
return Some(possible_paths);
160-
}
161-
162122
// And at this point we've reached a special time in the life of the
163123
// child. The child must now be considered hamstrung and unable to
164124
// do anything other than syscalls really. Consider the following
@@ -192,8 +152,7 @@ impl Command {
192152
unsafe fn do_exec(
193153
&mut self,
194154
stdio: ChildPipes,
195-
maybe_envp: Option<&CStringArray>,
196-
maybe_possible_paths: Option<Vec<CString>>,
155+
maybe_envp: Option<&CStringArray>
197156
) -> io::Error {
198157
use sys::{self, cvt_r};
199158

@@ -234,6 +193,9 @@ impl Command {
234193
if let Some(ref cwd) = *self.get_cwd() {
235194
t!(cvt(libc::chdir(cwd.as_ptr())));
236195
}
196+
if let Some(envp) = maybe_envp {
197+
*sys::os::environ() = envp.as_ptr();
198+
}
237199

238200
// emscripten has no signal support.
239201
#[cfg(not(any(target_os = "emscripten")))]
@@ -269,53 +231,8 @@ impl Command {
269231
t!(callback());
270232
}
271233

272-
// If the program isn't an absolute path, and our environment contains a PATH var, then we
273-
// implement the PATH traversal ourselves so that it honors the child's PATH instead of the
274-
// parent's. This mirrors the logic that exists in glibc's execvpe, except using the
275-
// child's env to fetch PATH.
276-
match maybe_possible_paths {
277-
Some(possible_paths) => {
278-
let mut pending_error = None;
279-
for path in possible_paths {
280-
libc::execve(
281-
path.as_ptr(),
282-
self.get_argv().as_ptr(),
283-
maybe_envp.map(|envp| envp.as_ptr()).unwrap_or_else(|| *sys::os::environ())
284-
);
285-
let err = io::Error::last_os_error();
286-
match err.kind() {
287-
io::ErrorKind::PermissionDenied => {
288-
// If we saw a PermissionDenied, and none of the other entries in
289-
// $PATH are successful, then we'll return the first EACCESS we see.
290-
if pending_error.is_none() {
291-
pending_error = Some(err);
292-
}
293-
},
294-
// Errors which indicate we failed to find a file are ignored and we try
295-
// the next entry in the path.
296-
io::ErrorKind::NotFound | io::ErrorKind::TimedOut => {
297-
continue
298-
},
299-
// Any other error means we found a file and couldn't execute it.
300-
_ => {
301-
return err;
302-
}
303-
}
304-
}
305-
if let Some(err) = pending_error {
306-
return err;
307-
}
308-
return io::Error::from_raw_os_error(libc::ENOENT);
309-
},
310-
_ => {
311-
libc::execve(
312-
self.get_argv()[0],
313-
self.get_argv().as_ptr(),
314-
maybe_envp.map(|envp| envp.as_ptr()).unwrap_or_else(|| *sys::os::environ())
315-
);
316-
return io::Error::last_os_error()
317-
}
318-
}
234+
libc::execvp(self.get_argv()[0], self.get_argv().as_ptr());
235+
io::Error::last_os_error()
319236
}
320237

321238
#[cfg(not(any(target_os = "macos", target_os = "freebsd",

src/test/run-pass/command-exec.rs

-12
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ fn main() {
4848
println!("passed");
4949
}
5050

51-
"exec-test5" => {
52-
env::set_var("VARIABLE", "ABC");
53-
Command::new("definitely-not-a-real-binary").env("VARIABLE", "XYZ").exec();
54-
assert_eq!(env::var("VARIABLE").unwrap(), "ABC");
55-
println!("passed");
56-
}
57-
5851
_ => panic!("unknown argument: {}", arg),
5952
}
6053
return
@@ -79,9 +72,4 @@ fn main() {
7972
assert!(output.status.success());
8073
assert!(output.stderr.is_empty());
8174
assert_eq!(output.stdout, b"passed\n");
82-
83-
let output = Command::new(&me).arg("exec-test5").output().unwrap();
84-
assert!(output.status.success());
85-
assert!(output.stderr.is_empty());
86-
assert_eq!(output.stdout, b"passed\n");
8775
}

0 commit comments

Comments
 (0)