I've encountered an error where memfd_exec::process::ExitStatus::success returns false when the execution was successful and returned with status code 0.
Minimal example to reproduce:
use memfd_exec::MemFdExecutable;
fn main() {
let code = include_bytes!("/usr/bin/echo");
let exit_status = MemFdExecutable::new("echo", code)
.arg("Hello")
.status()
.expect("failed to execute process");
// Exit status is 0
println!("exit status {exit_status:?}");
// Success fails
assert!(exit_status.success());
}
It looks like the issue is in ExitStatus::exit_ok:
/// Was termination successful? Returns a Result.
pub fn exit_ok(&self) -> Result<()> {
// This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
// true on all actual versions of Unix, is widely assumed, and is specified in SuS
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html . If it is not
// true for a platform pretending to be Unix, the tests (our doctests, and also
// procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
#[allow(clippy::useless_conversion)]
match c_int::try_from(self.0) {
/* was nonzero */
Ok(failure) => Err(Error::new(
std::io::ErrorKind::Other,
format!("process exited with status {}", failure),
)),
/* was zero, couldn't convert */
Err(_) => Ok(()),
}
}
This assumes that c_int::try_from(self.0) will fail if self.0 == 0, but a c_int can be 0 and the conversion always succeeds.
The standard library implementation (for std::sys::pal::unix::process::process_inner::ExitStatus) is:
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
// This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
// true on all actual versions of Unix, is widely assumed, and is specified in SuS
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
// true for a platform pretending to be Unix, the tests (our doctests, and also
// process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
match NonZero::try_from(self.0) {
/* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
/* was zero, couldn't convert */ Err(_) => Ok(()),
}
}
Which makes sense, because NonZero actually cannot be 0, unlike c_int.
I've encountered an error where
memfd_exec::process::ExitStatus::successreturns false when the execution was successful and returned with status code 0.Minimal example to reproduce:
It looks like the issue is in
ExitStatus::exit_ok:This assumes that
c_int::try_from(self.0)will fail ifself.0 == 0, but ac_intcan be 0 and the conversion always succeeds.The standard library implementation (for
std::sys::pal::unix::process::process_inner::ExitStatus) is:Which makes sense, because
NonZeroactually cannot be 0, unlikec_int.