Intial support to Python bindings for the libafl crate (#429)
* Add libafl py module * Hardcoded baby_fuzzer * Trait abstraction: MapObserver Send type name as a param as it's needed for extracting the rust struct from the PyObject * Fix merge * Impl traits for python wrappers * Add PythonExecutor Not buildable version * Executor trait bindings * Monitor trait bindings * EventManager trait bindings * Fix warnings * Add corpus trait bindings * Use corpus trait bindings * Rand trait bindings * Remove python feature from default * Add cfg attribute * Fix fmt * No std box * Fix clippy * turn OwnedInProcessExecutor in a simple type alias * remove crate-type from libafl's Cargo.toml * Add python baby_fuzzer * Fix doc * Maturin doc * multiple map observer * fmt * build pylibafl with nightly * macro for map element type * Update py baby_fuzzer & fmt * Mutator bindings * fmt * merge conflicts * StdMutationalStage bindings Not working: Cannot pass mutator to new method because not clonable * Stage bindings * StagesOwnedList bindings Not working: Stage not clonable * Unsafe transmute copy fix * Use Stage bindings in baby_fuzzer * fmt * fmt * Fix doc * fix merge * Remove x86_64 feature from pylibafl Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
This commit is contained in:
parent
393afa56c8
commit
2dcdaaa89f
@ -7,6 +7,8 @@ edition = "2021"
|
|||||||
pyo3 = { version = "0.15", features = ["extension-module"] }
|
pyo3 = { version = "0.15", features = ["extension-module"] }
|
||||||
libafl_qemu = { path = "../../libafl_qemu", version = "0.7", features = ["python"] }
|
libafl_qemu = { path = "../../libafl_qemu", version = "0.7", features = ["python"] }
|
||||||
libafl_sugar = { path = "../../libafl_sugar", version = "0.7", features = ["python"] }
|
libafl_sugar = { path = "../../libafl_sugar", version = "0.7", features = ["python"] }
|
||||||
|
libafl = { path = "../../libafl", version = "0.7", features = ["python"] }
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pyo3-build-config = { version = "0.15" }
|
pyo3-build-config = { version = "0.15" }
|
||||||
@ -14,3 +16,6 @@ pyo3-build-config = { version = "0.15" }
|
|||||||
[lib]
|
[lib]
|
||||||
name = "pylibafl"
|
name = "pylibafl"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
31
bindings/pylibafl/README.md
Normal file
31
bindings/pylibafl/README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# How to use python bindings
|
||||||
|
## First time setup
|
||||||
|
```
|
||||||
|
# Create environment variable
|
||||||
|
python -m venv .env
|
||||||
|
# Install maturin
|
||||||
|
pip install maturin
|
||||||
|
```
|
||||||
|
## Build bindings
|
||||||
|
```
|
||||||
|
# Activate virtual environment
|
||||||
|
source .env/bin/activate
|
||||||
|
# Build python module
|
||||||
|
maturin develop
|
||||||
|
```
|
||||||
|
This is going to install `pylibafl` python module.
|
||||||
|
|
||||||
|
## Use bindings
|
||||||
|
### Example: Running baby_fuzzer in fuzzers/baby_fuzzer/baby_fuzzer.py
|
||||||
|
First, make sure the python virtual environment is activated. If not, run `source .env/bin/activate
|
||||||
|
`. Running `pip freeze` at this point should display the following (versions may differ):
|
||||||
|
```
|
||||||
|
maturin==0.12.6
|
||||||
|
pylibafl==0.7.0
|
||||||
|
toml==0.10.2
|
||||||
|
```
|
||||||
|
Then simply run
|
||||||
|
```
|
||||||
|
python PATH_TO_BABY_FUZZER/baby_fuzzer.py
|
||||||
|
```
|
||||||
|
The crashes' directory will be created in the directory from which you ran the command.
|
1
bindings/pylibafl/rust-toolchain
Normal file
1
bindings/pylibafl/rust-toolchain
Normal file
@ -0,0 +1 @@
|
|||||||
|
nightly
|
@ -1,5 +1,6 @@
|
|||||||
use libafl_qemu;
|
use libafl_qemu;
|
||||||
use libafl_sugar;
|
use libafl_sugar;
|
||||||
|
use libafl;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
@ -13,5 +14,9 @@ pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
|
|||||||
libafl_qemu::python_module(py, qemu_module)?;
|
libafl_qemu::python_module(py, qemu_module)?;
|
||||||
m.add_submodule(qemu_module)?;
|
m.add_submodule(qemu_module)?;
|
||||||
|
|
||||||
|
let libafl_module = PyModule::new(py, "libafl")?;
|
||||||
|
libafl::python_module(py, libafl_module)?;
|
||||||
|
m.add_submodule(libafl_module)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
70
fuzzers/baby_fuzzer/baby_fuzzer.py
Normal file
70
fuzzers/baby_fuzzer/baby_fuzzer.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
from pylibafl import libafl
|
||||||
|
|
||||||
|
# LIBRARY WRAPPER
|
||||||
|
|
||||||
|
def map_observer_wrapper(map_observer):
|
||||||
|
if type(map_observer).__name__ == "OwnedMapObserverI32":
|
||||||
|
return libafl.MapObserverI32.new_from_owned(map_observer)
|
||||||
|
|
||||||
|
def executor_wrapper(executor):
|
||||||
|
if type(executor).__name__ == "OwnedInProcessExecutorI32":
|
||||||
|
return libafl.ExecutorI32.new_from_inprocess(executor)
|
||||||
|
|
||||||
|
def monitor_wrapper(monitor):
|
||||||
|
if type(monitor).__name__ == "SimpleMonitor":
|
||||||
|
return libafl.Monitor.new_from_simple(monitor)
|
||||||
|
|
||||||
|
def event_manager_wrapper(event_manager):
|
||||||
|
if type(event_manager).__name__ == "SimpleEventManager":
|
||||||
|
return libafl.EventManagerI32.new_from_simple(event_manager)
|
||||||
|
|
||||||
|
def corpus_wrapper(corpus):
|
||||||
|
if type(corpus).__name__ == "InMemoryCorpus":
|
||||||
|
return libafl.Corpus.new_from_in_memory(corpus)
|
||||||
|
if type(corpus).__name__ == "OnDiskCorpus":
|
||||||
|
return libafl.Corpus.new_from_on_disk(corpus)
|
||||||
|
|
||||||
|
def rand_wrapper(rand):
|
||||||
|
if type(rand).__name__ == "StdRand":
|
||||||
|
return libafl.Rand.new_from_std(rand)
|
||||||
|
|
||||||
|
def stage_wrapper(stage):
|
||||||
|
if type(stage).__name__ == "StdScheduledHavocMutationsStageI32":
|
||||||
|
return libafl.StageI32.new_from_std_scheduled(stage)
|
||||||
|
|
||||||
|
# CODE WRITTEN BY USER
|
||||||
|
|
||||||
|
def harness(inp):
|
||||||
|
if len(inp.hex()) >= 2 and inp.hex()[:2] == '61':
|
||||||
|
raise Exception("NOOOOOO =)")
|
||||||
|
|
||||||
|
map_observer = libafl.OwnedMapObserverI32("signals", [0] * 16)
|
||||||
|
|
||||||
|
feedback_state = libafl.MapFeedbackStateI32.with_observer(map_observer_wrapper(map_observer))
|
||||||
|
|
||||||
|
feedback = libafl.MaxMapFeedbackI32(feedback_state, map_observer_wrapper(map_observer))
|
||||||
|
|
||||||
|
state = libafl.StdStateI32(
|
||||||
|
rand_wrapper(libafl.StdRand.with_current_nanos()),
|
||||||
|
corpus_wrapper(libafl.InMemoryCorpus()),
|
||||||
|
corpus_wrapper(libafl.OnDiskCorpus("./crashes")),
|
||||||
|
feedback_state
|
||||||
|
)
|
||||||
|
|
||||||
|
monitor = libafl.SimpleMonitor()
|
||||||
|
|
||||||
|
mgr = libafl.SimpleEventManager(monitor_wrapper(monitor))
|
||||||
|
|
||||||
|
fuzzer = libafl.StdFuzzerI32(feedback)
|
||||||
|
|
||||||
|
executor = libafl.OwnedInProcessExecutorI32(harness, map_observer_wrapper(map_observer), fuzzer, state, event_manager_wrapper(mgr))
|
||||||
|
|
||||||
|
generator = libafl.RandPrintablesGeneratorI32(32)
|
||||||
|
|
||||||
|
state.generate_initial_inputs(fuzzer, executor_wrapper(executor), generator, event_manager_wrapper(mgr), 8)
|
||||||
|
|
||||||
|
stage = libafl.StdScheduledHavocMutationsStageI32.new_from_scheduled_havoc_mutations()
|
||||||
|
|
||||||
|
stage_tuple_list = libafl.StagesOwnedListI32(stage_wrapper(stage))
|
||||||
|
|
||||||
|
fuzzer.fuzz_loop(executor_wrapper(executor), state, event_manager_wrapper(mgr), stage_tuple_list)
|
@ -19,6 +19,7 @@ fork = [] # uses the fork() syscall to spawn children, instead of launching a ne
|
|||||||
rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng`
|
rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng`
|
||||||
introspection = [] # Include performance statistics of the fuzzing pipeline
|
introspection = [] # Include performance statistics of the fuzzing pipeline
|
||||||
concolic_mutation = ["z3"] # include a simple concolic mutator based on z3
|
concolic_mutation = ["z3"] # include a simple concolic mutator based on z3
|
||||||
|
python = ["pyo3"]
|
||||||
tui_monitor = ["tui", "crossterm"] # enable TuiMonitor with crossterm
|
tui_monitor = ["tui", "crossterm"] # enable TuiMonitor with crossterm
|
||||||
cli = ["clap"] # expose bolts::cli
|
cli = ["clap"] # expose bolts::cli
|
||||||
qemu_cli = ["cli"]
|
qemu_cli = ["cli"]
|
||||||
@ -81,6 +82,8 @@ wait-timeout = { version = "0.2", optional = true } # used by CommandExecutor to
|
|||||||
|
|
||||||
z3 = { version = "0.11", features = ["static-link-z3"], optional = true } # for concolic mutation
|
z3 = { version = "0.11", features = ["static-link-z3"], optional = true } # for concolic mutation
|
||||||
|
|
||||||
|
pyo3 = { version = "0.15", optional = true }
|
||||||
|
|
||||||
# AGPL
|
# AGPL
|
||||||
# !!! this create requires nightly
|
# !!! this create requires nightly
|
||||||
grammartec = { version = "0.1", optional = true }
|
grammartec = { version = "0.1", optional = true }
|
||||||
|
@ -224,7 +224,7 @@ unsafe fn handle_signal(sig: c_int, info: siginfo_t, void: *mut c_void) {
|
|||||||
|
|
||||||
/// Setup signal handlers in a somewhat rusty way.
|
/// Setup signal handlers in a somewhat rusty way.
|
||||||
/// This will allocate a signal stack and set the signal handlers accordingly.
|
/// This will allocate a signal stack and set the signal handlers accordingly.
|
||||||
/// It is, for example, used in the [`struct@crate::executors::InProcessExecutor`] to restart the fuzzer in case of a crash,
|
/// It is, for example, used in the [`type@crate::executors::InProcessExecutor`] to restart the fuzzer in case of a crash,
|
||||||
/// or to handle `SIGINT` in the broker process.
|
/// or to handle `SIGINT` in the broker process.
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The signal handlers will be called on any signal. They should (tm) be async safe.
|
/// The signal handlers will be called on any signal. They should (tm) be async safe.
|
||||||
|
@ -430,3 +430,81 @@ mod tests {
|
|||||||
println!("random value: {}", mutator.rng.next_u32());
|
println!("random value: {}", mutator.rng.next_u32());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `Rand` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use super::Rand;
|
||||||
|
use crate::bolts::{current_nanos, rands::StdRand};
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = "StdRand")]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
/// Python class for StdRand
|
||||||
|
pub struct PythonStdRand {
|
||||||
|
/// Rust wrapped StdRand object
|
||||||
|
pub std_rand: StdRand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonStdRand {
|
||||||
|
#[staticmethod]
|
||||||
|
fn with_current_nanos() -> Self {
|
||||||
|
Self {
|
||||||
|
std_rand: StdRand::with_seed(current_nanos()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[staticmethod]
|
||||||
|
fn with_seed(seed: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
std_rand: StdRand::with_seed(seed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
enum PythonRandWrapper {
|
||||||
|
StdRand(PythonStdRand),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rand Trait binding
|
||||||
|
#[pyclass(unsendable, name = "Rand")]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct PythonRand {
|
||||||
|
rand: PythonRandWrapper,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonRand {
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_std(py_std_rand: PythonStdRand) -> Self {
|
||||||
|
Self {
|
||||||
|
rand: PythonRandWrapper::StdRand(py_std_rand),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rand for PythonRand {
|
||||||
|
fn set_seed(&mut self, seed: u64) {
|
||||||
|
match &mut self.rand {
|
||||||
|
PythonRandWrapper::StdRand(py_std_rand) => py_std_rand.std_rand.set_seed(seed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> u64 {
|
||||||
|
match &mut self.rand {
|
||||||
|
PythonRandWrapper::StdRand(py_std_rand) => py_std_rand.std_rand.next(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonStdRand>()?;
|
||||||
|
m.add_class::<PythonRand>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -133,3 +133,38 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ``CachedOnDiskCorpus`` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::corpus::CachedOnDiskCorpus;
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = "CachedOnDiskCorpus")]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
/// Python class for CachedOnDiskCorpus
|
||||||
|
pub struct PythonCachedOnDiskCorpus {
|
||||||
|
/// Rust wrapped CachedOnDiskCorpus object
|
||||||
|
pub cached_on_disk_corpus: CachedOnDiskCorpus<BytesInput>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonCachedOnDiskCorpus {
|
||||||
|
#[new]
|
||||||
|
fn new(path: String, cache_max_len: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
cached_on_disk_corpus: CachedOnDiskCorpus::new(PathBuf::from(path), cache_max_len)
|
||||||
|
.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonCachedOnDiskCorpus>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -87,3 +87,35 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `InMemoryCorpus` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::corpus::InMemoryCorpus;
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = "InMemoryCorpus")]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
/// Python class for InMemoryCorpus
|
||||||
|
pub struct PythonInMemoryCorpus {
|
||||||
|
/// Rust wrapped InMemoryCorpus object
|
||||||
|
pub in_memory_corpus: InMemoryCorpus<BytesInput>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonInMemoryCorpus {
|
||||||
|
#[new]
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
in_memory_corpus: InMemoryCorpus::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonInMemoryCorpus>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -148,3 +148,171 @@ impl Default for RandCorpusScheduler {
|
|||||||
/// A [`StdCorpusScheduler`] uses the default scheduler in `LibAFL` to schedule [`Testcase`]s.
|
/// A [`StdCorpusScheduler`] uses the default scheduler in `LibAFL` to schedule [`Testcase`]s.
|
||||||
/// The current `Std` is a [`RandCorpusScheduler`], although this may change in the future, if another [`CorpusScheduler`] delivers better results.
|
/// The current `Std` is a [`RandCorpusScheduler`], although this may change in the future, if another [`CorpusScheduler`] delivers better results.
|
||||||
pub type StdCorpusScheduler = RandCorpusScheduler;
|
pub type StdCorpusScheduler = RandCorpusScheduler;
|
||||||
|
|
||||||
|
/// `Corpus` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::corpus::inmemory::pybind::PythonInMemoryCorpus;
|
||||||
|
use crate::corpus::{Corpus, Testcase};
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use crate::Error;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use super::cached::pybind::PythonCachedOnDiskCorpus;
|
||||||
|
use super::ondisk::pybind::PythonOnDiskCorpus;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
enum PythonCorpusWrapper {
|
||||||
|
InMemory(PythonInMemoryCorpus),
|
||||||
|
CachedOnDisk(PythonCachedOnDiskCorpus),
|
||||||
|
OnDisk(PythonOnDiskCorpus),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Corpus Trait binding
|
||||||
|
#[pyclass(unsendable, name = "Corpus")]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct PythonCorpus {
|
||||||
|
corpus: PythonCorpusWrapper,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonCorpus {
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_in_memory(py_in_memory_corpus: PythonInMemoryCorpus) -> Self {
|
||||||
|
Self {
|
||||||
|
corpus: PythonCorpusWrapper::InMemory(py_in_memory_corpus),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_cached_on_disk(py_cached_on_disk_corpus: PythonCachedOnDiskCorpus) -> Self {
|
||||||
|
Self {
|
||||||
|
corpus: PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_on_disk(py_on_disk_corpus: PythonOnDiskCorpus) -> Self {
|
||||||
|
Self {
|
||||||
|
corpus: PythonCorpusWrapper::OnDisk(py_on_disk_corpus),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Corpus<BytesInput> for PythonCorpus {
|
||||||
|
#[inline]
|
||||||
|
fn count(&self) -> usize {
|
||||||
|
match &self.corpus {
|
||||||
|
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
|
||||||
|
py_in_memory_corpus.in_memory_corpus.count()
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
|
||||||
|
py_cached_on_disk_corpus.cached_on_disk_corpus.count()
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
|
||||||
|
py_on_disk_corpus.on_disk_corpus.count()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
|
||||||
|
match &mut self.corpus {
|
||||||
|
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
|
||||||
|
py_in_memory_corpus.in_memory_corpus.add(testcase)
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
|
||||||
|
py_cached_on_disk_corpus.cached_on_disk_corpus.add(testcase)
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
|
||||||
|
py_on_disk_corpus.on_disk_corpus.add(testcase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
|
||||||
|
match &mut self.corpus {
|
||||||
|
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
|
||||||
|
py_in_memory_corpus.in_memory_corpus.replace(idx, testcase)
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
|
||||||
|
py_cached_on_disk_corpus
|
||||||
|
.cached_on_disk_corpus
|
||||||
|
.replace(idx, testcase)
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
|
||||||
|
py_on_disk_corpus.on_disk_corpus.replace(idx, testcase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
|
||||||
|
match &mut self.corpus {
|
||||||
|
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
|
||||||
|
py_in_memory_corpus.in_memory_corpus.remove(idx)
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
|
||||||
|
py_cached_on_disk_corpus.cached_on_disk_corpus.remove(idx)
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
|
||||||
|
py_on_disk_corpus.on_disk_corpus.remove(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
|
||||||
|
match &self.corpus {
|
||||||
|
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
|
||||||
|
py_in_memory_corpus.in_memory_corpus.get(idx)
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
|
||||||
|
py_cached_on_disk_corpus.cached_on_disk_corpus.get(idx)
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
|
||||||
|
py_on_disk_corpus.on_disk_corpus.get(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn current(&self) -> &Option<usize> {
|
||||||
|
match &self.corpus {
|
||||||
|
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
|
||||||
|
py_in_memory_corpus.in_memory_corpus.current()
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
|
||||||
|
py_cached_on_disk_corpus.cached_on_disk_corpus.current()
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
|
||||||
|
py_on_disk_corpus.on_disk_corpus.current()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn current_mut(&mut self) -> &mut Option<usize> {
|
||||||
|
match &mut self.corpus {
|
||||||
|
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
|
||||||
|
py_in_memory_corpus.in_memory_corpus.current_mut()
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
|
||||||
|
py_cached_on_disk_corpus.cached_on_disk_corpus.current_mut()
|
||||||
|
}
|
||||||
|
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
|
||||||
|
py_on_disk_corpus.on_disk_corpus.current_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonCorpus>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -205,3 +205,36 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `OnDiskCorpus` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::corpus::OnDiskCorpus;
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = "OnDiskCorpus")]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
/// Python class for OnDiskCorpus
|
||||||
|
pub struct PythonOnDiskCorpus {
|
||||||
|
/// Rust wrapped OnDiskCorpus object
|
||||||
|
pub on_disk_corpus: OnDiskCorpus<BytesInput>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonOnDiskCorpus {
|
||||||
|
#[new]
|
||||||
|
fn new(path: String) -> Self {
|
||||||
|
Self {
|
||||||
|
on_disk_corpus: OnDiskCorpus::new(PathBuf::from(path)).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonOnDiskCorpus>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -543,3 +543,208 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// `EventManager` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::events::simple::pybind::PythonSimpleEventManager;
|
||||||
|
use crate::events::{
|
||||||
|
Event, EventFirer, EventManager, EventManagerId, EventProcessor, EventRestarter,
|
||||||
|
HasEventManagerId, ProgressReporter,
|
||||||
|
};
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use crate::Error;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! define_python_event_manager {
|
||||||
|
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $std_state_name: ident, $executor_name: ident, $my_std_fuzzer_type_name: ident) => {
|
||||||
|
use crate::executors::pybind::$executor_name;
|
||||||
|
use crate::pybind::$my_std_fuzzer_type_name;
|
||||||
|
use crate::state::pybind::$std_state_name;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum $wrapper_name {
|
||||||
|
Simple(*mut PythonSimpleEventManager),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// EventManager Trait binding
|
||||||
|
#[pyclass(unsendable, name = $py_name_trait)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct $struct_name_trait {
|
||||||
|
event_manager: $wrapper_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $struct_name_trait {
|
||||||
|
fn get_event_manager(
|
||||||
|
&self,
|
||||||
|
) -> &impl EventManager<
|
||||||
|
$executor_name,
|
||||||
|
BytesInput,
|
||||||
|
$std_state_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
> {
|
||||||
|
unsafe {
|
||||||
|
match self.event_manager {
|
||||||
|
$wrapper_name::Simple(py_simple_event_manager) => {
|
||||||
|
&(*py_simple_event_manager).simple_event_manager
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut_event_manager(
|
||||||
|
&mut self,
|
||||||
|
) -> &mut impl EventManager<
|
||||||
|
$executor_name,
|
||||||
|
BytesInput,
|
||||||
|
$std_state_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
> {
|
||||||
|
unsafe {
|
||||||
|
match self.event_manager {
|
||||||
|
$wrapper_name::Simple(py_simple_event_manager) => {
|
||||||
|
&mut (*py_simple_event_manager).simple_event_manager
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name_trait {
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_simple(py_simple_event_manager: &mut PythonSimpleEventManager) -> Self {
|
||||||
|
Self {
|
||||||
|
event_manager: $wrapper_name::Simple(py_simple_event_manager),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventFirer<BytesInput> for $struct_name_trait {
|
||||||
|
fn fire<S>(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut S,
|
||||||
|
event: Event<BytesInput>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.get_mut_event_manager().fire(_state, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> EventRestarter<S> for $struct_name_trait {}
|
||||||
|
|
||||||
|
impl
|
||||||
|
EventProcessor<
|
||||||
|
$executor_name,
|
||||||
|
BytesInput,
|
||||||
|
$std_state_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
> for $struct_name_trait
|
||||||
|
{
|
||||||
|
fn process(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut $my_std_fuzzer_type_name,
|
||||||
|
state: &mut $std_state_name,
|
||||||
|
_executor: &mut $executor_name,
|
||||||
|
) -> Result<usize, Error> {
|
||||||
|
self.get_mut_event_manager()
|
||||||
|
.process(_fuzzer, state, _executor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProgressReporter<BytesInput> for $struct_name_trait {}
|
||||||
|
|
||||||
|
impl HasEventManagerId for $struct_name_trait {
|
||||||
|
fn mgr_id(&self) -> EventManagerId {
|
||||||
|
self.get_event_manager().mgr_id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventManager<$executor_name, BytesInput, $std_state_name, $my_std_fuzzer_type_name>
|
||||||
|
for $struct_name_trait
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonEventManagerI8,
|
||||||
|
"EventManagerI8",
|
||||||
|
PythonEventManagerWrapperI8,
|
||||||
|
MyStdStateI8,
|
||||||
|
PythonExecutorI8,
|
||||||
|
MyStdFuzzerI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonEventManagerI16,
|
||||||
|
"EventManagerI16",
|
||||||
|
PythonEventManagerWrapperI16,
|
||||||
|
MyStdStateI16,
|
||||||
|
PythonExecutorI16,
|
||||||
|
MyStdFuzzerI16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonEventManagerI32,
|
||||||
|
"EventManagerI32",
|
||||||
|
PythonEventManagerWrapperI32,
|
||||||
|
MyStdStateI32,
|
||||||
|
PythonExecutorI32,
|
||||||
|
MyStdFuzzerI32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonEventManagerI64,
|
||||||
|
"EventManagerI64",
|
||||||
|
PythonEventManagerWrapperI64,
|
||||||
|
MyStdStateI64,
|
||||||
|
PythonExecutorI64,
|
||||||
|
MyStdFuzzerI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonEventManagerU8,
|
||||||
|
"EventManagerU8",
|
||||||
|
PythonEventManagerWrapperU8,
|
||||||
|
MyStdStateU8,
|
||||||
|
PythonExecutorU8,
|
||||||
|
MyStdFuzzerU8
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonEventManagerU16,
|
||||||
|
"EventManagerU16",
|
||||||
|
PythonEventManagerWrapperU16,
|
||||||
|
MyStdStateU16,
|
||||||
|
PythonExecutorU16,
|
||||||
|
MyStdFuzzerU16
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonEventManagerU32,
|
||||||
|
"EventManagerU32",
|
||||||
|
PythonEventManagerWrapperU32,
|
||||||
|
MyStdStateU32,
|
||||||
|
PythonExecutorU32,
|
||||||
|
MyStdFuzzerU32
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonEventManagerU64,
|
||||||
|
"EventManagerU64",
|
||||||
|
PythonEventManagerWrapperU64,
|
||||||
|
MyStdStateU64,
|
||||||
|
PythonExecutorU64,
|
||||||
|
MyStdFuzzerU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonEventManagerI8>()?;
|
||||||
|
m.add_class::<PythonEventManagerI16>()?;
|
||||||
|
m.add_class::<PythonEventManagerI32>()?;
|
||||||
|
m.add_class::<PythonEventManagerI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonEventManagerU8>()?;
|
||||||
|
m.add_class::<PythonEventManagerU16>()?;
|
||||||
|
m.add_class::<PythonEventManagerU32>()?;
|
||||||
|
m.add_class::<PythonEventManagerU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -425,3 +425,35 @@ where
|
|||||||
Ok((state, mgr))
|
Ok((state, mgr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// `SimpleEventManager` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::events::SimpleEventManager;
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use crate::monitors::pybind::PythonMonitor;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = "SimpleEventManager")]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
/// Python class for SimpleEventManager
|
||||||
|
pub struct PythonSimpleEventManager {
|
||||||
|
/// Rust wrapped SimpleEventManager object
|
||||||
|
pub simple_event_manager: SimpleEventManager<BytesInput, PythonMonitor>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonSimpleEventManager {
|
||||||
|
#[new]
|
||||||
|
fn new(py_monitor: PythonMonitor) -> Self {
|
||||||
|
Self {
|
||||||
|
simple_event_manager: SimpleEventManager::new(py_monitor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonSimpleEventManager>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
//! Needs the `fork` feature flag.
|
//! Needs the `fork` feature flag.
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
|
borrow::BorrowMut,
|
||||||
ffi::c_void,
|
ffi::c_void,
|
||||||
fmt::{self, Debug, Formatter},
|
fmt::{self, Debug, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
@ -16,6 +17,8 @@ use core::{
|
|||||||
sync::atomic::{compiler_fence, Ordering},
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
#[cfg(all(feature = "std", unix))]
|
#[cfg(all(feature = "std", unix))]
|
||||||
use std::intrinsics::transmute;
|
use std::intrinsics::transmute;
|
||||||
|
|
||||||
@ -52,40 +55,50 @@ use crate::{
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The process executor simply calls a target function, as mutable reference to a closure
|
||||||
|
pub type InProcessExecutor<'a, H, I, OT, S> = GenericInProcessExecutor<H, &'a mut H, I, OT, S>;
|
||||||
|
|
||||||
|
/// The process executor simply calls a target function, as boxed `FnMut` trait object
|
||||||
|
pub type OwnedInProcessExecutor<I, OT, S> =
|
||||||
|
GenericInProcessExecutor<dyn FnMut(&I) -> ExitKind, Box<dyn FnMut(&I) -> ExitKind>, I, OT, S>;
|
||||||
|
|
||||||
/// The inmem executor simply calls a target function, then returns afterwards.
|
/// The inmem executor simply calls a target function, then returns afterwards.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct InProcessExecutor<'a, H, I, OT, S>
|
pub struct GenericInProcessExecutor<H, HB, I, OT, S>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
|
HB: BorrowMut<H>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
/// The harness function, being executed for each fuzzing loop execution
|
/// The harness function, being executed for each fuzzing loop execution
|
||||||
harness_fn: &'a mut H,
|
harness_fn: HB,
|
||||||
/// The observers, observing each run
|
/// The observers, observing each run
|
||||||
observers: OT,
|
observers: OT,
|
||||||
// Crash and timeout hah
|
// Crash and timeout hah
|
||||||
handlers: InProcessHandlers,
|
handlers: InProcessHandlers,
|
||||||
phantom: PhantomData<(I, S)>,
|
phantom: PhantomData<(I, S, *const H)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H, I, OT, S> Debug for InProcessExecutor<'a, H, I, OT, S>
|
impl<H, HB, I, OT, S> Debug for GenericInProcessExecutor<H, HB, I, OT, S>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
|
HB: BorrowMut<H>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("InProcessExecutor")
|
f.debug_struct("GenericInProcessExecutor")
|
||||||
.field("harness_fn", &"<fn>")
|
.field("harness_fn", &"<fn>")
|
||||||
.field("observers", &self.observers)
|
.field("observers", &self.observers)
|
||||||
.finish_non_exhaustive()
|
.finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, EM, H, I, OT, S, Z> Executor<EM, I, S, Z> for InProcessExecutor<'a, H, I, OT, S>
|
impl<EM, H, HB, I, OT, S, Z> Executor<EM, I, S, Z> for GenericInProcessExecutor<H, HB, I, OT, S>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
|
HB: BorrowMut<H>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
@ -99,16 +112,17 @@ where
|
|||||||
self.handlers
|
self.handlers
|
||||||
.pre_run_target(self, fuzzer, state, mgr, input);
|
.pre_run_target(self, fuzzer, state, mgr, input);
|
||||||
|
|
||||||
let ret = (self.harness_fn)(input);
|
let ret = (self.harness_fn.borrow_mut())(input);
|
||||||
|
|
||||||
self.handlers.post_run_target();
|
self.handlers.post_run_target();
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H, I, OT, S> HasObservers<I, OT, S> for InProcessExecutor<'a, H, I, OT, S>
|
impl<H, HB, I, OT, S> HasObservers<I, OT, S> for GenericInProcessExecutor<H, HB, I, OT, S>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
|
HB: BorrowMut<H>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
@ -123,9 +137,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H, I, OT, S> InProcessExecutor<'a, H, I, OT, S>
|
impl<H, HB, I, OT, S> GenericInProcessExecutor<H, HB, I, OT, S>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
|
HB: BorrowMut<H>,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
@ -136,7 +151,7 @@ where
|
|||||||
/// * `observers` - the observers observing the target during execution
|
/// * `observers` - the observers observing the target during execution
|
||||||
/// This may return an error on unix, if signal handler setup fails
|
/// This may return an error on unix, if signal handler setup fails
|
||||||
pub fn new<EM, OF, Z>(
|
pub fn new<EM, OF, Z>(
|
||||||
harness_fn: &'a mut H,
|
harness_fn: HB,
|
||||||
observers: OT,
|
observers: OT,
|
||||||
_fuzzer: &mut Z,
|
_fuzzer: &mut Z,
|
||||||
_state: &mut S,
|
_state: &mut S,
|
||||||
@ -175,13 +190,13 @@ where
|
|||||||
/// Retrieve the harness function.
|
/// Retrieve the harness function.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn harness(&self) -> &H {
|
pub fn harness(&self) -> &H {
|
||||||
self.harness_fn
|
self.harness_fn.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the harness function for a mutable reference.
|
/// Retrieve the harness function for a mutable reference.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn harness_mut(&mut self) -> &mut H {
|
pub fn harness_mut(&mut self) -> &mut H {
|
||||||
self.harness_fn
|
self.harness_fn.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The inprocess handlers
|
/// The inprocess handlers
|
||||||
@ -305,7 +320,7 @@ impl InProcessHandlers {
|
|||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
S: HasSolutions<I> + HasClientPerfMonitor,
|
S: HasSolutions<I> + HasClientPerfMonitor,
|
||||||
Z: HasObjective<I, OF, S>,
|
Z: HasObjective<I, OF, S>,
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
{
|
{
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -1376,7 +1391,7 @@ impl Handler for InProcessForkExecutorGlobalData {
|
|||||||
#[cfg(all(feature = "std", unix))]
|
#[cfg(all(feature = "std", unix))]
|
||||||
pub struct InProcessForkExecutor<'a, H, I, OT, S, SP>
|
pub struct InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
@ -1391,7 +1406,7 @@ where
|
|||||||
#[cfg(all(feature = "std", unix))]
|
#[cfg(all(feature = "std", unix))]
|
||||||
impl<'a, H, I, OT, S, SP> Debug for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
impl<'a, H, I, OT, S, SP> Debug for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
@ -1408,7 +1423,7 @@ where
|
|||||||
impl<'a, EM, H, I, OT, S, SP, Z> Executor<EM, I, S, Z>
|
impl<'a, EM, H, I, OT, S, SP, Z> Executor<EM, I, S, Z>
|
||||||
for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
@ -1466,7 +1481,7 @@ where
|
|||||||
#[cfg(all(feature = "std", unix))]
|
#[cfg(all(feature = "std", unix))]
|
||||||
impl<'a, H, I, OT, S, SP> InProcessForkExecutor<'a, H, I, OT, S, SP>
|
impl<'a, H, I, OT, S, SP> InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
@ -1512,7 +1527,7 @@ where
|
|||||||
#[cfg(all(feature = "std", unix))]
|
#[cfg(all(feature = "std", unix))]
|
||||||
impl<'a, H, I, OT, S, SP> HasObservers<I, OT, S> for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
impl<'a, H, I, OT, S, SP> HasObservers<I, OT, S> for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
where
|
where
|
||||||
H: FnMut(&I) -> ExitKind,
|
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||||
I: Input,
|
I: Input,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
@ -1652,3 +1667,155 @@ mod tests {
|
|||||||
.is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `InProcess` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::bolts::tuples::tuple_list;
|
||||||
|
use crate::executors::{inprocess::OwnedInProcessExecutor, ExitKind};
|
||||||
|
use crate::inputs::{BytesInput, HasBytesVec};
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::types::PyBytes;
|
||||||
|
|
||||||
|
macro_rules! define_python_in_process_executor {
|
||||||
|
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $std_state_name: ident, $event_manager_name: ident, $map_observer_name: ident, $std_fuzzer_name: ident) => {
|
||||||
|
use crate::events::pybind::$event_manager_name;
|
||||||
|
use crate::fuzzer::pybind::$std_fuzzer_name;
|
||||||
|
use crate::observers::pybind::$map_observer_name;
|
||||||
|
use crate::state::pybind::{$my_std_state_type_name, $std_state_name};
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = $py_name)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Python class for OwnedInProcessExecutor (i.e. InProcessExecutor with owned harness)
|
||||||
|
pub struct $struct_name {
|
||||||
|
/// Rust wrapped OwnedInProcessExecutor object
|
||||||
|
pub owned_in_process_executor: OwnedInProcessExecutor<
|
||||||
|
BytesInput,
|
||||||
|
($map_observer_name, ()),
|
||||||
|
$my_std_state_type_name,
|
||||||
|
>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name {
|
||||||
|
#[new]
|
||||||
|
fn new(
|
||||||
|
harness: PyObject,
|
||||||
|
py_observer: $map_observer_name,
|
||||||
|
py_fuzzer: &mut $std_fuzzer_name,
|
||||||
|
py_state: &mut $std_state_name,
|
||||||
|
py_event_manager: &mut $event_manager_name,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
owned_in_process_executor: OwnedInProcessExecutor::new(
|
||||||
|
Box::new(move |input: &BytesInput| {
|
||||||
|
Python::with_gil(|py| -> PyResult<()> {
|
||||||
|
let args = (PyBytes::new(py, input.bytes()),);
|
||||||
|
harness.call1(py, args)?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
ExitKind::Ok
|
||||||
|
}),
|
||||||
|
tuple_list!(py_observer),
|
||||||
|
&mut py_fuzzer.std_fuzzer,
|
||||||
|
&mut py_state.std_state,
|
||||||
|
py_event_manager,
|
||||||
|
)
|
||||||
|
.expect("Failed to create the Executor".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_in_process_executor!(
|
||||||
|
PythonOwnedInProcessExecutorI8,
|
||||||
|
"OwnedInProcessExecutorI8",
|
||||||
|
MyStdStateI8,
|
||||||
|
PythonStdStateI8,
|
||||||
|
PythonEventManagerI8,
|
||||||
|
PythonMapObserverI8,
|
||||||
|
PythonStdFuzzerI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_in_process_executor!(
|
||||||
|
PythonOwnedInProcessExecutorI16,
|
||||||
|
"OwnedInProcessExecutorI16",
|
||||||
|
MyStdStateI16,
|
||||||
|
PythonStdStateI16,
|
||||||
|
PythonEventManagerI16,
|
||||||
|
PythonMapObserverI16,
|
||||||
|
PythonStdFuzzerI16
|
||||||
|
);
|
||||||
|
define_python_in_process_executor!(
|
||||||
|
PythonOwnedInProcessExecutorI32,
|
||||||
|
"OwnedInProcessExecutorI32",
|
||||||
|
MyStdStateI32,
|
||||||
|
PythonStdStateI32,
|
||||||
|
PythonEventManagerI32,
|
||||||
|
PythonMapObserverI32,
|
||||||
|
PythonStdFuzzerI32
|
||||||
|
);
|
||||||
|
define_python_in_process_executor!(
|
||||||
|
PythonOwnedInProcessExecutorI64,
|
||||||
|
"OwnedInProcessExecutorI64",
|
||||||
|
MyStdStateI64,
|
||||||
|
PythonStdStateI64,
|
||||||
|
PythonEventManagerI64,
|
||||||
|
PythonMapObserverI64,
|
||||||
|
PythonStdFuzzerI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_in_process_executor!(
|
||||||
|
PythonOwnedInProcessExecutorU8,
|
||||||
|
"OwnedInProcessExecutorU8",
|
||||||
|
MyStdStateU8,
|
||||||
|
PythonStdStateU8,
|
||||||
|
PythonEventManagerU8,
|
||||||
|
PythonMapObserverU8,
|
||||||
|
PythonStdFuzzerU8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_in_process_executor!(
|
||||||
|
PythonOwnedInProcessExecutorU16,
|
||||||
|
"OwnedInProcessExecutorU16",
|
||||||
|
MyStdStateU16,
|
||||||
|
PythonStdStateU16,
|
||||||
|
PythonEventManagerU16,
|
||||||
|
PythonMapObserverU16,
|
||||||
|
PythonStdFuzzerU16
|
||||||
|
);
|
||||||
|
define_python_in_process_executor!(
|
||||||
|
PythonOwnedInProcessExecutorU32,
|
||||||
|
"OwnedInProcessExecutorU32",
|
||||||
|
MyStdStateU32,
|
||||||
|
PythonStdStateU32,
|
||||||
|
PythonEventManagerU32,
|
||||||
|
PythonMapObserverU32,
|
||||||
|
PythonStdFuzzerU32
|
||||||
|
);
|
||||||
|
define_python_in_process_executor!(
|
||||||
|
PythonOwnedInProcessExecutorU64,
|
||||||
|
"OwnedInProcessExecutorU64",
|
||||||
|
MyStdStateU64,
|
||||||
|
PythonStdStateU64,
|
||||||
|
PythonEventManagerU64,
|
||||||
|
PythonMapObserverU64,
|
||||||
|
PythonStdFuzzerU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonOwnedInProcessExecutorI8>()?;
|
||||||
|
m.add_class::<PythonOwnedInProcessExecutorI16>()?;
|
||||||
|
m.add_class::<PythonOwnedInProcessExecutorI32>()?;
|
||||||
|
m.add_class::<PythonOwnedInProcessExecutorI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonOwnedInProcessExecutorU8>()?;
|
||||||
|
m.add_class::<PythonOwnedInProcessExecutorU16>()?;
|
||||||
|
m.add_class::<PythonOwnedInProcessExecutorU32>()?;
|
||||||
|
m.add_class::<PythonOwnedInProcessExecutorU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -184,3 +184,223 @@ mod test {
|
|||||||
.is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `Executor` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::executors::{Executor, ExitKind, HasObservers};
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use crate::Error;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! define_python_executor {
|
||||||
|
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident,
|
||||||
|
$event_manager_name: ident, $in_process_executor_name: ident, $map_observer_name: ident) => {
|
||||||
|
use crate::events::pybind::$event_manager_name;
|
||||||
|
use crate::executors::inprocess::pybind::$in_process_executor_name;
|
||||||
|
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
|
||||||
|
use crate::observers::map::pybind::$map_observer_name;
|
||||||
|
use crate::state::pybind::$my_std_state_type_name;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum $wrapper_name {
|
||||||
|
OwnedInProcess(*mut $in_process_executor_name),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = $py_name_trait)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Executor + HasObservers Trait binding
|
||||||
|
pub struct $struct_name_trait {
|
||||||
|
executor: $wrapper_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $struct_name_trait {
|
||||||
|
fn get_executor(
|
||||||
|
&self,
|
||||||
|
) -> &(impl Executor<
|
||||||
|
$event_manager_name,
|
||||||
|
BytesInput,
|
||||||
|
$my_std_state_type_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
> + HasObservers<BytesInput, ($map_observer_name, ()), $my_std_state_type_name>)
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
match self.executor {
|
||||||
|
$wrapper_name::OwnedInProcess(py_owned_inprocess_executor) => {
|
||||||
|
&(*py_owned_inprocess_executor).owned_in_process_executor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut_executor(
|
||||||
|
&mut self,
|
||||||
|
) -> &mut (impl Executor<
|
||||||
|
$event_manager_name,
|
||||||
|
BytesInput,
|
||||||
|
$my_std_state_type_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
> + HasObservers<
|
||||||
|
BytesInput,
|
||||||
|
($map_observer_name, ()),
|
||||||
|
$my_std_state_type_name,
|
||||||
|
>) {
|
||||||
|
unsafe {
|
||||||
|
match self.executor {
|
||||||
|
$wrapper_name::OwnedInProcess(py_owned_inprocess_executor) => {
|
||||||
|
&mut (*py_owned_inprocess_executor).owned_in_process_executor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name_trait {
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_inprocess(
|
||||||
|
owned_inprocess_executor: &mut $in_process_executor_name,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
executor: $wrapper_name::OwnedInProcess(owned_inprocess_executor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S> HasObservers<I, ($map_observer_name, ()), S> for $struct_name_trait {
|
||||||
|
// #[inline]
|
||||||
|
fn observers(&self) -> &($map_observer_name, ()) {
|
||||||
|
self.get_executor().observers()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn observers_mut(&mut self) -> &mut ($map_observer_name, ()) {
|
||||||
|
self.get_mut_executor().observers_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl
|
||||||
|
Executor<
|
||||||
|
$event_manager_name,
|
||||||
|
BytesInput,
|
||||||
|
$my_std_state_type_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
> for $struct_name_trait
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn run_target(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut $my_std_fuzzer_type_name,
|
||||||
|
state: &mut $my_std_state_type_name,
|
||||||
|
mgr: &mut $event_manager_name,
|
||||||
|
input: &BytesInput,
|
||||||
|
) -> Result<ExitKind, Error> {
|
||||||
|
self.get_mut_executor()
|
||||||
|
.run_target(fuzzer, state, mgr, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_executor!(
|
||||||
|
PythonExecutorI8,
|
||||||
|
"ExecutorI8",
|
||||||
|
PythonExecutorWrapperI8,
|
||||||
|
MyStdStateI8,
|
||||||
|
MyStdFuzzerI8,
|
||||||
|
PythonEventManagerI8,
|
||||||
|
PythonOwnedInProcessExecutorI8,
|
||||||
|
PythonMapObserverI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_executor!(
|
||||||
|
PythonExecutorI16,
|
||||||
|
"ExecutorI16",
|
||||||
|
PythonExecutorWrapperI16,
|
||||||
|
MyStdStateI16,
|
||||||
|
MyStdFuzzerI16,
|
||||||
|
PythonEventManagerI16,
|
||||||
|
PythonOwnedInProcessExecutorI16,
|
||||||
|
PythonMapObserverI16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_executor!(
|
||||||
|
PythonExecutorI32,
|
||||||
|
"ExecutorI32",
|
||||||
|
PythonExecutorWrapperI32,
|
||||||
|
MyStdStateI32,
|
||||||
|
MyStdFuzzerI32,
|
||||||
|
PythonEventManagerI32,
|
||||||
|
PythonOwnedInProcessExecutorI32,
|
||||||
|
PythonMapObserverI32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_executor!(
|
||||||
|
PythonExecutorI64,
|
||||||
|
"ExecutorI64",
|
||||||
|
PythonExecutorWrapperI64,
|
||||||
|
MyStdStateI64,
|
||||||
|
MyStdFuzzerI64,
|
||||||
|
PythonEventManagerI64,
|
||||||
|
PythonOwnedInProcessExecutorI64,
|
||||||
|
PythonMapObserverI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_executor!(
|
||||||
|
PythonExecutorU8,
|
||||||
|
"ExecutorU8",
|
||||||
|
PythonExecutorWrapperU8,
|
||||||
|
MyStdStateU8,
|
||||||
|
MyStdFuzzerU8,
|
||||||
|
PythonEventManagerU8,
|
||||||
|
PythonOwnedInProcessExecutorU8,
|
||||||
|
PythonMapObserverU8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_executor!(
|
||||||
|
PythonExecutorU16,
|
||||||
|
"ExecutorU16",
|
||||||
|
PythonExecutorWrapperU16,
|
||||||
|
MyStdStateU16,
|
||||||
|
MyStdFuzzerU16,
|
||||||
|
PythonEventManagerU16,
|
||||||
|
PythonOwnedInProcessExecutorU16,
|
||||||
|
PythonMapObserverU16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_executor!(
|
||||||
|
PythonExecutorU32,
|
||||||
|
"ExecutorU32",
|
||||||
|
PythonExecutorWrapperU32,
|
||||||
|
MyStdStateU32,
|
||||||
|
MyStdFuzzerU32,
|
||||||
|
PythonEventManagerU32,
|
||||||
|
PythonOwnedInProcessExecutorU32,
|
||||||
|
PythonMapObserverU32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_executor!(
|
||||||
|
PythonExecutorU64,
|
||||||
|
"ExecutorU64",
|
||||||
|
PythonExecutorWrapperU64,
|
||||||
|
MyStdStateU64,
|
||||||
|
MyStdFuzzerU64,
|
||||||
|
PythonEventManagerU64,
|
||||||
|
PythonOwnedInProcessExecutorU64,
|
||||||
|
PythonMapObserverU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonExecutorI8>()?;
|
||||||
|
m.add_class::<PythonExecutorI16>()?;
|
||||||
|
m.add_class::<PythonExecutorI32>()?;
|
||||||
|
m.add_class::<PythonExecutorI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonExecutorU8>()?;
|
||||||
|
m.add_class::<PythonExecutorU16>()?;
|
||||||
|
m.add_class::<PythonExecutorU32>()?;
|
||||||
|
m.add_class::<PythonExecutorU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -654,7 +654,6 @@ where
|
|||||||
self.name.as_str()
|
self.name.as_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::feedbacks::{AllIsNovel, IsNovel, NextPow2IsNovel};
|
use crate::feedbacks::{AllIsNovel, IsNovel, NextPow2IsNovel};
|
||||||
@ -679,3 +678,162 @@ mod tests {
|
|||||||
assert!(!NextPow2IsNovel::is_novel(255_u8, 255));
|
assert!(!NextPow2IsNovel::is_novel(255_u8, 255));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// Map Feedback Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::feedbacks::map::{MapFeedbackState, MaxMapFeedback};
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! define_python_map_feedback {
|
||||||
|
($map_feedback_state_struct_name:ident, $map_feedback_state_py_name:tt, $max_map_feedback_struct_name:ident,
|
||||||
|
$max_map_feedback_py_name:tt, $datatype:ty, $map_observer_name: ident, $std_state_name: ident) => {
|
||||||
|
use crate::observers::map::pybind::$map_observer_name;
|
||||||
|
use crate::state::pybind::$std_state_name;
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = $map_feedback_state_py_name)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
/// Python class for MapFeedbackState
|
||||||
|
pub struct $map_feedback_state_struct_name {
|
||||||
|
/// Rust wrapped MapFeedbackState object
|
||||||
|
pub map_feedback_state: MapFeedbackState<$datatype>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $map_feedback_state_struct_name {
|
||||||
|
#[staticmethod]
|
||||||
|
fn with_observer(py_observer: &$map_observer_name) -> Self {
|
||||||
|
Self {
|
||||||
|
map_feedback_state: MapFeedbackState::with_observer(py_observer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = $max_map_feedback_py_name)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
/// Python class for MaxMapFeedback
|
||||||
|
pub struct $max_map_feedback_struct_name {
|
||||||
|
/// Rust wrapped MaxMapFeedback object
|
||||||
|
pub max_map_feedback:
|
||||||
|
MaxMapFeedback<BytesInput, $map_observer_name, $std_state_name, $datatype>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $max_map_feedback_struct_name {
|
||||||
|
#[new]
|
||||||
|
fn new(
|
||||||
|
py_feedback_state: &$map_feedback_state_struct_name,
|
||||||
|
py_observer: &$map_observer_name,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
max_map_feedback: MaxMapFeedback::new(
|
||||||
|
&py_feedback_state.map_feedback_state,
|
||||||
|
py_observer,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_map_feedback!(
|
||||||
|
PythonMapFeedbackStateI8,
|
||||||
|
"MapFeedbackStateI8",
|
||||||
|
PythonMaxMapFeedbackI8,
|
||||||
|
"MaxMapFeedbackI8",
|
||||||
|
i8,
|
||||||
|
PythonMapObserverI8,
|
||||||
|
MyStdStateI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_map_feedback!(
|
||||||
|
PythonMapFeedbackStateI16,
|
||||||
|
"MapFeedbackStateI16",
|
||||||
|
PythonMaxMapFeedbackI16,
|
||||||
|
"MaxMapFeedbackI16",
|
||||||
|
i16,
|
||||||
|
PythonMapObserverI16,
|
||||||
|
MyStdStateI16
|
||||||
|
);
|
||||||
|
define_python_map_feedback!(
|
||||||
|
PythonMapFeedbackStateI32,
|
||||||
|
"MapFeedbackStateI32",
|
||||||
|
PythonMaxMapFeedbackI32,
|
||||||
|
"MaxMapFeedbackI32",
|
||||||
|
i32,
|
||||||
|
PythonMapObserverI32,
|
||||||
|
MyStdStateI32
|
||||||
|
);
|
||||||
|
define_python_map_feedback!(
|
||||||
|
PythonMapFeedbackStateI64,
|
||||||
|
"MapFeedbackStateI64",
|
||||||
|
PythonMaxMapFeedbackI64,
|
||||||
|
"MaxMapFeedbackI64",
|
||||||
|
i64,
|
||||||
|
PythonMapObserverI64,
|
||||||
|
MyStdStateI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_map_feedback!(
|
||||||
|
PythonMapFeedbackStateU8,
|
||||||
|
"MapFeedbackStateU8",
|
||||||
|
PythonMaxMapFeedbackU8,
|
||||||
|
"MaxMapFeedbackU8",
|
||||||
|
u8,
|
||||||
|
PythonMapObserverU8,
|
||||||
|
MyStdStateU8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_map_feedback!(
|
||||||
|
PythonMapFeedbackStateU16,
|
||||||
|
"MapFeedbackStateU16",
|
||||||
|
PythonMaxMapFeedbackU16,
|
||||||
|
"MaxMapFeedbackU16",
|
||||||
|
u16,
|
||||||
|
PythonMapObserverU16,
|
||||||
|
MyStdStateU16
|
||||||
|
);
|
||||||
|
define_python_map_feedback!(
|
||||||
|
PythonMapFeedbackStateU32,
|
||||||
|
"MapFeedbackStateU32",
|
||||||
|
PythonMaxMapFeedbackU32,
|
||||||
|
"MaxMapFeedbackU32",
|
||||||
|
u32,
|
||||||
|
PythonMapObserverU32,
|
||||||
|
MyStdStateU32
|
||||||
|
);
|
||||||
|
define_python_map_feedback!(
|
||||||
|
PythonMapFeedbackStateU64,
|
||||||
|
"MapFeedbackStateU64",
|
||||||
|
PythonMaxMapFeedbackU64,
|
||||||
|
"MaxMapFeedbackU64",
|
||||||
|
u64,
|
||||||
|
PythonMapObserverU64,
|
||||||
|
MyStdStateU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonMapFeedbackStateI8>()?;
|
||||||
|
m.add_class::<PythonMapFeedbackStateI16>()?;
|
||||||
|
m.add_class::<PythonMapFeedbackStateI32>()?;
|
||||||
|
m.add_class::<PythonMapFeedbackStateI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonMapFeedbackStateU8>()?;
|
||||||
|
m.add_class::<PythonMapFeedbackStateU16>()?;
|
||||||
|
m.add_class::<PythonMapFeedbackStateU32>()?;
|
||||||
|
m.add_class::<PythonMapFeedbackStateU64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonMaxMapFeedbackI8>()?;
|
||||||
|
m.add_class::<PythonMaxMapFeedbackI16>()?;
|
||||||
|
m.add_class::<PythonMaxMapFeedbackI32>()?;
|
||||||
|
m.add_class::<PythonMaxMapFeedbackI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonMaxMapFeedbackU8>()?;
|
||||||
|
m.add_class::<PythonMaxMapFeedbackU16>()?;
|
||||||
|
m.add_class::<PythonMaxMapFeedbackU32>()?;
|
||||||
|
m.add_class::<PythonMaxMapFeedbackU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -666,3 +666,199 @@ where
|
|||||||
Ok(exit_kind)
|
Ok(exit_kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `Fuzzer` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::corpus::QueueCorpusScheduler;
|
||||||
|
use crate::feedbacks::{CrashFeedback, MaxMapFeedback};
|
||||||
|
use crate::fuzzer::{Fuzzer, StdFuzzer};
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! define_python_fuzzer {
|
||||||
|
($type_name:ident, $struct_name:ident, $py_name:tt, $datatype:ty, $my_std_state_type_name: ident, $std_state_name: ident,
|
||||||
|
$event_manager_name: ident, $map_observer_name: ident, $max_map_feedback_py_name: ident, $executor_name: ident, $stage_tuple_name: ident) => {
|
||||||
|
use crate::events::pybind::$event_manager_name;
|
||||||
|
use crate::executors::pybind::$executor_name;
|
||||||
|
use crate::feedbacks::map::pybind::$max_map_feedback_py_name;
|
||||||
|
use crate::observers::map::pybind::$map_observer_name;
|
||||||
|
use crate::stages::owned::pybind::$stage_tuple_name;
|
||||||
|
use crate::state::pybind::{$my_std_state_type_name, $std_state_name};
|
||||||
|
|
||||||
|
/// `StdFuzzer` with fixed generics
|
||||||
|
pub type $type_name = StdFuzzer<
|
||||||
|
QueueCorpusScheduler,
|
||||||
|
MaxMapFeedback<BytesInput, $map_observer_name, $my_std_state_type_name, $datatype>,
|
||||||
|
BytesInput,
|
||||||
|
CrashFeedback,
|
||||||
|
($map_observer_name, ()),
|
||||||
|
$my_std_state_type_name,
|
||||||
|
>;
|
||||||
|
/// Python class for StdFuzzer
|
||||||
|
#[pyclass(unsendable, name = $py_name)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct $struct_name {
|
||||||
|
/// Rust wrapped StdFuzzer object
|
||||||
|
pub std_fuzzer: $type_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name {
|
||||||
|
#[new]
|
||||||
|
fn new(py_max_map_feedback: $max_map_feedback_py_name) -> Self {
|
||||||
|
Self {
|
||||||
|
std_fuzzer: StdFuzzer::new(
|
||||||
|
QueueCorpusScheduler::new(),
|
||||||
|
py_max_map_feedback.max_map_feedback,
|
||||||
|
CrashFeedback::new(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fuzz_loop(
|
||||||
|
&mut self,
|
||||||
|
py_executor: &mut $executor_name,
|
||||||
|
py_state: &mut $std_state_name,
|
||||||
|
py_mgr: &mut $event_manager_name,
|
||||||
|
stage_tuple: &mut $stage_tuple_name,
|
||||||
|
) {
|
||||||
|
self.std_fuzzer
|
||||||
|
.fuzz_loop(
|
||||||
|
&mut stage_tuple.stages_owned_list,
|
||||||
|
py_executor,
|
||||||
|
&mut py_state.std_state,
|
||||||
|
py_mgr,
|
||||||
|
)
|
||||||
|
.expect("Failed to generate the initial corpus".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_fuzzer!(
|
||||||
|
MyStdFuzzerI8,
|
||||||
|
PythonStdFuzzerI8,
|
||||||
|
"StdFuzzerI8",
|
||||||
|
i8,
|
||||||
|
MyStdStateI8,
|
||||||
|
PythonStdStateI8,
|
||||||
|
PythonEventManagerI8,
|
||||||
|
PythonMapObserverI8,
|
||||||
|
PythonMaxMapFeedbackI8,
|
||||||
|
PythonExecutorI8,
|
||||||
|
PythonStagesOwnedListI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_fuzzer!(
|
||||||
|
MyStdFuzzerI16,
|
||||||
|
PythonStdFuzzerI16,
|
||||||
|
"StdFuzzerI16",
|
||||||
|
i16,
|
||||||
|
MyStdStateI16,
|
||||||
|
PythonStdStateI16,
|
||||||
|
PythonEventManagerI16,
|
||||||
|
PythonMapObserverI16,
|
||||||
|
PythonMaxMapFeedbackI16,
|
||||||
|
PythonExecutorI16,
|
||||||
|
PythonStagesOwnedListI16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_fuzzer!(
|
||||||
|
MyStdFuzzerI32,
|
||||||
|
PythonStdFuzzerI32,
|
||||||
|
"StdFuzzerI32",
|
||||||
|
i32,
|
||||||
|
MyStdStateI32,
|
||||||
|
PythonStdStateI32,
|
||||||
|
PythonEventManagerI32,
|
||||||
|
PythonMapObserverI32,
|
||||||
|
PythonMaxMapFeedbackI32,
|
||||||
|
PythonExecutorI32,
|
||||||
|
PythonStagesOwnedListI32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_fuzzer!(
|
||||||
|
MyStdFuzzerI64,
|
||||||
|
PythonStdFuzzerI64,
|
||||||
|
"StdFuzzerI64",
|
||||||
|
i64,
|
||||||
|
MyStdStateI64,
|
||||||
|
PythonStdStateI64,
|
||||||
|
PythonEventManagerI64,
|
||||||
|
PythonMapObserverI64,
|
||||||
|
PythonMaxMapFeedbackI64,
|
||||||
|
PythonExecutorI64,
|
||||||
|
PythonStagesOwnedListI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_fuzzer!(
|
||||||
|
MyStdFuzzerU8,
|
||||||
|
PythonStdFuzzerU8,
|
||||||
|
"StdFuzzerU8",
|
||||||
|
u8,
|
||||||
|
MyStdStateU8,
|
||||||
|
PythonStdStateU8,
|
||||||
|
PythonEventManagerU8,
|
||||||
|
PythonMapObserverU8,
|
||||||
|
PythonMaxMapFeedbackU8,
|
||||||
|
PythonExecutorU8,
|
||||||
|
PythonStagesOwnedListU8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_fuzzer!(
|
||||||
|
MyStdFuzzerU16,
|
||||||
|
PythonStdFuzzerU16,
|
||||||
|
"StdFuzzerU16",
|
||||||
|
u16,
|
||||||
|
MyStdStateU16,
|
||||||
|
PythonStdStateU16,
|
||||||
|
PythonEventManagerU16,
|
||||||
|
PythonMapObserverU16,
|
||||||
|
PythonMaxMapFeedbackU16,
|
||||||
|
PythonExecutorU16,
|
||||||
|
PythonStagesOwnedListU16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_fuzzer!(
|
||||||
|
MyStdFuzzerU32,
|
||||||
|
PythonStdFuzzerU32,
|
||||||
|
"StdFuzzerU32",
|
||||||
|
u32,
|
||||||
|
MyStdStateU32,
|
||||||
|
PythonStdStateU32,
|
||||||
|
PythonEventManagerU32,
|
||||||
|
PythonMapObserverU32,
|
||||||
|
PythonMaxMapFeedbackU32,
|
||||||
|
PythonExecutorU32,
|
||||||
|
PythonStagesOwnedListU32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_fuzzer!(
|
||||||
|
MyStdFuzzerU64,
|
||||||
|
PythonStdFuzzerU64,
|
||||||
|
"StdFuzzerU64",
|
||||||
|
u64,
|
||||||
|
MyStdStateU64,
|
||||||
|
PythonStdStateU64,
|
||||||
|
PythonEventManagerU64,
|
||||||
|
PythonMapObserverU64,
|
||||||
|
PythonMaxMapFeedbackU64,
|
||||||
|
PythonExecutorU64,
|
||||||
|
PythonStagesOwnedListU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonStdFuzzerI8>()?;
|
||||||
|
m.add_class::<PythonStdFuzzerI16>()?;
|
||||||
|
m.add_class::<PythonStdFuzzerI32>()?;
|
||||||
|
m.add_class::<PythonStdFuzzerI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonStdFuzzerU8>()?;
|
||||||
|
m.add_class::<PythonStdFuzzerU16>()?;
|
||||||
|
m.add_class::<PythonStdFuzzerU32>()?;
|
||||||
|
m.add_class::<PythonStdFuzzerU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -125,3 +125,90 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `Generator` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::generators::RandPrintablesGenerator;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! define_python_event_manager {
|
||||||
|
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident) => {
|
||||||
|
use crate::state::pybind::$my_std_state_type_name;
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = $py_name)]
|
||||||
|
/// Python class for RandPrintablesGenerator
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct $struct_name {
|
||||||
|
/// Rust wrapped SimpleEventManager object
|
||||||
|
pub rand_printable_generator: RandPrintablesGenerator<$my_std_state_type_name>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name {
|
||||||
|
#[new]
|
||||||
|
fn new(max_size: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
rand_printable_generator: RandPrintablesGenerator::new(max_size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonRandPrintablesGeneratorI8,
|
||||||
|
"RandPrintablesGeneratorI8",
|
||||||
|
MyStdStateI8
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonRandPrintablesGeneratorI16,
|
||||||
|
"RandPrintablesGeneratorI16",
|
||||||
|
MyStdStateI16
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonRandPrintablesGeneratorI32,
|
||||||
|
"RandPrintablesGeneratorI32",
|
||||||
|
MyStdStateI32
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonRandPrintablesGeneratorI64,
|
||||||
|
"RandPrintablesGeneratorI64",
|
||||||
|
MyStdStateI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonRandPrintablesGeneratorU8,
|
||||||
|
"RandPrintablesGeneratorU8",
|
||||||
|
MyStdStateU8
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonRandPrintablesGeneratorU16,
|
||||||
|
"RandPrintablesGeneratorU16",
|
||||||
|
MyStdStateU16
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonRandPrintablesGeneratorU32,
|
||||||
|
"RandPrintablesGeneratorU32",
|
||||||
|
MyStdStateU32
|
||||||
|
);
|
||||||
|
define_python_event_manager!(
|
||||||
|
PythonRandPrintablesGeneratorU64,
|
||||||
|
"RandPrintablesGeneratorU64",
|
||||||
|
MyStdStateU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonRandPrintablesGeneratorI8>()?;
|
||||||
|
m.add_class::<PythonRandPrintablesGeneratorI16>()?;
|
||||||
|
m.add_class::<PythonRandPrintablesGeneratorI32>()?;
|
||||||
|
m.add_class::<PythonRandPrintablesGeneratorI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonRandPrintablesGeneratorU8>()?;
|
||||||
|
m.add_class::<PythonRandPrintablesGeneratorU16>()?;
|
||||||
|
m.add_class::<PythonRandPrintablesGeneratorU32>()?;
|
||||||
|
m.add_class::<PythonRandPrintablesGeneratorU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -314,3 +314,32 @@ pub extern "C" fn external_current_millis() -> u64 {
|
|||||||
// TODO: use "real" time here
|
// TODO: use "real" time here
|
||||||
1000
|
1000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
#[pymodule]
|
||||||
|
#[pyo3(name = "libafl")]
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
observers::map::pybind::register(py, m)?;
|
||||||
|
feedbacks::map::pybind::register(py, m)?;
|
||||||
|
state::pybind::register(py, m)?;
|
||||||
|
monitors::pybind::register(py, m)?;
|
||||||
|
events::pybind::register(py, m)?;
|
||||||
|
events::simple::pybind::register(py, m)?;
|
||||||
|
fuzzer::pybind::register(py, m)?;
|
||||||
|
executors::pybind::register(py, m)?;
|
||||||
|
executors::inprocess::pybind::register(py, m)?;
|
||||||
|
generators::pybind::register(py, m)?;
|
||||||
|
corpus::pybind::register(py, m)?;
|
||||||
|
corpus::ondisk::pybind::register(py, m)?;
|
||||||
|
corpus::inmemory::pybind::register(py, m)?;
|
||||||
|
corpus::cached::pybind::register(py, m)?;
|
||||||
|
bolts::rands::pybind::register(py, m)?;
|
||||||
|
stages::pybind::register(py, m)?;
|
||||||
|
stages::owned::pybind::register(py, m)?;
|
||||||
|
stages::mutational::pybind::register(py, m)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -784,3 +784,104 @@ impl Default for ClientPerfMonitor {
|
|||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// `Monitor` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::monitors::{Monitor, SimpleMonitor};
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
use super::ClientStats;
|
||||||
|
use core::time::Duration;
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = "SimpleMonitor")]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
/// Python class for SimpleMonitor
|
||||||
|
pub struct PythonSimpleMonitor {
|
||||||
|
/// Rust wrapped SimpleMonitor object
|
||||||
|
pub simple_monitor: SimpleMonitor<fn(String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonSimpleMonitor {
|
||||||
|
#[new]
|
||||||
|
fn new(/*py_print_fn: PyObject */) -> Self {
|
||||||
|
// TODO: Find a fix to: closures can only be coerced to `fn` types if they
|
||||||
|
// do not capture any variables and print_fn expected to be fn pointer.
|
||||||
|
// fn printf_fn (s: String){
|
||||||
|
// Python::with_gil(|py| -> PyResult<()> {
|
||||||
|
// print_fn.call1(py, (PyUnicode::new(py, &s),));
|
||||||
|
// Ok(())
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
Self {
|
||||||
|
simple_monitor: SimpleMonitor::new(|s| println!("{}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum PythonMonitorWrapper {
|
||||||
|
Simple(PythonSimpleMonitor),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = "Monitor")]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
/// EventManager Trait binding
|
||||||
|
pub struct PythonMonitor {
|
||||||
|
monitor: PythonMonitorWrapper,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PythonMonitor {
|
||||||
|
fn get_monitor(&self) -> &impl Monitor {
|
||||||
|
match &self.monitor {
|
||||||
|
PythonMonitorWrapper::Simple(py_simple_monitor) => {
|
||||||
|
&py_simple_monitor.simple_monitor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut_monitor(&mut self) -> &mut impl Monitor {
|
||||||
|
match &mut self.monitor {
|
||||||
|
PythonMonitorWrapper::Simple(py_simple_monitor) => {
|
||||||
|
&mut py_simple_monitor.simple_monitor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PythonMonitor {
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_simple(simple_monitor: PythonSimpleMonitor) -> Self {
|
||||||
|
Self {
|
||||||
|
monitor: PythonMonitorWrapper::Simple(simple_monitor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monitor for PythonMonitor {
|
||||||
|
fn client_stats_mut(&mut self) -> &mut Vec<ClientStats> {
|
||||||
|
self.get_mut_monitor().client_stats_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_stats(&self) -> &[ClientStats] {
|
||||||
|
self.get_monitor().client_stats()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Time this fuzzing run stated
|
||||||
|
fn start_time(&mut self) -> Duration {
|
||||||
|
self.get_mut_monitor().start_time()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(&mut self, event_msg: String, sender_id: u32) {
|
||||||
|
self.get_mut_monitor().display(event_msg, sender_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonSimpleMonitor>()?;
|
||||||
|
m.add_class::<PythonMonitor>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -769,7 +769,6 @@ where
|
|||||||
Self { base }
|
Self { base }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Multi Map Observer merge different maps into one observer
|
/// The Multi Map Observer merge different maps into one observer
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||||
@ -977,3 +976,408 @@ where
|
|||||||
self.maps.iter().flatten()
|
self.maps.iter().flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Exact copy of `StdMapObserver` that owns its map
|
||||||
|
/// Used for python bindings
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||||
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
|
pub struct OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
map: Vec<T>,
|
||||||
|
initial: T,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S, T> Observer<I, S> for OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
|
Self: MapObserver,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
||||||
|
self.reset_map()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Named for OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> HasLen for OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.map.as_slice().len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'it, T> IntoIterator for &'it OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
|
{
|
||||||
|
type Item = <Iter<'it, T> as Iterator>::Item;
|
||||||
|
type IntoIter = Iter<'it, T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.as_slice().iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'it, T> IntoIterator for &'it mut OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
|
{
|
||||||
|
type Item = <IterMut<'it, T> as Iterator>::Item;
|
||||||
|
type IntoIter = IterMut<'it, T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.as_mut_slice().iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MapObserver for OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
|
{
|
||||||
|
type Entry = T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get(&self, pos: usize) -> &T {
|
||||||
|
&self.as_slice()[pos]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_mut(&mut self, idx: usize) -> &mut T {
|
||||||
|
&mut self.as_mut_slice()[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn usable_count(&self) -> usize {
|
||||||
|
self.as_slice().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash(&self) -> u64 {
|
||||||
|
hash_slice(self.as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn initial(&self) -> T {
|
||||||
|
self.initial
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn initial_mut(&mut self) -> &mut T {
|
||||||
|
&mut self.initial
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_initial(&mut self, initial: T) {
|
||||||
|
self.initial = initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_vec(&self) -> Vec<T> {
|
||||||
|
self.as_slice().to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AsSlice<T> for OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
|
{
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
fn as_slice(&self) -> &[T] {
|
||||||
|
self.map.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> AsMutSlice<T> for OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
|
||||||
|
{
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
fn as_mut_slice(&mut self) -> &mut [T] {
|
||||||
|
self.map.as_mut_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> OwnedMapObserver<T>
|
||||||
|
where
|
||||||
|
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
/// Creates a new [`MapObserver`] with an owned map
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(name: &'static str, map: Vec<T>) -> Self {
|
||||||
|
let initial = if map.is_empty() { T::default() } else { map[0] };
|
||||||
|
Self {
|
||||||
|
map: map,
|
||||||
|
name: name.to_string(),
|
||||||
|
initial,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// `MapObserver` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::bolts::{tuples::Named, HasLen};
|
||||||
|
use crate::observers::{map::OwnedMapObserver, MapObserver, Observer};
|
||||||
|
use crate::Error;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
macro_rules! define_python_map_observer {
|
||||||
|
($struct_name:ident, $py_name:tt, $struct_name_trait:ident, $py_name_trait:tt, $datatype:ty, $wrapper_name: ident) => {
|
||||||
|
#[pyclass(unsendable, name = $py_name)]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
/// Python class for OwnedMapObserver (i.e. StdMapObserver with owned map)
|
||||||
|
pub struct $struct_name {
|
||||||
|
/// Rust wrapped OwnedMapObserver object
|
||||||
|
pub owned_map_observer: OwnedMapObserver<$datatype>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name {
|
||||||
|
#[new]
|
||||||
|
fn new(name: String, map: Vec<$datatype>) -> Self {
|
||||||
|
Self {
|
||||||
|
//TODO: Not leak memory
|
||||||
|
owned_map_observer: OwnedMapObserver::new(
|
||||||
|
Box::leak(name.into_boxed_str()),
|
||||||
|
map,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
enum $wrapper_name {
|
||||||
|
Owned($struct_name),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not be exposed to user
|
||||||
|
#[pyclass(unsendable, name = $py_name_trait)]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
/// MapObserver + Observer Trait binding
|
||||||
|
pub struct $struct_name_trait {
|
||||||
|
map_observer: $wrapper_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name_trait {
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_owned(owned_map_observer: $struct_name) -> Self {
|
||||||
|
Self {
|
||||||
|
map_observer: $wrapper_name::Owned(owned_map_observer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapObserver for $struct_name_trait {
|
||||||
|
type Entry = $datatype;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get(&self, idx: usize) -> &$datatype {
|
||||||
|
match &self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
&map_observer.owned_map_observer.get(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_mut(&mut self, idx: usize) -> &mut $datatype {
|
||||||
|
match &mut self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.get_mut(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn usable_count(&self) -> usize {
|
||||||
|
match &self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.usable_count()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash(&self) -> u64 {
|
||||||
|
match &self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.hash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn initial(&self) -> $datatype {
|
||||||
|
match &self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.initial()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn initial_mut(&mut self) -> &mut $datatype {
|
||||||
|
match &mut self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.initial_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_initial(&mut self, initial: $datatype) {
|
||||||
|
match &mut self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.set_initial(initial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_vec(&self) -> Vec<$datatype> {
|
||||||
|
match &self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for $struct_name_trait {
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
match &self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasLen for $struct_name_trait {
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
match &self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => map_observer.owned_map_observer.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S> Observer<I, S> for $struct_name_trait
|
||||||
|
where
|
||||||
|
Self: MapObserver,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
||||||
|
match &mut self.map_observer {
|
||||||
|
$wrapper_name::Owned(map_observer) => {
|
||||||
|
map_observer.owned_map_observer.pre_exec(_state, _input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_map_observer!(
|
||||||
|
PythonOwnedMapObserverI8,
|
||||||
|
"OwnedMapObserverI8",
|
||||||
|
PythonMapObserverI8,
|
||||||
|
"MapObserverI8",
|
||||||
|
i8,
|
||||||
|
PythonMapObserverWrapperI8
|
||||||
|
);
|
||||||
|
define_python_map_observer!(
|
||||||
|
PythonOwnedMapObserverI16,
|
||||||
|
"OwnedMapObserverI16",
|
||||||
|
PythonMapObserverI16,
|
||||||
|
"MapObserverI16",
|
||||||
|
i16,
|
||||||
|
PythonMapObserverWrapperI16
|
||||||
|
);
|
||||||
|
define_python_map_observer!(
|
||||||
|
PythonOwnedMapObserverI32,
|
||||||
|
"OwnedMapObserverI32",
|
||||||
|
PythonMapObserverI32,
|
||||||
|
"MapObserverI32",
|
||||||
|
i32,
|
||||||
|
PythonMapObserverWrapperI32
|
||||||
|
);
|
||||||
|
define_python_map_observer!(
|
||||||
|
PythonOwnedMapObserverI64,
|
||||||
|
"OwnedMapObserverI64",
|
||||||
|
PythonMapObserverI64,
|
||||||
|
"MapObserverI64",
|
||||||
|
i64,
|
||||||
|
PythonMapObserverWrapperI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_map_observer!(
|
||||||
|
PythonOwnedMapObserverU8,
|
||||||
|
"OwnedMapObserverU8",
|
||||||
|
PythonMapObserverU8,
|
||||||
|
"MapObserverU8",
|
||||||
|
u8,
|
||||||
|
PythonMapObserverWrapperU8
|
||||||
|
);
|
||||||
|
define_python_map_observer!(
|
||||||
|
PythonOwnedMapObserverU16,
|
||||||
|
"OwnedMapObserverU16",
|
||||||
|
PythonMapObserverU16,
|
||||||
|
"MapObserverU16",
|
||||||
|
u16,
|
||||||
|
PythonMapObserverWrapperU16
|
||||||
|
);
|
||||||
|
define_python_map_observer!(
|
||||||
|
PythonOwnedMapObserverU32,
|
||||||
|
"OwnedMapObserverU32",
|
||||||
|
PythonMapObserverU32,
|
||||||
|
"MapObserverU32",
|
||||||
|
u32,
|
||||||
|
PythonMapObserverWrapperU32
|
||||||
|
);
|
||||||
|
define_python_map_observer!(
|
||||||
|
PythonOwnedMapObserverU64,
|
||||||
|
"OwnedMapObserverU64",
|
||||||
|
PythonMapObserverU64,
|
||||||
|
"MapObserverU64",
|
||||||
|
u64,
|
||||||
|
PythonMapObserverWrapperU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonOwnedMapObserverI8>()?;
|
||||||
|
m.add_class::<PythonMapObserverI8>()?;
|
||||||
|
m.add_class::<PythonOwnedMapObserverI16>()?;
|
||||||
|
m.add_class::<PythonMapObserverI16>()?;
|
||||||
|
m.add_class::<PythonOwnedMapObserverI32>()?;
|
||||||
|
m.add_class::<PythonMapObserverI32>()?;
|
||||||
|
m.add_class::<PythonOwnedMapObserverI64>()?;
|
||||||
|
m.add_class::<PythonMapObserverI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonOwnedMapObserverU8>()?;
|
||||||
|
m.add_class::<PythonMapObserverU8>()?;
|
||||||
|
m.add_class::<PythonOwnedMapObserverU16>()?;
|
||||||
|
m.add_class::<PythonMapObserverU16>()?;
|
||||||
|
m.add_class::<PythonOwnedMapObserverU32>()?;
|
||||||
|
m.add_class::<PythonMapObserverU32>()?;
|
||||||
|
m.add_class::<PythonOwnedMapObserverU64>()?;
|
||||||
|
m.add_class::<PythonMapObserverU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -256,3 +256,190 @@ where
|
|||||||
.deinit(fuzzer, state, event_mgr, executor.observers_mut())
|
.deinit(fuzzer, state, event_mgr, executor.observers_mut())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `Stage` Python bindings
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::impl_asany;
|
||||||
|
use crate::stages::Stage;
|
||||||
|
use crate::Error;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
use super::owned::AnyStage;
|
||||||
|
|
||||||
|
macro_rules! define_python_stage {
|
||||||
|
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $std_havoc_mutations_stage_name: ident, $my_std_state_type_name: ident,
|
||||||
|
$my_std_fuzzer_type_name: ident, $executor_name: ident, $event_manager_name: ident) => {
|
||||||
|
use crate::events::pybind::$event_manager_name;
|
||||||
|
use crate::executors::pybind::$executor_name;
|
||||||
|
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
|
||||||
|
use crate::stages::mutational::pybind::$std_havoc_mutations_stage_name;
|
||||||
|
use crate::state::pybind::$my_std_state_type_name;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum $wrapper_name {
|
||||||
|
StdHavocMutations(*mut $std_havoc_mutations_stage_name),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stage Trait binding
|
||||||
|
#[pyclass(unsendable, name = $py_name_trait)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct $struct_name_trait {
|
||||||
|
stage: $wrapper_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name_trait {
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_std_scheduled(
|
||||||
|
py_std_havoc_mutations_stage: &mut $std_havoc_mutations_stage_name,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
stage: $wrapper_name::StdHavocMutations(py_std_havoc_mutations_stage),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl
|
||||||
|
Stage<
|
||||||
|
$executor_name,
|
||||||
|
$event_manager_name,
|
||||||
|
$my_std_state_type_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
> for $struct_name_trait
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::let_and_return)]
|
||||||
|
fn perform(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut $my_std_fuzzer_type_name,
|
||||||
|
executor: &mut $executor_name,
|
||||||
|
state: &mut $my_std_state_type_name,
|
||||||
|
manager: &mut $event_manager_name,
|
||||||
|
corpus_idx: usize,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
match self.stage {
|
||||||
|
$wrapper_name::StdHavocMutations(py_std_havoc_mutations_stage) => {
|
||||||
|
(*py_std_havoc_mutations_stage)
|
||||||
|
.std_mutational_stage
|
||||||
|
.perform(fuzzer, executor, state, manager, corpus_idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_asany!($struct_name_trait);
|
||||||
|
|
||||||
|
impl
|
||||||
|
AnyStage<
|
||||||
|
$executor_name,
|
||||||
|
$event_manager_name,
|
||||||
|
$my_std_state_type_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
> for $struct_name_trait
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_stage!(
|
||||||
|
PythonStageI8,
|
||||||
|
"StageI8",
|
||||||
|
PythonStageWrapperI8,
|
||||||
|
PythonStdScheduledHavocMutationsStageI8,
|
||||||
|
MyStdStateI8,
|
||||||
|
MyStdFuzzerI8,
|
||||||
|
PythonExecutorI8,
|
||||||
|
PythonEventManagerI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage!(
|
||||||
|
PythonStageI16,
|
||||||
|
"StageI16",
|
||||||
|
PythonStageWrapperI16,
|
||||||
|
PythonStdScheduledHavocMutationsStageI16,
|
||||||
|
MyStdStateI16,
|
||||||
|
MyStdFuzzerI16,
|
||||||
|
PythonExecutorI16,
|
||||||
|
PythonEventManagerI16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage!(
|
||||||
|
PythonStageI32,
|
||||||
|
"StageI32",
|
||||||
|
PythonStageWrapperI32,
|
||||||
|
PythonStdScheduledHavocMutationsStageI32,
|
||||||
|
MyStdStateI32,
|
||||||
|
MyStdFuzzerI32,
|
||||||
|
PythonExecutorI32,
|
||||||
|
PythonEventManagerI32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage!(
|
||||||
|
PythonStageI64,
|
||||||
|
"StageI64",
|
||||||
|
PythonStageWrapperI64,
|
||||||
|
PythonStdScheduledHavocMutationsStageI64,
|
||||||
|
MyStdStateI64,
|
||||||
|
MyStdFuzzerI64,
|
||||||
|
PythonExecutorI64,
|
||||||
|
PythonEventManagerI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage!(
|
||||||
|
PythonStageU8,
|
||||||
|
"StageU8",
|
||||||
|
PythonStageWrapperU8,
|
||||||
|
PythonStdScheduledHavocMutationsStageU8,
|
||||||
|
MyStdStateU8,
|
||||||
|
MyStdFuzzerU8,
|
||||||
|
PythonExecutorU8,
|
||||||
|
PythonEventManagerU8
|
||||||
|
);
|
||||||
|
define_python_stage!(
|
||||||
|
PythonStageU16,
|
||||||
|
"StageU16",
|
||||||
|
PythonStageWrapperU16,
|
||||||
|
PythonStdScheduledHavocMutationsStageU16,
|
||||||
|
MyStdStateU16,
|
||||||
|
MyStdFuzzerU16,
|
||||||
|
PythonExecutorU16,
|
||||||
|
PythonEventManagerU16
|
||||||
|
);
|
||||||
|
define_python_stage!(
|
||||||
|
PythonStageU32,
|
||||||
|
"StageU32",
|
||||||
|
PythonStageWrapperU32,
|
||||||
|
PythonStdScheduledHavocMutationsStageU32,
|
||||||
|
MyStdStateU32,
|
||||||
|
MyStdFuzzerU32,
|
||||||
|
PythonExecutorU32,
|
||||||
|
PythonEventManagerU32
|
||||||
|
);
|
||||||
|
define_python_stage!(
|
||||||
|
PythonStageU64,
|
||||||
|
"StageU64",
|
||||||
|
PythonStageWrapperU64,
|
||||||
|
PythonStdScheduledHavocMutationsStageU64,
|
||||||
|
MyStdStateU64,
|
||||||
|
MyStdFuzzerU64,
|
||||||
|
PythonExecutorU64,
|
||||||
|
PythonEventManagerU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonStageI8>()?;
|
||||||
|
m.add_class::<PythonStageI16>()?;
|
||||||
|
m.add_class::<PythonStageI32>()?;
|
||||||
|
m.add_class::<PythonStageI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonStageU8>()?;
|
||||||
|
m.add_class::<PythonStageU16>()?;
|
||||||
|
m.add_class::<PythonStageU32>()?;
|
||||||
|
m.add_class::<PythonStageU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -161,3 +161,163 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `StdMutationalStage` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::bolts::tuples::tuple_list_type;
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
pub use crate::mutators::mutations::*;
|
||||||
|
pub use crate::mutators::mutations::*;
|
||||||
|
use crate::mutators::{havoc_mutations, StdScheduledMutator};
|
||||||
|
use crate::stages::StdMutationalStage;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
type HavocMutationsType = tuple_list_type!(
|
||||||
|
BitFlipMutator,
|
||||||
|
ByteFlipMutator,
|
||||||
|
ByteIncMutator,
|
||||||
|
ByteDecMutator,
|
||||||
|
ByteNegMutator,
|
||||||
|
ByteRandMutator,
|
||||||
|
ByteAddMutator,
|
||||||
|
WordAddMutator,
|
||||||
|
DwordAddMutator,
|
||||||
|
QwordAddMutator,
|
||||||
|
ByteInterestingMutator,
|
||||||
|
WordInterestingMutator,
|
||||||
|
DwordInterestingMutator,
|
||||||
|
BytesDeleteMutator,
|
||||||
|
BytesDeleteMutator,
|
||||||
|
BytesDeleteMutator,
|
||||||
|
BytesDeleteMutator,
|
||||||
|
BytesExpandMutator,
|
||||||
|
BytesInsertMutator,
|
||||||
|
BytesRandInsertMutator,
|
||||||
|
BytesSetMutator,
|
||||||
|
BytesRandSetMutator,
|
||||||
|
BytesCopyMutator,
|
||||||
|
BytesInsertCopyMutator,
|
||||||
|
BytesSwapMutator,
|
||||||
|
CrossoverInsertMutator,
|
||||||
|
CrossoverReplaceMutator,
|
||||||
|
);
|
||||||
|
|
||||||
|
macro_rules! define_python_std_mutational_stage {
|
||||||
|
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident, $executor_name: ident, $event_manager_name: ident) => {
|
||||||
|
use crate::events::pybind::$event_manager_name;
|
||||||
|
use crate::executors::pybind::$executor_name;
|
||||||
|
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
|
||||||
|
use crate::state::pybind::$my_std_state_type_name;
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = $py_name)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Python class for StdMutationalStage
|
||||||
|
pub struct $struct_name {
|
||||||
|
/// Rust wrapped StdMutationalStage object
|
||||||
|
pub std_mutational_stage: StdMutationalStage<
|
||||||
|
$executor_name,
|
||||||
|
$event_manager_name,
|
||||||
|
BytesInput,
|
||||||
|
StdScheduledMutator<BytesInput, HavocMutationsType, $my_std_state_type_name>,
|
||||||
|
$my_std_state_type_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name {
|
||||||
|
#[staticmethod]
|
||||||
|
fn new_from_scheduled_havoc_mutations() -> Self {
|
||||||
|
Self {
|
||||||
|
std_mutational_stage: StdMutationalStage::new(StdScheduledMutator::new(
|
||||||
|
havoc_mutations(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_std_mutational_stage!(
|
||||||
|
PythonStdScheduledHavocMutationsStageI8,
|
||||||
|
"StdScheduledHavocMutationsStageI8",
|
||||||
|
MyStdStateI8,
|
||||||
|
MyStdFuzzerI8,
|
||||||
|
PythonExecutorI8,
|
||||||
|
PythonEventManagerI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_std_mutational_stage!(
|
||||||
|
PythonStdScheduledHavocMutationsStageI16,
|
||||||
|
"StdScheduledHavocMutationsStageI16",
|
||||||
|
MyStdStateI16,
|
||||||
|
MyStdFuzzerI16,
|
||||||
|
PythonExecutorI16,
|
||||||
|
PythonEventManagerI16
|
||||||
|
);
|
||||||
|
define_python_std_mutational_stage!(
|
||||||
|
PythonStdScheduledHavocMutationsStageI32,
|
||||||
|
"StdScheduledHavocMutationsStageI32",
|
||||||
|
MyStdStateI32,
|
||||||
|
MyStdFuzzerI32,
|
||||||
|
PythonExecutorI32,
|
||||||
|
PythonEventManagerI32
|
||||||
|
);
|
||||||
|
define_python_std_mutational_stage!(
|
||||||
|
PythonStdScheduledHavocMutationsStageI64,
|
||||||
|
"StdScheduledHavocMutationsStageI64",
|
||||||
|
MyStdStateI64,
|
||||||
|
MyStdFuzzerI64,
|
||||||
|
PythonExecutorI64,
|
||||||
|
PythonEventManagerI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_std_mutational_stage!(
|
||||||
|
PythonStdScheduledHavocMutationsStageU8,
|
||||||
|
"StdScheduledHavocMutationsStageU8",
|
||||||
|
MyStdStateU8,
|
||||||
|
MyStdFuzzerU8,
|
||||||
|
PythonExecutorU8,
|
||||||
|
PythonEventManagerU8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_std_mutational_stage!(
|
||||||
|
PythonStdScheduledHavocMutationsStageU16,
|
||||||
|
"StdScheduledHavocMutationsStageU16",
|
||||||
|
MyStdStateU16,
|
||||||
|
MyStdFuzzerU16,
|
||||||
|
PythonExecutorU16,
|
||||||
|
PythonEventManagerU16
|
||||||
|
);
|
||||||
|
define_python_std_mutational_stage!(
|
||||||
|
PythonStdScheduledHavocMutationsStageU32,
|
||||||
|
"StdScheduledHavocMutationsStageU32",
|
||||||
|
MyStdStateU32,
|
||||||
|
MyStdFuzzerU32,
|
||||||
|
PythonExecutorU32,
|
||||||
|
PythonEventManagerU32
|
||||||
|
);
|
||||||
|
define_python_std_mutational_stage!(
|
||||||
|
PythonStdScheduledHavocMutationsStageU64,
|
||||||
|
"StdScheduledHavocMutationsStageU64",
|
||||||
|
MyStdStateU64,
|
||||||
|
MyStdFuzzerU64,
|
||||||
|
PythonExecutorU64,
|
||||||
|
PythonEventManagerU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonStdScheduledHavocMutationsStageI8>()?;
|
||||||
|
m.add_class::<PythonStdScheduledHavocMutationsStageI16>()?;
|
||||||
|
m.add_class::<PythonStdScheduledHavocMutationsStageI32>()?;
|
||||||
|
m.add_class::<PythonStdScheduledHavocMutationsStageI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonStdScheduledHavocMutationsStageU8>()?;
|
||||||
|
m.add_class::<PythonStdScheduledHavocMutationsStageU16>()?;
|
||||||
|
m.add_class::<PythonStdScheduledHavocMutationsStageU32>()?;
|
||||||
|
m.add_class::<PythonStdScheduledHavocMutationsStageU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -42,3 +42,147 @@ impl<E, EM, S, Z> StagesOwnedList<E, EM, S, Z> {
|
|||||||
Self { list }
|
Self { list }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `StagesOwnedList` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::stages::owned::StagesOwnedList;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! define_python_stage_owned_list {
|
||||||
|
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident, $event_manager_name: ident,
|
||||||
|
$executor_name: ident, $stage_name: ident) => {
|
||||||
|
use crate::events::pybind::$event_manager_name;
|
||||||
|
use crate::executors::pybind::$executor_name;
|
||||||
|
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
|
||||||
|
use crate::stages::pybind::$stage_name;
|
||||||
|
use crate::state::pybind::$my_std_state_type_name;
|
||||||
|
#[pyclass(unsendable, name = $py_name)]
|
||||||
|
|
||||||
|
/// Python class for StagesOwnedList
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct $struct_name {
|
||||||
|
/// Rust wrapped StagesOwnedList object
|
||||||
|
pub stages_owned_list: StagesOwnedList<
|
||||||
|
$executor_name,
|
||||||
|
$event_manager_name,
|
||||||
|
$my_std_state_type_name,
|
||||||
|
$my_std_fuzzer_type_name,
|
||||||
|
>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name {
|
||||||
|
//TODO: Add new from list
|
||||||
|
#[new]
|
||||||
|
fn new(stage: &$stage_name) -> Self {
|
||||||
|
// TODO: Be safe
|
||||||
|
unsafe {
|
||||||
|
Self {
|
||||||
|
stages_owned_list: StagesOwnedList {
|
||||||
|
list: vec![Box::new(std::mem::transmute_copy::<
|
||||||
|
$stage_name,
|
||||||
|
$stage_name,
|
||||||
|
>(stage))],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_stage_owned_list!(
|
||||||
|
PythonStagesOwnedListI8,
|
||||||
|
"StagesOwnedListI8",
|
||||||
|
MyStdStateI8,
|
||||||
|
MyStdFuzzerI8,
|
||||||
|
PythonEventManagerI8,
|
||||||
|
PythonExecutorI8,
|
||||||
|
PythonStageI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage_owned_list!(
|
||||||
|
PythonStagesOwnedListI16,
|
||||||
|
"StagesOwnedListI16",
|
||||||
|
MyStdStateI16,
|
||||||
|
MyStdFuzzerI16,
|
||||||
|
PythonEventManagerI16,
|
||||||
|
PythonExecutorI16,
|
||||||
|
PythonStageI16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage_owned_list!(
|
||||||
|
PythonStagesOwnedListI32,
|
||||||
|
"StagesOwnedListI32",
|
||||||
|
MyStdStateI32,
|
||||||
|
MyStdFuzzerI32,
|
||||||
|
PythonEventManagerI32,
|
||||||
|
PythonExecutorI32,
|
||||||
|
PythonStageI32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage_owned_list!(
|
||||||
|
PythonStagesOwnedListI64,
|
||||||
|
"StagesOwnedListI64",
|
||||||
|
MyStdStateI64,
|
||||||
|
MyStdFuzzerI64,
|
||||||
|
PythonEventManagerI64,
|
||||||
|
PythonExecutorI64,
|
||||||
|
PythonStageI64
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage_owned_list!(
|
||||||
|
PythonStagesOwnedListU8,
|
||||||
|
"StagesOwnedListU8",
|
||||||
|
MyStdStateU8,
|
||||||
|
MyStdFuzzerU8,
|
||||||
|
PythonEventManagerU8,
|
||||||
|
PythonExecutorU8,
|
||||||
|
PythonStageU8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage_owned_list!(
|
||||||
|
PythonStagesOwnedListU16,
|
||||||
|
"StagesOwnedListU16",
|
||||||
|
MyStdStateU16,
|
||||||
|
MyStdFuzzerU16,
|
||||||
|
PythonEventManagerU16,
|
||||||
|
PythonExecutorU16,
|
||||||
|
PythonStageU16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage_owned_list!(
|
||||||
|
PythonStagesOwnedListU32,
|
||||||
|
"StagesOwnedListU32",
|
||||||
|
MyStdStateU32,
|
||||||
|
MyStdFuzzerU32,
|
||||||
|
PythonEventManagerU32,
|
||||||
|
PythonExecutorU32,
|
||||||
|
PythonStageU32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_stage_owned_list!(
|
||||||
|
PythonStagesOwnedListU64,
|
||||||
|
"StagesOwnedListU64",
|
||||||
|
MyStdStateU64,
|
||||||
|
MyStdFuzzerU64,
|
||||||
|
PythonEventManagerU64,
|
||||||
|
PythonExecutorU64,
|
||||||
|
PythonStageU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonStagesOwnedListI8>()?;
|
||||||
|
m.add_class::<PythonStagesOwnedListI16>()?;
|
||||||
|
m.add_class::<PythonStagesOwnedListI32>()?;
|
||||||
|
m.add_class::<PythonStagesOwnedListI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonStagesOwnedListU8>()?;
|
||||||
|
m.add_class::<PythonStagesOwnedListU16>()?;
|
||||||
|
m.add_class::<PythonStagesOwnedListU32>()?;
|
||||||
|
m.add_class::<PythonStagesOwnedListU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -638,3 +638,188 @@ where
|
|||||||
&mut self.stability
|
&mut self.stability
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `State` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use crate::bolts::rands::pybind::PythonRand;
|
||||||
|
use crate::bolts::tuples::tuple_list;
|
||||||
|
use crate::corpus::pybind::PythonCorpus;
|
||||||
|
use crate::feedbacks::map::MapFeedbackState;
|
||||||
|
use crate::inputs::BytesInput;
|
||||||
|
use crate::state::StdState;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! define_python_state {
|
||||||
|
($type_name:ident, $struct_name:ident, $py_name:tt, $datatype:ty, $py_map_feedback_state_name:ident, $event_manager_name: ident,
|
||||||
|
$fuzzer_name: ident, $executor_name: ident, $rand_printable_generator: ident) => {
|
||||||
|
use crate::events::pybind::$event_manager_name;
|
||||||
|
use crate::executors::pybind::$executor_name;
|
||||||
|
use crate::feedbacks::map::pybind::$py_map_feedback_state_name;
|
||||||
|
use crate::fuzzer::pybind::$fuzzer_name;
|
||||||
|
use crate::generators::pybind::$rand_printable_generator;
|
||||||
|
|
||||||
|
/// `StdState` with fixed generics
|
||||||
|
pub type $type_name = StdState<
|
||||||
|
PythonCorpus,
|
||||||
|
(MapFeedbackState<$datatype>, ()),
|
||||||
|
BytesInput,
|
||||||
|
PythonRand,
|
||||||
|
PythonCorpus,
|
||||||
|
>;
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = $py_name)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Python class for StdState
|
||||||
|
pub struct $struct_name {
|
||||||
|
/// Rust wrapped StdState object
|
||||||
|
pub std_state: $type_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl $struct_name {
|
||||||
|
#[new]
|
||||||
|
fn new(
|
||||||
|
py_rand: PythonRand,
|
||||||
|
corpus: PythonCorpus,
|
||||||
|
solutions: PythonCorpus,
|
||||||
|
py_map_feedback_state: $py_map_feedback_state_name,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
std_state: StdState::new(
|
||||||
|
py_rand,
|
||||||
|
corpus,
|
||||||
|
solutions,
|
||||||
|
tuple_list!(py_map_feedback_state.map_feedback_state),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_initial_inputs(
|
||||||
|
&mut self,
|
||||||
|
py_fuzzer: &mut $fuzzer_name,
|
||||||
|
py_executor: &mut $executor_name,
|
||||||
|
py_generator: &mut $rand_printable_generator,
|
||||||
|
py_mgr: &mut $event_manager_name,
|
||||||
|
num: usize,
|
||||||
|
) {
|
||||||
|
self.std_state
|
||||||
|
.generate_initial_inputs(
|
||||||
|
&mut py_fuzzer.std_fuzzer,
|
||||||
|
py_executor,
|
||||||
|
&mut py_generator.rand_printable_generator,
|
||||||
|
py_mgr,
|
||||||
|
num,
|
||||||
|
)
|
||||||
|
.expect("Failed to generate the initial corpus".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_python_state!(
|
||||||
|
MyStdStateI8,
|
||||||
|
PythonStdStateI8,
|
||||||
|
"StdStateI8",
|
||||||
|
i8,
|
||||||
|
PythonMapFeedbackStateI8,
|
||||||
|
PythonEventManagerI8,
|
||||||
|
PythonStdFuzzerI8,
|
||||||
|
PythonExecutorI8,
|
||||||
|
PythonRandPrintablesGeneratorI8
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_state!(
|
||||||
|
MyStdStateI16,
|
||||||
|
PythonStdStateI16,
|
||||||
|
"StdStateI16",
|
||||||
|
i16,
|
||||||
|
PythonMapFeedbackStateI16,
|
||||||
|
PythonEventManagerI16,
|
||||||
|
PythonStdFuzzerI16,
|
||||||
|
PythonExecutorI16,
|
||||||
|
PythonRandPrintablesGeneratorI16
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_state!(
|
||||||
|
MyStdStateI32,
|
||||||
|
PythonStdStateI32,
|
||||||
|
"StdStateI32",
|
||||||
|
i32,
|
||||||
|
PythonMapFeedbackStateI32,
|
||||||
|
PythonEventManagerI32,
|
||||||
|
PythonStdFuzzerI32,
|
||||||
|
PythonExecutorI32,
|
||||||
|
PythonRandPrintablesGeneratorI32
|
||||||
|
);
|
||||||
|
|
||||||
|
define_python_state!(
|
||||||
|
MyStdStateI64,
|
||||||
|
PythonStdStateI64,
|
||||||
|
"StdStateI64",
|
||||||
|
i64,
|
||||||
|
PythonMapFeedbackStateI64,
|
||||||
|
PythonEventManagerI64,
|
||||||
|
PythonStdFuzzerI64,
|
||||||
|
PythonExecutorI64,
|
||||||
|
PythonRandPrintablesGeneratorI64
|
||||||
|
);
|
||||||
|
define_python_state!(
|
||||||
|
MyStdStateU8,
|
||||||
|
PythonStdStateU8,
|
||||||
|
"StdStateU8",
|
||||||
|
u8,
|
||||||
|
PythonMapFeedbackStateU8,
|
||||||
|
PythonEventManagerU8,
|
||||||
|
PythonStdFuzzerU8,
|
||||||
|
PythonExecutorU8,
|
||||||
|
PythonRandPrintablesGeneratorU8
|
||||||
|
);
|
||||||
|
define_python_state!(
|
||||||
|
MyStdStateU16,
|
||||||
|
PythonStdStateU16,
|
||||||
|
"StdStateU16",
|
||||||
|
u16,
|
||||||
|
PythonMapFeedbackStateU16,
|
||||||
|
PythonEventManagerU16,
|
||||||
|
PythonStdFuzzerU16,
|
||||||
|
PythonExecutorU16,
|
||||||
|
PythonRandPrintablesGeneratorU16
|
||||||
|
);
|
||||||
|
define_python_state!(
|
||||||
|
MyStdStateU32,
|
||||||
|
PythonStdStateU32,
|
||||||
|
"StdStateU32",
|
||||||
|
u32,
|
||||||
|
PythonMapFeedbackStateU32,
|
||||||
|
PythonEventManagerU32,
|
||||||
|
PythonStdFuzzerU32,
|
||||||
|
PythonExecutorU32,
|
||||||
|
PythonRandPrintablesGeneratorU32
|
||||||
|
);
|
||||||
|
define_python_state!(
|
||||||
|
MyStdStateU64,
|
||||||
|
PythonStdStateU64,
|
||||||
|
"StdStateU64",
|
||||||
|
u64,
|
||||||
|
PythonMapFeedbackStateU64,
|
||||||
|
PythonEventManagerU64,
|
||||||
|
PythonStdFuzzerU64,
|
||||||
|
PythonExecutorU64,
|
||||||
|
PythonRandPrintablesGeneratorU64
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register the classes to the python module
|
||||||
|
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonStdStateI8>()?;
|
||||||
|
m.add_class::<PythonStdStateI16>()?;
|
||||||
|
m.add_class::<PythonStdStateI32>()?;
|
||||||
|
m.add_class::<PythonStdStateI64>()?;
|
||||||
|
|
||||||
|
m.add_class::<PythonStdStateU8>()?;
|
||||||
|
m.add_class::<PythonStdStateU16>()?;
|
||||||
|
m.add_class::<PythonStdStateU32>()?;
|
||||||
|
m.add_class::<PythonStdStateU64>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user