about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCadence Marseille <cadencemarseille@gmail.com>2013-12-12 09:07:43 -0500
committerCadence Marseille <cadencemarseille@gmail.com>2013-12-14 12:50:04 -0500
commit5de42701a87cb0e517921cce7bc3a512e513301c (patch)
treebf480894ad4ee3df5932a3d8e174eaba04f3320f
parent00b1adf93cab0ed11fbbace11f1c57c5f8017467 (diff)
downloadrust-5de42701a87cb0e517921cce7bc3a512e513301c.tar.gz
rust-5de42701a87cb0e517921cce7bc3a512e513301c.zip
Fix #10754 - `std::run` functions fail after io_error
The problem was that std::run::Process::new() was unwrap()ing the result
of std::io::process::Process::new(), which returns None in the case
where the io_error condition is raised to signal failure to start the
process.

Have std::run::Process::new() similarly return an Option<run::Process>
to reflect the fact that a subprocess might have failed to start. Update
utility functions run::process_status() and run::process_output() to
return Option<ProcessExit> and Option<ProcessOutput>, respectively.

Various parts of librustc and librustpkg needed to be updated to reflect
these API changes.

closes #10754
-rw-r--r--src/compiletest/procsrv.rs42
-rw-r--r--src/compiletest/runtest.rs40
-rw-r--r--src/librustc/back/archive.rs26
-rw-r--r--src/librustc/back/link.rs44
-rw-r--r--src/librustpkg/api.rs28
-rw-r--r--src/librustpkg/lib.rs87
-rw-r--r--src/librustpkg/source_control.rs33
-rw-r--r--src/librustpkg/tests.rs14
-rw-r--r--src/librustpkg/version.rs17
-rw-r--r--src/libstd/run.rs79
-rw-r--r--src/test/run-pass/core-run-destroy.rs15
-rw-r--r--src/test/run-pass/signal-exit-status.rs3
12 files changed, 275 insertions, 153 deletions
diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs
index 4f05247ada4..f919274f2ed 100644
--- a/src/compiletest/procsrv.rs
+++ b/src/compiletest/procsrv.rs
@@ -46,10 +46,10 @@ pub fn run(lib_path: &str,
            prog: &str,
            args: &[~str],
            env: ~[(~str, ~str)],
-           input: Option<~str>) -> Result {
+           input: Option<~str>) -> Option<Result> {
 
     let env = env + target_env(lib_path, prog);
-    let mut process = run::Process::new(prog, args, run::ProcessOptions {
+    let mut opt_process = run::Process::new(prog, args, run::ProcessOptions {
         env: Some(env),
         dir: None,
         in_fd: None,
@@ -57,15 +57,20 @@ pub fn run(lib_path: &str,
         err_fd: None
     });
 
-    for input in input.iter() {
-        process.input().write(input.as_bytes());
-    }
-    let run::ProcessOutput { status, output, error } = process.finish_with_output();
+    match opt_process {
+        Some(ref mut process) => {
+            for input in input.iter() {
+                process.input().write(input.as_bytes());
+            }
+            let run::ProcessOutput { status, output, error } = process.finish_with_output();
 
-    Result {
-        status: status,
-        out: str::from_utf8_owned(output),
-        err: str::from_utf8_owned(error)
+            Some(Result {
+                status: status,
+                out: str::from_utf8_owned(output),
+                err: str::from_utf8_owned(error)
+            })
+        },
+        None => None
     }
 }
 
@@ -73,10 +78,10 @@ pub fn run_background(lib_path: &str,
            prog: &str,
            args: &[~str],
            env: ~[(~str, ~str)],
-           input: Option<~str>) -> run::Process {
+           input: Option<~str>) -> Option<run::Process> {
 
     let env = env + target_env(lib_path, prog);
-    let mut process = run::Process::new(prog, args, run::ProcessOptions {
+    let opt_process = run::Process::new(prog, args, run::ProcessOptions {
         env: Some(env),
         dir: None,
         in_fd: None,
@@ -84,9 +89,14 @@ pub fn run_background(lib_path: &str,
         err_fd: None
     });
 
-    for input in input.iter() {
-        process.input().write(input.as_bytes());
-    }
+    match opt_process {
+        Some(mut process) => {
+            for input in input.iter() {
+                process.input().write(input.as_bytes());
+            }
 
-    return process;
+            Some(process)
+        },
+        None => None
+    }
 }
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index dae5a1d342b..136f29765ea 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -289,20 +289,23 @@ fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) {
                 dump_output_file(config, testfile, script_str, "debugger.script");
 
 
-                procsrv::run("", config.adb_path.clone(),
+                procsrv::run("", config.adb_path,
                     [~"push", exe_file.as_str().unwrap().to_owned(), config.adb_test_dir.clone()],
-                    ~[(~"",~"")], Some(~""));
+                    ~[(~"",~"")], Some(~""))
+                    .expect(format!("failed to exec `{}`", config.adb_path));
 
                 procsrv::run("", config.adb_path,
                     [~"forward", ~"tcp:5039", ~"tcp:5039"],
-                    ~[(~"",~"")], Some(~""));
+                    ~[(~"",~"")], Some(~""))
+                    .expect(format!("failed to exec `{}`", config.adb_path));
 
                 let adb_arg = format!("export LD_LIBRARY_PATH={}; gdbserver :5039 {}/{}",
                          config.adb_test_dir.clone(), config.adb_test_dir.clone(),
                          str::from_utf8(exe_file.filename().unwrap()));
 
-                let mut process = procsrv::run_background("", config.adb_path.clone(),
-                        [~"shell",adb_arg.clone()],~[(~"",~"")], Some(~""));
+                let mut process = procsrv::run_background("", config.adb_path,
+                        [~"shell",adb_arg.clone()],~[(~"",~"")], Some(~""))
+                        .expect(format!("failed to exec `{}`", config.adb_path));
                 loop {
                     //waiting 1 second for gdbserver start
                     timer::sleep(1000);
@@ -334,10 +337,12 @@ fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) {
                 let debugger_opts = ~[~"-quiet", ~"-batch", ~"-nx",
                     "-command=" + debugger_script.as_str().unwrap().to_owned()];
 
+                let gdb_path = tool_path.append("/bin/arm-linux-androideabi-gdb");
                 let procsrv::Result{ out, err, status }=
                     procsrv::run("",
-                            tool_path.append("/bin/arm-linux-androideabi-gdb"),
-                            debugger_opts, ~[(~"",~"")], None);
+                            gdb_path,
+                            debugger_opts, ~[(~"",~"")], None)
+                    .expect(format!("failed to exec `{}`", gdb_path));
                 let cmdline = {
                     let cmdline = make_cmdline("", "arm-linux-androideabi-gdb", debugger_opts);
                     logv(config, format!("executing {}", cmdline));
@@ -800,7 +805,8 @@ fn program_output(config: &config, testfile: &Path, lib_path: &str, prog: ~str,
             cmdline
         };
     let procsrv::Result{ out, err, status } =
-            procsrv::run(lib_path, prog, args, env, input);
+            procsrv::run(lib_path, prog, args, env, input)
+            .expect(format!("failed to exec `{}`", prog));
     dump_output(config, testfile, out, err);
     return ProcRes {status: status,
          stdout: out,
@@ -908,7 +914,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
     // copy to target
     let copy_result = procsrv::run("", config.adb_path,
         [~"push", args.prog.clone(), config.adb_test_dir.clone()],
-        ~[(~"",~"")], Some(~""));
+        ~[(~"",~"")], Some(~""))
+        .expect(format!("failed to exec `{}`", config.adb_path));
 
     if config.verbose {
         println!("push ({}) {} {} {}",
@@ -932,7 +939,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
     for tv in args.args.iter() {
         runargs.push(tv.to_owned());
     }
-    procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
+    procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""))
+        .expect(format!("failed to exec `{}`", config.adb_path));
 
     // get exitcode of result
     runargs = ~[];
@@ -942,7 +950,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
 
     let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
         procsrv::run("", config.adb_path, runargs, ~[(~"",~"")],
-                     Some(~""));
+                     Some(~""))
+        .expect(format!("failed to exec `{}`", config.adb_path));
 
     let mut exitcode : int = 0;
     for c in exitcode_out.chars() {
@@ -960,7 +969,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
     runargs.push(format!("{}/{}.stdout", config.adb_test_dir, prog_short));
 
     let procsrv::Result{ out: stdout_out, err: _, status: _ } =
-        procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
+        procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""))
+        .expect(format!("failed to exec `{}`", config.adb_path));
 
     // get stderr of result
     runargs = ~[];
@@ -969,7 +979,8 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
     runargs.push(format!("{}/{}.stderr", config.adb_test_dir, prog_short));
 
     let procsrv::Result{ out: stderr_out, err: _, status: _ } =
-        procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
+        procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""))
+        .expect(format!("failed to exec `{}`", config.adb_path));
 
     dump_output(config, testfile, stdout_out, stderr_out);
 
@@ -1004,7 +1015,8 @@ fn _arm_push_aux_shared_library(config: &config, testfile: &Path) {
             // FIXME (#9639): This needs to handle non-utf8 paths
             let copy_result = procsrv::run("", config.adb_path,
                 [~"push", file.as_str().unwrap().to_owned(), config.adb_test_dir.clone()],
-                ~[(~"",~"")], Some(~""));
+                ~[(~"",~"")], Some(~""))
+                .expect(format!("failed to exec `{}`", config.adb_path));
 
             if config.verbose {
                 println!("push ({}) {} {} {}",
diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs
index c1916714bf2..9cb73ecb07b 100644
--- a/src/librustc/back/archive.rs
+++ b/src/librustc/back/archive.rs
@@ -40,15 +40,25 @@ fn run_ar(sess: Session, args: &str, cwd: Option<&Path>,
         Some(p) => { debug!("inside {}", p.display()); }
         None => {}
     }
-    let o = Process::new(ar, args.as_slice(), opts).finish_with_output();
-    if !o.status.success() {
-        sess.err(format!("{} {} failed with: {}", ar, args.connect(" "),
-                         o.status));
-        sess.note(format!("stdout ---\n{}", str::from_utf8(o.output)));
-        sess.note(format!("stderr ---\n{}", str::from_utf8(o.error)));
-        sess.abort_if_errors();
+    let mut opt_prog = Process::new(ar, args.as_slice(), opts);
+    match opt_prog {
+        Some(ref mut prog) => {
+            let o = prog.finish_with_output();
+            if !o.status.success() {
+                sess.err(format!("{} {} failed with: {}", ar, args.connect(" "),
+                                 o.status));
+                sess.note(format!("stdout ---\n{}", str::from_utf8(o.output)));
+                sess.note(format!("stderr ---\n{}", str::from_utf8(o.error)));
+                sess.abort_if_errors();
+            }
+            o
+        },
+        None => {
+            sess.err(format!("could not exec `{}`", ar));
+            sess.abort_if_errors();
+            fail!("rustc::back::archive::run_ar() should not reach this point");
+        }
     }
-    o
 }
 
 impl Archive {
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 91680f5c2e5..d67277289d4 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -310,13 +310,19 @@ pub mod write {
             assembly.as_str().unwrap().to_owned()];
 
         debug!("{} '{}'", cc, args.connect("' '"));
-        let prog = run::process_output(cc, args);
-
-        if !prog.status.success() {
-            sess.err(format!("linking with `{}` failed: {}", cc, prog.status));
-            sess.note(format!("{} arguments: '{}'", cc, args.connect("' '")));
-            sess.note(str::from_utf8_owned(prog.error + prog.output));
-            sess.abort_if_errors();
+        match run::process_output(cc, args) {
+            Some(prog) => {
+                if !prog.status.success() {
+                    sess.err(format!("linking with `{}` failed: {}", cc, prog.status));
+                    sess.note(format!("{} arguments: '{}'", cc, args.connect("' '")));
+                    sess.note(str::from_utf8_owned(prog.error + prog.output));
+                    sess.abort_if_errors();
+                }
+            },
+            None => {
+                sess.err(format!("could not exec `{}`", cc));
+                sess.abort_if_errors();
+            }
         }
     }
 
@@ -949,14 +955,22 @@ fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
 
     // Invoke the system linker
     debug!("{} {}", cc_prog, cc_args.connect(" "));
-    let prog = time(sess.time_passes(), "running linker", (), |()|
-                    run::process_output(cc_prog, cc_args));
-
-    if !prog.status.success() {
-        sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
-        sess.note(format!("{} arguments: '{}'", cc_prog, cc_args.connect("' '")));
-        sess.note(str::from_utf8_owned(prog.error + prog.output));
-        sess.abort_if_errors();
+    let opt_prog = time(sess.time_passes(), "running linker", (), |()|
+                        run::process_output(cc_prog, cc_args));
+
+    match opt_prog {
+        Some(prog) => {
+            if !prog.status.success() {
+                sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
+                sess.note(format!("{} arguments: '{}'", cc_prog, cc_args.connect("' '")));
+                sess.note(str::from_utf8_owned(prog.error + prog.output));
+                sess.abort_if_errors();
+            }
+        },
+        None => {
+            sess.err(format!("could not exec `{}`", cc_prog));
+            sess.abort_if_errors();
+        }
     }
 
 
diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs
index 0d0d0b7c4c7..8e4216562c0 100644
--- a/src/librustpkg/api.rs
+++ b/src/librustpkg/api.rs
@@ -142,14 +142,14 @@ pub fn install_pkg(cx: &BuildContext,
 /// Builds an arbitrary library whose short name is `output`,
 /// by invoking `tool` with arguments `args` plus "-o %s", where %s
 /// is the platform-specific library name for `output`.
-/// Returns that platform-specific name.
+/// Returns that platform-specific name, or None if `tool` could not be started.
 pub fn build_library_in_workspace(exec: &mut workcache::Exec,
                                   context: &mut Context,
                                   package_name: &str,
                                   tool: &str,
                                   flags: &[~str],
                                   paths: &[~str],
-                                  output: &str) -> ~str {
+                                  output: &str) -> Option<~str> {
     use command_failed = conditions::command_failed::cond;
 
     let workspace = my_workspace(context, package_name);
@@ -169,16 +169,20 @@ pub fn build_library_in_workspace(exec: &mut workcache::Exec,
 
     let all_args = flags + absolute_paths + cc_args +
          ~[~"-o", out_name.as_str().unwrap().to_owned()];
-    let exit_process = run::process_status(tool, all_args);
-    if exit_process.success() {
-        let out_name_str = out_name.as_str().unwrap().to_owned();
-        exec.discover_output("binary",
-                             out_name_str,
-                             digest_only_date(&out_name));
-        context.add_library_path(out_name.dir_path());
-        out_name_str
-    } else {
-        command_failed.raise((tool.to_owned(), all_args, exit_process))
+    match run::process_status(tool, all_args) {
+        Some(exit_process) => {
+            if exit_process.success() {
+                let out_name_str = out_name.as_str().unwrap().to_owned();
+                exec.discover_output("binary",
+                                     out_name_str,
+                                     digest_only_date(&out_name));
+                context.add_library_path(out_name.dir_path());
+                Some(out_name_str)
+            } else {
+                Some(command_failed.raise((tool.to_owned(), all_args, exit_process)))
+            }
+        },
+        None => None
     }
 }
 
diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs
index cedb21eeb2a..76d2db0a587 100644
--- a/src/librustpkg/lib.rs
+++ b/src/librustpkg/lib.rs
@@ -166,29 +166,47 @@ impl<'a> PkgScript<'a> {
     /// Run the contents of this package script, where <what>
     /// is the command to pass to it (e.g., "build", "clean", "install")
     /// Returns a pair of an exit code and list of configs (obtained by
-    /// calling the package script's configs() function if it exists
-    fn run_custom(exe: &Path, sysroot: &Path) -> (~[~str], process::ProcessExit) {
+    /// calling the package script's configs() function if it exists, or
+    /// None if `exe` could not be started.
+    fn run_custom(exe: &Path, sysroot: &Path) -> Option<(~[~str], process::ProcessExit)> {
         debug!("Running program: {} {} {}", exe.as_str().unwrap().to_owned(),
                sysroot.display(), "install");
         // FIXME #7401 should support commands besides `install`
         // FIXME (#9639): This needs to handle non-utf8 paths
-        let status = run::process_status(exe.as_str().unwrap(),
-                                         [sysroot.as_str().unwrap().to_owned(), ~"install"]);
-        if !status.success() {
-            debug!("run_custom: first pkg command failed with {:?}", status);
-            (~[], status)
-        }
-        else {
-            debug!("Running program (configs): {} {} {}",
-                   exe.display(), sysroot.display(), "configs");
-            // FIXME (#9639): This needs to handle non-utf8 paths
-            let output = run::process_output(exe.as_str().unwrap(),
-                                             [sysroot.as_str().unwrap().to_owned(), ~"configs"]);
-            debug!("run_custom: second pkg command did {:?}", output.status);
-            // Run the configs() function to get the configs
-            let cfgs = str::from_utf8(output.output).words()
-                .map(|w| w.to_owned()).collect();
-            (cfgs, output.status)
+        let opt_status = run::process_status(exe.as_str().unwrap(),
+                                             [sysroot.as_str().unwrap().to_owned(), ~"install"]);
+        match opt_status {
+            Some(status) => {
+                if !status.success() {
+                    debug!("run_custom: first pkg command failed with {:?}", status);
+                    Some((~[], status))
+                }
+                else {
+                    debug!("Running program (configs): {} {} {}",
+                           exe.display(), sysroot.display(), "configs");
+                    // FIXME (#9639): This needs to handle non-utf8 paths
+                    let opt_output = run::process_output(exe.as_str().unwrap(),
+                                                         [sysroot.as_str().unwrap().to_owned(),
+                                                          ~"configs"]);
+                    match opt_output {
+                        Some(output) => {
+                            debug!("run_custom: second pkg command did {:?}", output.status);
+                            // Run the configs() function to get the configs
+                            let cfgs = str::from_utf8(output.output).words()
+                                .map(|w| w.to_owned()).collect();
+                            Some((cfgs, output.status))
+                        },
+                        None => {
+                            debug!("run_custom: second pkg command failed to start");
+                            Some((~[], status))
+                        }
+                    }
+                }
+            },
+            None => {
+                debug!("run_custom: first pkg command failed to start");
+                None
+            }
         }
     }
 }
@@ -481,14 +499,20 @@ impl CtxMethods for BuildContext {
                     })
                 });
                 // We always *run* the package script
-                let (cfgs, hook_result) = PkgScript::run_custom(&Path::new(pkg_exe), &sysroot);
-                debug!("Command return code = {:?}", hook_result);
-                if !hook_result.success() {
-                    fail!("Error running custom build command")
+                match PkgScript::run_custom(&Path::new(pkg_exe), &sysroot) {
+                    Some((cfgs, hook_result)) => {
+                        debug!("Command return code = {:?}", hook_result);
+                        if !hook_result.success() {
+                            fail!("Error running custom build command")
+                        }
+                        custom = true;
+                        // otherwise, the package script succeeded
+                        cfgs
+                    },
+                    None => {
+                        fail!("Error starting custom build command")
+                    }
                 }
-                custom = true;
-                // otherwise, the package script succeeded
-                cfgs
             }
             (Some(_), Inferred) => {
                 debug!("There is a package script, but we're ignoring it");
@@ -693,9 +717,14 @@ impl CtxMethods for BuildContext {
             Some(test_exec) => {
                 debug!("test: test_exec = {}", test_exec.display());
                 // FIXME (#9639): This needs to handle non-utf8 paths
-                let status = run::process_status(test_exec.as_str().unwrap(), [~"--test"]);
-                if !status.success() {
-                    fail!("Some tests failed");
+                let opt_status = run::process_status(test_exec.as_str().unwrap(), [~"--test"]);
+                match opt_status {
+                    Some(status) => {
+                        if !status.success() {
+                            fail!("Some tests failed");
+                        }
+                    },
+                    None => fail!("Could not exec `{}`", test_exec.display())
                 }
             }
             None => {
diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs
index 702a849e4ad..cbb55030231 100644
--- a/src/librustpkg/source_control.rs
+++ b/src/librustpkg/source_control.rs
@@ -33,15 +33,16 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult
         if !target.exists() {
             debug!("Running: git clone {} {}", source.display(), target.display());
             // FIXME (#9639): This needs to handle non-utf8 paths
-            let outp = run::process_output("git", [~"clone",
-                                                   source.as_str().unwrap().to_owned(),
-                                                   target.as_str().unwrap().to_owned()]);
+            let opt_outp = run::process_output("git", [~"clone",
+                                                       source.as_str().unwrap().to_owned(),
+                                                       target.as_str().unwrap().to_owned()]);
+            let outp = opt_outp.expect("Failed to exec `git`");
             if !outp.status.success() {
                 println(str::from_utf8_owned(outp.output.clone()));
                 println(str::from_utf8_owned(outp.error));
                 return DirToUse(target.clone());
             }
-                else {
+            else {
                 match v {
                     &ExactRevision(ref s) => {
                         let git_dir = target.join(".git");
@@ -51,7 +52,7 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult
                         let outp = run::process_output("git",
                             [format!("--work-tree={}", target.as_str().unwrap().to_owned()),
                              format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()),
-                             ~"checkout", format!("{}", *s)]);
+                             ~"checkout", format!("{}", *s)]).expect("Failed to exec `git`");
                         if !outp.status.success() {
                             println(str::from_utf8_owned(outp.output.clone()));
                             println(str::from_utf8_owned(outp.error));
@@ -72,7 +73,8 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult
             let args = [format!("--work-tree={}", target.as_str().unwrap().to_owned()),
                         format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()),
                         ~"pull", ~"--no-edit", source.as_str().unwrap().to_owned()];
-            let outp = run::process_output("git", args);
+            let opt_outp = run::process_output("git", args);
+            let outp = opt_outp.expect("Failed to exec `git`");
             assert!(outp.status.success());
         }
         CheckedOutSources
@@ -108,8 +110,9 @@ pub fn git_clone_url(source: &str, target: &Path, v: &Version) {
     use conditions::git_checkout_failed::cond;
 
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let outp = run::process_output("git", [~"clone", source.to_owned(),
-                                           target.as_str().unwrap().to_owned()]);
+    let opt_outp = run::process_output("git", [~"clone", source.to_owned(),
+                                               target.as_str().unwrap().to_owned()]);
+    let outp = opt_outp.expect("Failed to exec `git`");
     if !outp.status.success() {
          debug!("{}", str::from_utf8_owned(outp.output.clone()));
          debug!("{}", str::from_utf8_owned(outp.error));
@@ -118,8 +121,9 @@ pub fn git_clone_url(source: &str, target: &Path, v: &Version) {
     else {
         match v {
             &ExactRevision(ref s) | &Tagged(ref s) => {
-                    let outp = process_output_in_cwd("git", [~"checkout", s.to_owned()],
+                    let opt_outp = process_output_in_cwd("git", [~"checkout", s.to_owned()],
                                                          target);
+                    let outp = opt_outp.expect("Failed to exec `git`");
                     if !outp.status.success() {
                         debug!("{}", str::from_utf8_owned(outp.output.clone()));
                         debug!("{}", str::from_utf8_owned(outp.error));
@@ -131,10 +135,13 @@ pub fn git_clone_url(source: &str, target: &Path, v: &Version) {
     }
 }
 
-fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> ProcessOutput {
-    let mut prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd)
-                                ,..ProcessOptions::new()});
-    prog.finish_with_output()
+fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
+    let mut opt_prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd)
+                                    ,..ProcessOptions::new()});
+    match opt_prog {
+        Some(ref mut prog) => Some(prog.finish_with_output()),
+        None => None
+    }
 }
 
 pub fn is_git_dir(p: &Path) -> bool {
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index 59fdf20941e..28bf8deb5a7 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -148,7 +148,7 @@ fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &st
         in_fd: None,
         out_fd: None,
         err_fd: None
-    });
+    }).expect("failed to exec `git`");
     let rslt = prog.finish_with_output();
     if !rslt.status.success() {
         fail!("{} [git returned {:?}, output = {}, error = {}]", err_msg,
@@ -285,7 +285,7 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
         in_fd: None,
         out_fd: None,
         err_fd: None
-    });
+    }).expect(format!("failed to exec `{}`", cmd));
     let output = prog.finish_with_output();
     debug!("Output from command {} with args {:?} was {} \\{{}\\}[{:?}]",
            cmd, args, str::from_utf8(output.output),
@@ -503,7 +503,8 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
             // n.b. Bumps time up by 2 seconds to get around granularity issues
             if !run::process_output("touch", [~"--date",
                                              ~"+2 seconds",
-                                             p.as_str().unwrap().to_owned()]).status.success() {
+                                             p.as_str().unwrap().to_owned()])
+                .expect("failed to exec `touch`").status.success() {
                 let _ = cond.raise((pkg_src_dir.clone(), ~"Bad path"));
             }
         }
@@ -521,7 +522,8 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
             // FIXME (#9639): This needs to handle non-utf8 paths
             // n.b. Bumps time up by 2 seconds to get around granularity issues
             if !run::process_output("touch", [~"-A02",
-                                             p.as_str().unwrap().to_owned()]).status.success() {
+                                             p.as_str().unwrap().to_owned()])
+                .expect("failed to exec `touch`").status.success() {
                 let _ = cond.raise((pkg_src_dir.clone(), ~"Bad path"));
             }
         }
@@ -1276,7 +1278,7 @@ fn test_extern_mod() {
         in_fd: None,
         out_fd: None,
         err_fd: None
-    });
+    }).expect(format!("failed to exec `{}`", rustc.as_str().unwrap()));
     let outp = prog.finish_with_output();
     if !outp.status.success() {
         fail!("output was {}, error was {}",
@@ -1331,7 +1333,7 @@ fn test_extern_mod_simpler() {
         in_fd: None,
         out_fd: None,
         err_fd: None
-    });
+    }).expect(format!("failed to exec `{}`", rustc.as_str().unwrap()));
     let outp = prog.finish_with_output();
     if !outp.status.success() {
         fail!("output was {}, error was {}",
diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs
index ba6cf5f513b..e9ccfccb126 100644
--- a/src/librustpkg/version.rs
+++ b/src/librustpkg/version.rs
@@ -104,8 +104,9 @@ pub fn try_getting_local_version(local_path: &Path) -> Option<Version> {
             continue;
         }
         // FIXME (#9639): This needs to handle non-utf8 paths
-        let outp = run::process_output("git",
+        let opt_outp = run::process_output("git",
                                    ["--git-dir=" + git_dir.as_str().unwrap(), ~"tag", ~"-l"]);
+        let outp = opt_outp.expect("Failed to exec `git`");
 
         debug!("git --git-dir={} tag -l ~~~> {:?}", git_dir.display(), outp.status);
 
@@ -140,9 +141,10 @@ pub fn try_getting_version(remote_path: &Path) -> Option<Version> {
                remote_path.display(),
                tmp_dir.display());
         // FIXME (#9639): This needs to handle non-utf8 paths
-        let outp  = run::process_output("git", [~"clone", format!("https://{}",
-                                                                  remote_path.as_str().unwrap()),
-                                                tmp_dir.as_str().unwrap().to_owned()]);
+        let opt_outp = run::process_output("git", [~"clone", format!("https://{}",
+                                                                     remote_path.as_str().unwrap()),
+                                                   tmp_dir.as_str().unwrap().to_owned()]);
+        let outp = opt_outp.expect("Failed to exec `git`");
         if outp.status.success() {
             debug!("Cloned it... ( {}, {} )",
                    str::from_utf8(outp.output),
@@ -152,9 +154,10 @@ pub fn try_getting_version(remote_path: &Path) -> Option<Version> {
             debug!("(getting version, now getting tags) executing \\{git --git-dir={} tag -l\\}",
                    git_dir.display());
             // FIXME (#9639): This needs to handle non-utf8 paths
-            let outp = run::process_output("git",
-                                           ["--git-dir=" + git_dir.as_str().unwrap(),
-                                            ~"tag", ~"-l"]);
+            let opt_outp = run::process_output("git",
+                                               ["--git-dir=" + git_dir.as_str().unwrap(),
+                                                ~"tag", ~"-l"]);
+            let outp = opt_outp.expect("Failed to exec `git`");
             let output_text = str::from_utf8(outp.output);
             debug!("Full output: ( {} ) [{:?}]", output_text, outp.status);
             for l in output_text.lines() {
diff --git a/src/libstd/run.rs b/src/libstd/run.rs
index 754c02e308f..14d49df59a4 100644
--- a/src/libstd/run.rs
+++ b/src/libstd/run.rs
@@ -119,7 +119,7 @@ impl Process {
      * * options - Options to configure the environment of the process,
      *             the working directory and the standard IO streams.
      */
-    pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Process {
+    pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Option<Process> {
         let ProcessOptions { env, dir, in_fd, out_fd, err_fd } = options;
         let env = env.as_ref().map(|a| a.as_slice());
         let cwd = dir.as_ref().map(|a| a.as_str().unwrap());
@@ -138,8 +138,10 @@ impl Process {
             cwd: cwd,
             io: rtio,
         };
-        let inner = process::Process::new(rtconfig).unwrap();
-        Process { inner: inner }
+        match process::Process::new(rtconfig) {
+            Some(inner) => Some(Process { inner: inner }),
+            None => None
+        }
     }
 
     /// Returns the unique id of the process
@@ -290,17 +292,20 @@ impl Process {
  *
  * # Return value
  *
- * The process's exit code
+ * The process's exit code, or None if the child process could not be started
  */
-pub fn process_status(prog: &str, args: &[~str]) -> ProcessExit {
-    let mut prog = Process::new(prog, args, ProcessOptions {
+pub fn process_status(prog: &str, args: &[~str]) -> Option<ProcessExit> {
+    let mut opt_prog = Process::new(prog, args, ProcessOptions {
         env: None,
         dir: None,
         in_fd: Some(unsafe { libc::dup(libc::STDIN_FILENO) }),
         out_fd: Some(unsafe { libc::dup(libc::STDOUT_FILENO) }),
         err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) })
     });
-    prog.finish()
+    match opt_prog {
+        Some(ref mut prog) => Some(prog.finish()),
+        None => None
+    }
 }
 
 /**
@@ -313,11 +318,15 @@ pub fn process_status(prog: &str, args: &[~str]) -> ProcessExit {
  *
  * # Return value
  *
- * The process's stdout/stderr output and exit code.
+ * The process's stdout/stderr output and exit code, or None if the child process could not be
+ * started.
  */
-pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput {
-    let mut prog = Process::new(prog, args, ProcessOptions::new());
-    prog.finish_with_output()
+pub fn process_output(prog: &str, args: &[~str]) -> Option<ProcessOutput> {
+    let mut opt_prog = Process::new(prog, args, ProcessOptions::new());
+    match opt_prog {
+        Some(ref mut prog) => Some(prog.finish_with_output()),
+        None => None
+    }
 }
 
 #[cfg(test)]
@@ -331,24 +340,36 @@ mod tests {
     use task::spawn;
     use unstable::running_on_valgrind;
     use io::native::file;
-    use io::{Writer, Reader};
+    use io::{Writer, Reader, io_error};
 
     #[test]
     #[cfg(not(target_os="android"))] // FIXME(#10380)
     fn test_process_status() {
-        let mut status = run::process_status("false", []);
+        let mut status = run::process_status("false", []).expect("failed to exec `false`");
         assert!(status.matches_exit_status(1));
 
-        status = run::process_status("true", []);
+        status = run::process_status("true", []).expect("failed to exec `true`");
         assert!(status.success());
     }
 
     #[test]
+    fn test_process_output_fail_to_start() {
+        let mut trapped_io_error = false;
+        let opt_outp = io_error::cond.trap(|_| {
+            trapped_io_error = true;
+        }).inside(|| -> Option<run::ProcessOutput> {
+            run::process_output("no-binary-by-this-name-should-exist", [])
+        });
+        assert!(trapped_io_error);
+        assert!(opt_outp.is_none());
+    }
+
+    #[test]
     #[cfg(not(target_os="android"))] // FIXME(#10380)
     fn test_process_output_output() {
 
         let run::ProcessOutput {status, output, error}
-             = run::process_output("echo", [~"hello"]);
+             = run::process_output("echo", [~"hello"]).expect("failed to exec `echo`");
         let output_str = str::from_utf8_owned(output);
 
         assert!(status.success());
@@ -364,7 +385,7 @@ mod tests {
     fn test_process_output_error() {
 
         let run::ProcessOutput {status, output, error}
-             = run::process_output("mkdir", [~"."]);
+             = run::process_output("mkdir", [~"."]).expect("failed to exec `mkdir`");
 
         assert!(status.matches_exit_status(1));
         assert_eq!(output, ~[]);
@@ -385,7 +406,7 @@ mod tests {
             in_fd: Some(pipe_in.input),
             out_fd: Some(pipe_out.out),
             err_fd: Some(pipe_err.out)
-        });
+        }).expect("failed to exec `cat`");
 
         os::close(pipe_in.input);
         os::close(pipe_out.out);
@@ -422,14 +443,16 @@ mod tests {
     #[test]
     #[cfg(not(target_os="android"))] // FIXME(#10380)
     fn test_finish_once() {
-        let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
+        let mut prog = run::Process::new("false", [], run::ProcessOptions::new())
+            .expect("failed to exec `false`");
         assert!(prog.finish().matches_exit_status(1));
     }
 
     #[test]
     #[cfg(not(target_os="android"))] // FIXME(#10380)
     fn test_finish_twice() {
-        let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
+        let mut prog = run::Process::new("false", [], run::ProcessOptions::new())
+            .expect("failed to exec `false`");
         assert!(prog.finish().matches_exit_status(1));
         assert!(prog.finish().matches_exit_status(1));
     }
@@ -438,7 +461,8 @@ mod tests {
     #[cfg(not(target_os="android"))] // FIXME(#10380)
     fn test_finish_with_output_once() {
 
-        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
+        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new())
+            .expect("failed to exec `echo`");
         let run::ProcessOutput {status, output, error}
             = prog.finish_with_output();
         let output_str = str::from_utf8_owned(output);
@@ -455,7 +479,8 @@ mod tests {
     #[cfg(not(target_os="android"))] // FIXME(#10380)
     fn test_finish_with_output_twice() {
 
-        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
+        let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new())
+            .expect("failed to exec `echo`");
         let run::ProcessOutput {status, output, error}
             = prog.finish_with_output();
 
@@ -484,14 +509,14 @@ mod tests {
         run::Process::new("pwd", [], run::ProcessOptions {
             dir: dir,
             .. run::ProcessOptions::new()
-        })
+        }).expect("failed to exec `pwd`")
     }
     #[cfg(unix,target_os="android")]
     fn run_pwd(dir: Option<&Path>) -> run::Process {
         run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions {
             dir: dir,
             .. run::ProcessOptions::new()
-        })
+        }).expect("failed to exec `/system/bin/sh`")
     }
 
     #[cfg(windows)]
@@ -499,7 +524,7 @@ mod tests {
         run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions {
             dir: dir,
             .. run::ProcessOptions::new()
-        })
+        }).expect("failed to run `cmd`")
     }
 
     #[test]
@@ -539,14 +564,14 @@ mod tests {
         run::Process::new("env", [], run::ProcessOptions {
             env: env,
             .. run::ProcessOptions::new()
-        })
+        }).expect("failed to exec `env`")
     }
     #[cfg(unix,target_os="android")]
     fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
         run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
             env: env,
             .. run::ProcessOptions::new()
-        })
+        }).expect("failed to exec `/system/bin/sh`")
     }
 
     #[cfg(windows)]
@@ -554,7 +579,7 @@ mod tests {
         run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
             env: env,
             .. run::ProcessOptions::new()
-        })
+        }).expect("failed to run `cmd`")
     }
 
     #[test]
diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs
index 05f74ca8373..4b7ab09e152 100644
--- a/src/test/run-pass/core-run-destroy.rs
+++ b/src/test/run-pass/core-run-destroy.rs
@@ -27,7 +27,8 @@ fn test_destroy_once() {
     #[cfg(target_os="android")]
     static PROG: &'static str = "ls"; // android don't have echo binary
 
-    let mut p = run::Process::new(PROG, [], run::ProcessOptions::new());
+    let mut p = run::Process::new(PROG, [], run::ProcessOptions::new())
+        .expect(format!("failed to exec `{}`", PROG));
     p.destroy(); // this shouldn't crash (and nor should the destructor)
 }
 
@@ -38,7 +39,8 @@ fn test_destroy_twice() {
     #[cfg(target_os="android")]
     static PROG: &'static str = "ls"; // android don't have echo binary
 
-    let mut p = run::Process::new(PROG, [], run::ProcessOptions::new());
+    let mut p = run::Process::new(PROG, [], run::ProcessOptions::new())
+        .expect(format!("failed to exec `{}`", PROG));
     p.destroy(); // this shouldnt crash...
     io::io_error::cond.trap(|_| {}).inside(|| {
         p.destroy(); // ...and nor should this (and nor should the destructor)
@@ -58,13 +60,15 @@ fn test_destroy_actually_kills(force: bool) {
 
     #[cfg(unix,not(target_os="android"))]
     fn process_exists(pid: libc::pid_t) -> bool {
-        let run::ProcessOutput {output, ..} = run::process_output("ps", [~"-p", pid.to_str()]);
+        let run::ProcessOutput {output, ..} = run::process_output("ps", [~"-p", pid.to_str()])
+            .expect("failed to exec `ps`");
         str::from_utf8_owned(output).contains(pid.to_str())
     }
 
     #[cfg(unix,target_os="android")]
     fn process_exists(pid: libc::pid_t) -> bool {
-        let run::ProcessOutput {output, ..} = run::process_output("/system/bin/ps", [pid.to_str()]);
+        let run::ProcessOutput {output, ..} = run::process_output("/system/bin/ps", [pid.to_str()])
+            .expect("failed to exec `/system/bin/ps`");
         str::from_utf8_owned(output).contains(~"root")
     }
 
@@ -88,7 +92,8 @@ fn test_destroy_actually_kills(force: bool) {
     }
 
     // this process will stay alive indefinitely trying to read from stdin
-    let mut p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
+    let mut p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new())
+        .expect(format!("failed to exec `{}`", BLOCK_COMMAND));
 
     assert!(process_exists(p.get_id()));
 
diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs
index 8fa8c8d0c14..c26c79112fe 100644
--- a/src/test/run-pass/signal-exit-status.rs
+++ b/src/test/run-pass/signal-exit-status.rs
@@ -19,7 +19,8 @@ fn main() {
         // Raise a segfault.
         unsafe { *(0 as *mut int) = 0; }
     } else {
-        let status = run::process_status(args[0], [~"signal"]);
+        let status = run::process_status(args[0], [~"signal"])
+            .expect("failed to exec `signal`");
         // Windows does not have signal, so we get exit status 0xC0000028 (STATUS_BAD_STACK).
         match status {
             process::ExitSignal(_) if cfg!(unix) => {},