1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use libafl::executors::ExitKind;
use log::{info, trace, warn};
use once_cell::sync::OnceCell;
use rand::Rng;

use crate::{
    error::Error,
    fuzzer::stats_stage::*,
    protocol::ProtocolBehavior,
    put::PutOptions,
    put_registry::PutRegistry,
    trace::{Action, Trace, TraceContext},
};

static DEFAULT_PUT_OPTIONS: OnceCell<PutOptions> = OnceCell::new();

/// Returns the current default put options which are used
pub fn default_put_options() -> &'static PutOptions {
    DEFAULT_PUT_OPTIONS
        .get()
        .expect("current default put options needs to be set")
}

pub fn set_default_put_options(default_put_options: PutOptions) -> Result<(), ()> {
    DEFAULT_PUT_OPTIONS
        .set(default_put_options)
        .map_err(|_err| ())
}

pub fn harness<PB: ProtocolBehavior + 'static>(
    put_registry: &PutRegistry<PB>,
    input: &Trace<PB::Matcher>,
) -> ExitKind {
    let mut ctx = TraceContext::new(put_registry, default_put_options().clone());

    TRACE_LENGTH.update(input.steps.len());

    for step in &input.steps {
        match &step.action {
            Action::Input(input) => {
                TERM_SIZE.update(input.recipe.size());
            }
            Action::Output(_) => {}
        }
    }

    if let Err(err) = input.execute(&mut ctx) {
        match &err {
            Error::Fn(_) => FN_ERROR.increment(),
            Error::Term(_e) => TERM.increment(),
            Error::Put(_) => PUT.increment(),
            Error::IO(_) => IO.increment(),
            Error::Agent(_) => AGENT.increment(),
            Error::Stream(_) => STREAM.increment(),
            Error::Extraction() => EXTRACTION.increment(),
            Error::SecurityClaim(msg) => {
                warn!("{}", msg);
                std::process::abort()
            }
        }

        trace!("{}", err);
    }

    ExitKind::Ok
}

#[allow(unused)]
pub fn dummy_harness<PB: ProtocolBehavior + 'static>(_input: &Trace<PB::Matcher>) -> ExitKind {
    let mut rng = rand::thread_rng();

    let n1 = rng.gen_range(0..10);
    info!("Run {}", n1);
    if n1 <= 5 {
        return ExitKind::Timeout;
    }
    ExitKind::Ok // Everything other than Ok is recorded in the crash corpus
}