Make process exit status more flexible to allow for handling when a child is terminated by signal#10109
Conversation
|
Maybe this should return an enum like: enum ProcessExit {
ExitOk, // status == 0, could be merged into ExitStatus.
ExitStatus(int),
ExitSignal(int)
} |
|
Working on the enum solution - it is significantly nicer. This would of course break any existing code that uses |
|
It's fine to break existing code, but I think that there should definitely be some tests accompanying this change. It's fine to only run the tests on some platforms (getting a forking/shell tests working on both windows/android is annoying), but this should not get regressed on. |
|
I have implemented the enum and added a few helpers to @alexcrichton I agree, so I added a test to |
|
Would it be possible to write a test that invokes itself with arguments that will raise a signal, e.g. fn main() {
let args = os::args();
if args.len() >= 2 && args[1] == "signal" {
// called like `./testname signal`, so raise a signal...
} else {
// work out the path to this executable.
let mut self_path = os::self_exe_path().unwrap();
self_path.push(args[0]);
let status = run::process_status(format!("{}", self_path.display()),
[~"signal"]);
assert_eq!(status, ExitSignal(/* whatever */));
}
}(This might be unreasonably complicated for a test.) |
src/libstd/rt/io/process.rs
Outdated
There was a problem hiding this comment.
Can these all be methods? i.e.
impl ProcessExit {
fn is_success(&self) -> bool { ... }
fn maybe_get_exit_code(&self) -> Option<int> { ... }
// etc
}|
Hm ok reader the uv code, it looks like exec errors are reported in the callback (which is a little unfortunate). I also think that the current handling of the error codes is pretty wrong, and I think that the callback should get modified slightly. I think that the uv match term_signal {
0 => match exit_status {
n if n < 0 => ExitExecError(UvError(n)),
n => ExitStatus(n),
},
n => ExitSignal(n),
}I'm not entirely certain if you can have a clean negative exit status, but I that this will correctly propagate the uv error. Note that |
|
We actually have a raw Will work on fixing up these things - the utility functions for example should've been methods from the very beginning. Just seeking some clarification @alexcrichton when you say the There's a test in |
|
Right now the function in |
|
Updated with input from review and rebased onto current master with the libuv crate move. No local regressions with a Still not totally sure on the I am also uncertain about the updated code to handle problems running @huonw - RE the test that invokes itself. Sure, I can look into doing that. Is there any advantage to doing it that way over the current test, which sends itself a SIGHUP via bash? |
It is more platform independent than calling out to sh; i.e. it should work on any platform that supports running external processes, whereas the sh one only works when sh is around. |
src/compiletest/runtest.rs
Outdated
There was a problem hiding this comment.
This seems to be a pretty common switch, and it looks like the case of a fork error is commonly forgotten as well. I think that a good way to handle this might be to have a to_str() or fmt::Default implementation for ProcessExit which becomes one of:
error code: 100signal: 10exec error: failed to allocate memory
And then error messages like this could be format!("failure produced {}", status)
|
This is really awesome, thanks so much for this excellent work! I think the only real remaining bump is Also, were you able to figure out what happened if you spawned a process of a nonexistent program? I would expect that to return an |
|
Working on these now. @alexcrichton had a quick look and the pattern matching against an IoError requires a move - I really haven't looked too closely yet though while I do the formatter and such. @huonw fair point! I have no idea what happens when you segfault on Windows with respect to exit codes or "signals" - and I don't have a Windows machine handy. I could do up a test with this PR that works on unixy systems, and see what it does when it hits CI on Windows? |
|
@alexcrichton the latest commit has everything bar the IoError change. This includes modifying the existing test in @huonw I have added a new test that uses more or less the code you suggested, and checks for termination by signal. I have specifically avoided checking the exact value of the signal to avoid having to deal with system specifics (eg, SIGBUS vs SIGSEGV vs Windows), resorting to only |
There was a problem hiding this comment.
I have a feeling this isn't correct: doesn't this attempt to compile the #[test] in this file (i.e. all zero of them :P ) into a testsuite, and should just be removed?
There was a problem hiding this comment.
Isn't args[0] equivalent to self_path? It seems like this push is simply overriding what was previously there.
|
With the latest commit, This is because I have not yet made I feel like this code is a lot hackier as a result of trying to make this work and I don't like it as much, but I've put it up as an RFC to make sure I'm going about things the right way. |
src/librustc/back/link.rs
Outdated
There was a problem hiding this comment.
This should probably still say linking with
There was a problem hiding this comment.
Oops! Missed that in the diff before I pushed. Cheers.
|
Pushed current work. @alexcrichton just waiting now on word about libuv (and watching the related issue over there). |
|
I'm upgrading libuv as part of #10321, after that lands this should be ready for a rebase. |
|
Aha! I've finally landed 10321, so this should be ready for a rebase now. |
|
@alexcrichton rebased and should be good to go (the builders might disagree, though I've done tests). |
src/librustpkg/tests.rs
Outdated
There was a problem hiding this comment.
I don't think that this function exists any more
…cess for getting process termination status, or the signal that terminated a process. A test has been added to rtio-processes.rs to ensure signal termination is picked up correctly.
…mination-by-signal, r=alexcrichton The UvProcess exit callback is called with a zero exit status and non-zero termination signal when a child is terminated by a signal. If a parent checks only the exit status (for example, only checks the return value from `wait()`), it may believe the process completed successfully when it actually failed. Helpers for common use-cases are in `std::rt::io::process`. Should resolve #10062.
| let args = os::args(); | ||
| if args.len() >= 2 && args[1] == ~"signal" { | ||
| // Raise a segfault. | ||
| unsafe { *(0 as *mut int) = 0; } |
There was a problem hiding this comment.
This is UB and has remained unfixed on master, the address should be 1 or something else, not NULL.
Might work on windows too then.
…chton Fix run-pass/signal-exit-status to not trigger UB by writing to NULL. `run-pass/signal-exit-status` has had UB (NULL dereference) since it was introduced in rust-lang#10109. Fixes the test failure found by @camlorn while running under Windows Subsystem for Linux.
Fix FP in needless_return when using yeet Fixes rust-lang#9947 changelog: Fix: [`needless_return`]: don't lint when using `do yeet` rust-lang#10109
The UvProcess exit callback is called with a zero exit status and non-zero termination signal when a child is terminated by a signal.
If a parent checks only the exit status (for example, only checks the return value from
wait()), it may believe the process completed successfully when it actually failed.Helpers for common use-cases are in
std::rt::io::process.Should resolve #10062.