diff --git a/src/test/compiletest/compiletest.rs b/src/test/compiletest/compiletest.rs index 1f5e49134148..0c1f85a4d85d 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}); } }