Skip to content

Commit fd293df

Browse files
committed
std: rewrite run::with_{argv,envp,dirp} to copy C strings
1 parent 08b6cb4 commit fd293df

File tree

1 file changed

+59
-44
lines changed

1 file changed

+59
-44
lines changed

src/libstd/run.rs

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use prelude::*;
2424
use ptr;
2525
use task;
2626
use vec::ImmutableVector;
27+
use vec;
2728

2829
/**
2930
* A value representing a child process.
@@ -690,46 +691,58 @@ fn spawn_process_os(prog: &str, args: &[~str],
690691
}
691692

692693
#[cfg(unix)]
693-
fn with_argv<T>(prog: &str, args: &[~str],
694-
cb: &fn(**libc::c_char) -> T) -> T {
695-
let mut argptrs = ~[prog.as_c_str(|b| b)];
696-
let mut tmps = ~[];
694+
fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
695+
// We can't directly convert `str`s into `*char`s, as someone needs to hold
696+
// a reference to the intermediary byte buffers. So first build an array to
697+
// hold all the ~[u8] byte strings.
698+
let mut tmps = vec::with_capacity(args.len() + 1);
699+
700+
tmps.push(prog.to_owned().to_c_str());
701+
697702
foreach arg in args.iter() {
698-
let t = @(*arg).clone();
699-
tmps.push(t);
700-
argptrs.push(t.as_c_str(|b| b));
703+
tmps.push(arg.to_owned().to_c_str());
701704
}
702-
argptrs.push(ptr::null());
703-
argptrs.as_imm_buf(|buf, _len| cb(buf))
705+
706+
// Next, convert each of the byte strings into a pointer. This is
707+
// technically unsafe as the caller could leak these pointers out of our
708+
// scope.
709+
let mut ptrs = do tmps.map |tmp| {
710+
tmp.as_imm_buf(|buf, _| buf as *libc::c_char)
711+
};
712+
713+
// Finally, make sure we add a null pointer.
714+
ptrs.push(ptr::null());
715+
716+
ptrs.as_imm_buf(|buf, _| cb(buf))
704717
}
705718

706719
#[cfg(unix)]
707720
fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
708-
// On posixy systems we can pass a char** for envp, which is
709-
// a null-terminated array of "k=v\n" strings.
721+
// On posixy systems we can pass a char** for envp, which is a
722+
// null-terminated array of "k=v\n" strings. Like `with_argv`, we have to
723+
// have a temporary buffer to hold the intermediary `~[u8]` byte strings.
710724
match env {
711-
Some(es) => {
712-
let mut tmps = ~[];
713-
let mut ptrs = ~[];
714-
715-
foreach pair in es.iter() {
716-
// Use of match here is just to workaround limitations
717-
// in the stage0 irrefutable pattern impl.
718-
match pair {
719-
&(ref k, ref v) => {
720-
let kv = @fmt!("%s=%s", *k, *v);
721-
tmps.push(kv);
722-
ptrs.push(kv.as_c_str(|b| b));
723-
}
725+
Some(env) => {
726+
let mut tmps = vec::with_capacity(env.len());
727+
728+
foreach pair in env.iter() {
729+
// Use of match here is just to workaround limitations
730+
// in the stage0 irrefutable pattern impl.
731+
let kv = fmt!("%s=%s", pair.first(), pair.second());
732+
tmps.push(kv.to_c_str());
724733
}
725-
}
726734

727-
ptrs.push(ptr::null());
728-
ptrs.as_imm_buf(|p, _len|
729-
unsafe { cb(::cast::transmute(p)) }
730-
)
731-
}
732-
_ => cb(ptr::null())
735+
// Once again, this is unsafe.
736+
let mut ptrs = do tmps.map |tmp| {
737+
tmp.as_imm_buf(|buf, _| buf as *libc::c_char)
738+
};
739+
ptrs.push(ptr::null());
740+
741+
do ptrs.as_imm_buf |buf, _| {
742+
unsafe { cb(cast::transmute(buf)) }
743+
}
744+
}
745+
_ => cb(ptr::null())
733746
}
734747
}
735748

@@ -739,23 +752,25 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
739752
// rather a concatenation of null-terminated k=v\0 sequences, with a final
740753
// \0 to terminate.
741754
match env {
742-
Some(es) => {
743-
let mut blk = ~[];
744-
foreach pair in es.iter() {
745-
let kv = fmt!("%s=%s", pair.first(), pair.second());
746-
blk.push_all(kv.to_bytes_with_null());
755+
Some(env) => {
756+
let mut blk = ~[];
757+
758+
foreach pair in env.iter() {
759+
let kv = fmt!("%s=%s", pair.first(), pair.second());
760+
blk.push_all(kv.to_c_str());
761+
}
762+
763+
blk.push(0);
764+
765+
do blk.as_imm_buf |p, _len| {
766+
unsafe { cb(cast::transmute(p)) }
767+
}
747768
}
748-
blk.push(0);
749-
blk.as_imm_buf(|p, _len|
750-
unsafe { cb(::cast::transmute(p)) }
751-
)
752-
}
753-
_ => cb(ptr::mut_null())
769+
_ => cb(ptr::mut_null())
754770
}
755771
}
756772

757-
fn with_dirp<T>(d: Option<&Path>,
758-
cb: &fn(*libc::c_char) -> T) -> T {
773+
fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
759774
match d {
760775
Some(dir) => dir.to_str().as_c_str(cb),
761776
None => cb(ptr::null())

0 commit comments

Comments
 (0)