Panicked with "Wait() should either return Ok or panic"


I'm working with std::process::Command and with code like this.

It's ok when I run with cargo run ls. But with cargo run cmd-not-exist, I got:

["target/debug/rust-demo-spawn", "cmd-not-exist"]
code: 0
waitpid ok: Exited(Pid(18790), 1)
thread 'main' panicked at 'wait() should either return Ok or panic', libstd/sys/unix/process/
stack backtrace:
   0:        0x10b784e3f - std::sys::unix::backtrace::tracing::imp::unwind_backtrace::hdfdb4ba75a1dcb88
                               at libstd/sys/unix/backtrace/tracing/
   1:        0x10b77794a - std::sys_common::backtrace::print::h5823bdde4d2f8639
                               at libstd/sys_common/
                               at libstd/sys_common/
   2:        0x10b788ae3 - std::panicking::default_hook::{{closure}}::h06fc925781e26cfe
                               at libstd/
   3:        0x10b78886c - std::panicking::default_hook::hdfdcc6f72e7aec0a
                               at libstd/

It won't panic if I either remove the SIGCHLD handler or p.before_exec() part.

Is there anything I can do to prevent the panic? Or it's an issue of the lib std::process::Command?

i think the problem is that you're waiting for the child process twice: once in the SIGCHLD handler, and once inside match p.spawn().

the second wait won't expect that the process termination was already handled and panics because of that ?

that it only happens in some cases might have to do with timing…

Then why it won't panic if I remove the p.before_exec() part?

And for cmd-not-exist, it won't reach child.wait().

so i tried but cannot get any panics here (ubuntu 18.04, rustc 1.30.0-beta.8 (269c1bdc7 2018-09-27)):

ondoyante:/tmp/proj/src$ cargo run /bin/ls
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `/tmp/proj/target/debug/rust-demo-spawn /bin/ls`
["/tmp/proj/target/debug/rust-demo-spawn", "/bin/ls"]
code: 0
spawn ok: Child { stdin: None, stdout: None, stderr: None }
waitpid error: Sys(ECHILD)
ok: ExitStatus(ExitStatus(0))
the end.
ondoyante:/tmp/proj/src$ cargo run /bin/lsd
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `/tmp/proj/target/debug/rust-demo-spawn /bin/lsd`
["/tmp/proj/target/debug/rust-demo-spawn", "/bin/lsd"]
code: 0
waitpid error: Sys(ECHILD)
spawn error: Os { code: 2, kind: NotFound, message: "No such file or directory" }
the end.

Got help from IRC channel. Basically it is what you said.

SIGCHLD handler got and handled wait() for the child, and the child gone. Then in Command::spawn(), which panic the parent with assert!(p.wait().is_ok(), ...), since wait() returns with error.

I'm using macOS. Just checked with Ubuntu, no such panic :slight_smile:

(Personally think Command::spawn() should replace those asserts with Err.)

Thanks! @vmedea