about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/test/compiletest/compiletest.rs117
1 files changed, 86 insertions, 31 deletions
diff --git a/src/test/compiletest/compiletest.rs b/src/test/compiletest/compiletest.rs
index 1f5e4913414..0c1f85a4d85 100644
--- a/src/test/compiletest/compiletest.rs
+++ b/src/test/compiletest/compiletest.rs
@@ -11,6 +11,7 @@ import std::generic_os::getenv;
 import std::os;
 import std::run;
 import std::task;
+import std::unsafe;
 
 tag mode { mode_compile_fail; mode_run_fail; mode_run_pass; }
 
@@ -175,7 +176,6 @@ fn make_test(cx: &cx, testfile: &str, configport: &port[str]) ->
             ignore: header::is_test_ignored(cx.config, testfile)}
 }
 
-
 /*
 So this is kind of crappy:
 
@@ -223,7 +223,7 @@ fn closure_to_task(cx: cx, configport: port[str], testfn: &fn() ) -> task {
                             cx.config.run_ignored, opt_str(cx.config.filter),
                             opt_str(cx.config.runtool),
                             opt_str(cx.config.rustcflags), cx.config.verbose,
-                            procsrv::clone(cx.procsrv).chan, testfile);
+                            task::clone_chan(cx.procsrv.chan), testfile);
 }
 
 fn run_test_task(compile_lib_path: str, run_lib_path: str, rustc_path: str,
@@ -304,6 +304,23 @@ fn logv(config: &config, s: &str) {
     if config.verbose { io::stdout().write_line(s); }
 }
 
+fn clone_str(s: &str) -> str {
+    let new = s + "";
+    // new should be a different pointer
+    let sptr: int = unsafe::reinterpret_cast(s);
+    let newptr: int = unsafe::reinterpret_cast(new);
+    assert sptr != newptr;
+    new
+}
+
+fn clone_ivecstr(v: &str[]) -> str[] {
+    let r = ~[];
+    for t: str in ivec::slice(v, 0u, ivec::len(v)) {
+        r += ~[clone_str(t)];
+    }
+    ret r;
+}
+
 mod header {
 
     export test_props;
@@ -396,10 +413,10 @@ mod runtest {
         log #fmt("running %s", testfile);
         let props = load_props(testfile);
         alt cx.config.mode {
-                mode_compile_fail. { run_cfail_test(cx, props, testfile); }
-                mode_run_fail. { run_rfail_test(cx, props, testfile); }
-                mode_run_pass. { run_rpass_test(cx, props, testfile); }
-            }
+          mode_compile_fail. { run_cfail_test(cx, props, testfile); }
+          mode_run_fail. { run_rfail_test(cx, props, testfile); }
+          mode_run_pass. { run_rpass_test(cx, props, testfile); }
+        }
     }
 
     fn run_cfail_test(cx: &cx, props: &test_props, testfile: &str) {
@@ -622,7 +639,7 @@ mod procsrv {
 
     type handle = {task: option::t[task], chan: reqchan};
 
-    tag request { exec(str, str, vec[str], chan[response]); stop; }
+    tag request { exec(str, str, str[], chan[response]); stop; }
 
     type response = {pid: int, outfd: int, errfd: int};
 
@@ -631,7 +648,7 @@ mod procsrv {
         let task = spawn fn(setupchan: chan[chan[request]]) {
             let reqport = port();
             let reqchan = chan(reqport);
-            task::send(setupchan, reqchan);
+            task::send(setupchan, task::clone_chan(reqchan));
             worker(reqport);
         } (chan(setupport));
         ret {task: option::some(task),
@@ -657,7 +674,10 @@ mod procsrv {
         {status: int, out: str, err: str} {
         let p = port[response]();
         let ch = chan(p);
-        task::send(handle.chan, exec(lib_path, prog, args, ch));
+        task::send(handle.chan, exec(lib_path,
+                                     prog,
+                                     clone_ivecstr(ivec::from_vec(args)),
+                                     task::clone_chan(ch)));
         let resp = task::recv(p);
         let output = readclose(resp.outfd);
         let errput = readclose(resp.errfd);
@@ -679,29 +699,64 @@ mod procsrv {
     }
 
     fn worker(p: port[request]) {
+
+        // FIXME: If we declare this inside of the while loop and then
+        // break out of it before it's ever initialized (i.e. we don't run
+        // any tests), then the cleanups will puke, so we're initializing it
+        // here with defaults.
+        let execparms = {
+            lib_path: "",
+            prog: "",
+            args: ~[],
+            // This works because a NULL box is ignored during cleanup
+            respchan: unsafe::reinterpret_cast(0)
+        };
+
         while true {
-            alt task::recv(p) {
-              exec(lib_path, prog, args, respchan) {
-                // This is copied from run::start_program
-                let pipe_in = os::pipe();
-                let pipe_out = os::pipe();
-                let pipe_err = os::pipe();
-                let spawnproc =
-                    bind run::spawn_process(prog, args, pipe_in.in,
-                                            pipe_out.out, pipe_err.out);
-                let pid = with_lib_path(lib_path, spawnproc);
-                if pid == -1 { fail; }
-                os::libc::close(pipe_in.in);
-                os::libc::close(pipe_in.out);
-                os::libc::close(pipe_out.out);
-                os::libc::close(pipe_err.out);
-                task::send(respchan,
-                           {pid: pid,
-                            outfd: pipe_out.in,
-                            errfd: pipe_err.in});
-              }
-              stop. { ret; }
-            }
+            // FIXME: Sending strings across channels seems to still
+            // leave them refed on the sender's end, which causes problems if
+            // the receiver's poniters outlive the sender's. Here we clone
+            // everything and let the originals go out of scope before sending
+            // a response.
+            execparms = {
+                // FIXME: The 'discriminant' of an alt expression has the
+                // same scope as the alt expression itself, so we have to put
+                // the entire alt in another block to make sure the exec
+                // message goes out of scope. Seems like the scoping rules for
+                // the alt discriminant are wrong.
+                alt task::recv(p) {
+                  exec(lib_path, prog, args, respchan) {
+                    {
+                        lib_path: clone_str(lib_path),
+                        prog: clone_str(prog),
+                        args: clone_ivecstr(args),
+                        respchan: respchan
+                    }
+                  }
+                  stop. { ret }
+                }
+            };
+
+            // This is copied from run::start_program
+            let pipe_in = os::pipe();
+            let pipe_out = os::pipe();
+            let pipe_err = os::pipe();
+            let spawnproc =
+                bind run::spawn_process(execparms.prog,
+                                        ivec::to_vec(execparms.args),
+                                        pipe_in.in,
+                                        pipe_out.out,
+                                        pipe_err.out);
+            let pid = with_lib_path(execparms.lib_path, spawnproc);
+            if pid == -1 { fail; }
+            os::libc::close(pipe_in.in);
+            os::libc::close(pipe_in.out);
+            os::libc::close(pipe_out.out);
+            os::libc::close(pipe_err.out);
+            task::send(execparms.respchan,
+                       {pid: pid,
+                        outfd: pipe_out.in,
+                        errfd: pipe_err.in});
         }
     }