use core::marker::PhantomData;
#[cfg(feature = "std")]
use std::process::Child;
#[cfg(feature = "std")]
use crate::{executors::HasObservers, inputs::Input, observers::ObserversTuple, Error};
#[cfg(all(feature = "std", unix))]
use crate::executors::{Executor, ExitKind};
#[cfg(all(feature = "std", unix))]
use std::time::Duration;
pub struct CommandExecutor<EM, I, S, Z, T, OT> {
inner: T,
observers: OT,
phantom: PhantomData<(EM, I, S, Z)>,
}
impl<EM, I, S, Z, T, OT> CommandExecutor<EM, I, S, Z, T, OT> {
pub fn inner(&mut self) -> &mut T {
&mut self.inner
}
}
#[cfg(all(feature = "std", unix))]
impl<EM, I, S, Z, T, OT> Executor<EM, I, S, Z> for CommandExecutor<EM, I, S, Z, T, OT>
where
I: Input,
T: CommandConfigurator<EM, I, S, Z>,
OT: ObserversTuple<I, S>,
{
fn run_target(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
input: &I,
) -> Result<ExitKind, Error> {
use std::os::unix::prelude::ExitStatusExt;
use wait_timeout::ChildExt;
let mut child = self.inner.spawn_child(_fuzzer, _state, _mgr, input)?;
match child
.wait_timeout(Duration::from_secs(5))
.expect("waiting on child failed")
.map(|status| status.signal())
{
Some(Some(9)) => Ok(ExitKind::Oom),
Some(Some(_)) => Ok(ExitKind::Crash),
Some(None) => Ok(ExitKind::Ok),
None => {
drop(child.kill());
drop(child.wait());
Ok(ExitKind::Timeout)
}
}
}
}
#[cfg(feature = "std")]
impl<EM, I, S, Z, T, OT> HasObservers<I, OT, S> for CommandExecutor<EM, I, S, Z, T, OT>
where
I: Input,
OT: ObserversTuple<I, S>,
T: CommandConfigurator<EM, I, S, Z>,
{
#[inline]
fn observers(&self) -> &OT {
&self.observers
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
}
}
#[cfg(feature = "std")]
pub trait CommandConfigurator<EM, I: Input, S, Z>: Sized {
fn spawn_child(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<Child, Error>;
fn into_executor<OT>(self, observers: OT) -> CommandExecutor<EM, I, S, Z, Self, OT>
where
OT: ObserversTuple<I, S>,
{
CommandExecutor {
inner: self,
observers,
phantom: PhantomData,
}
}
}