Make exit status interpretable by CommandConfigurator (#2723)

* Make exit status interpretable by CommandConfigurator

* Fix import issues

* Fix default implementation for non-unix environment

* Make docs only available on unix if the entry is only for unix

* Revert "Fix default implementation for non-unix environment"

This reverts commit 5457f6f7376c2a3a4d4c8459de46d6b54bb0d44f.

* Fix the invalid link in the example
This commit is contained in:
Mohammad Omidvar 2024-11-27 11:02:35 -08:00 committed by GitHub
parent 94fa4014ac
commit 0d0bbf0c5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 30 additions and 23 deletions

View File

@ -38,7 +38,9 @@ use typed_builder::TypedBuilder;
use super::HasTimeout;
#[cfg(all(feature = "std", unix))]
use crate::executors::{Executor, ExitKind};
use crate::executors::Executor;
#[cfg(all(feature = "std", any(unix, doc)))]
use crate::executors::ExitKind;
use crate::{
corpus::Corpus,
executors::{hooks::ExecutorHooksTuple, HasObservers},
@ -337,8 +339,6 @@ where
OT: Debug + ObserversTuple<I, S>,
{
fn execute_input_with_command(&mut self, state: &mut S, input: &I) -> Result<ExitKind, Error> {
use std::os::unix::prelude::ExitStatusExt;
use wait_timeout::ChildExt;
*state.executions_mut() += 1;
@ -346,29 +346,21 @@ where
let mut child = self.configurer.spawn_child(input)?;
let res = match child
let exit_kind = child
.wait_timeout(self.configurer.exec_timeout())
.expect("waiting on child failed")
.map(|status| status.signal())
{
// for reference: https://www.man7.org/linux/man-pages/man7/signal.7.html
Some(Some(9)) => Ok(ExitKind::Oom),
Some(Some(_)) => Ok(ExitKind::Crash),
Some(None) => Ok(ExitKind::Ok),
None => {
.map(|status| self.configurer.exit_kind_from_status(&status))
.unwrap_or_else(|| {
// if this fails, there is not much we can do. let's hope it failed because the process finished
// in the meantime.
drop(child.kill());
// finally, try to wait to properly clean up system resources.
drop(child.wait());
Ok(ExitKind::Timeout)
}
};
ExitKind::Timeout
});
if let Ok(exit_kind) = res {
self.observers
.post_exec_child_all(state, input, &exit_kind)?;
}
if let Some(h) = &mut self.configurer.stdout_observer() {
let mut stdout = Vec::new();
@ -392,7 +384,7 @@ where
let obs = observers.index_mut(h);
obs.observe_stderr(&stderr);
}
res
Ok(exit_kind)
}
}
@ -809,7 +801,7 @@ impl CommandExecutorBuilder {
/// MyExecutor.into_executor(())
/// }
/// ```
#[cfg(all(feature = "std", any(unix, doc)))]
#[cfg(all(feature = "std", unix))]
pub trait CommandConfigurator<I, C = Child>: Sized {
/// Get the stdout
fn stdout_observer(&self) -> Option<Handle<StdOutObserver>> {
@ -828,6 +820,18 @@ pub trait CommandConfigurator<I, C = Child>: Sized {
/// Set the timeout duration for execution of the child process.
fn exec_timeout_mut(&mut self) -> &mut Duration;
/// Maps the exit status of the child process to an `ExitKind`.
#[inline]
fn exit_kind_from_status(&self, status: &std::process::ExitStatus) -> ExitKind {
use crate::std::os::unix::process::ExitStatusExt;
match status.signal() {
// for reference: https://www.man7.org/linux/man-pages/man7/signal.7.html
Some(9) => ExitKind::Oom,
Some(_) => ExitKind::Crash,
None => ExitKind::Ok,
}
}
/// Create an `Executor` from this `CommandConfigurator`.
fn into_executor<OT, S>(self, observers: OT) -> CommandExecutor<OT, S, Self, (), C>
where

View File

@ -5,7 +5,7 @@ use alloc::vec::Vec;
use core::{fmt::Debug, time::Duration};
pub use combined::CombinedExecutor;
#[cfg(all(feature = "std", any(unix, doc)))]
#[cfg(all(feature = "std", unix))]
pub use command::CommandExecutor;
pub use differential::DiffExecutor;
#[cfg(all(feature = "std", feature = "fork", unix))]
@ -23,7 +23,7 @@ pub use with_observers::WithObservers;
use crate::{state::UsesState, Error};
pub mod combined;
#[cfg(all(feature = "std", any(unix, doc)))]
#[cfg(all(feature = "std", unix))]
pub mod command;
pub mod differential;
#[cfg(all(feature = "std", feature = "fork", unix))]

View File

@ -2,7 +2,10 @@
//!
//! The [`StdOutObserver`] and [`StdErrObserver`] observers look at the stdout of a program
//! The executor must explicitly support these observers.
//! For example, they are supported on the [`crate::executors::CommandExecutor`].
#![cfg_attr(
all(feature = "std", unix),
doc = r"For example, they are supported on the [`crate::executors::CommandExecutor`]."
)]
use alloc::borrow::Cow;
use std::vec::Vec;