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"] }
|
||||
libafl_qemu = { path = "../../libafl_qemu", 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]
|
||||
pyo3-build-config = { version = "0.15" }
|
||||
@ -14,3 +16,6 @@ pyo3-build-config = { version = "0.15" }
|
||||
[lib]
|
||||
name = "pylibafl"
|
||||
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_sugar;
|
||||
use libafl;
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[pymodule]
|
||||
@ -13,5 +14,9 @@ pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
|
||||
libafl_qemu::python_module(py, 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(())
|
||||
}
|
||||
|
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`
|
||||
introspection = [] # Include performance statistics of the fuzzing pipeline
|
||||
concolic_mutation = ["z3"] # include a simple concolic mutator based on z3
|
||||
python = ["pyo3"]
|
||||
tui_monitor = ["tui", "crossterm"] # enable TuiMonitor with crossterm
|
||||
cli = ["clap"] # expose bolts::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
|
||||
|
||||
pyo3 = { version = "0.15", optional = true }
|
||||
|
||||
# AGPL
|
||||
# !!! this create requires nightly
|
||||
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.
|
||||
/// 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.
|
||||
/// # Safety
|
||||
/// 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());
|
||||
}
|
||||
}
|
||||
|
||||
#[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.
|
||||
/// The current `Std` is a [`RandCorpusScheduler`], although this may change in the future, if another [`CorpusScheduler`] delivers better results.
|
||||
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))
|
||||
}
|
||||
}
|
||||
/// `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.
|
||||
|
||||
use core::{
|
||||
borrow::BorrowMut,
|
||||
ffi::c_void,
|
||||
fmt::{self, Debug, Formatter},
|
||||
marker::PhantomData,
|
||||
@ -16,6 +17,8 @@ use core::{
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
use std::intrinsics::transmute;
|
||||
|
||||
@ -52,40 +55,50 @@ use crate::{
|
||||
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.
|
||||
#[allow(dead_code)]
|
||||
pub struct InProcessExecutor<'a, H, I, OT, S>
|
||||
pub struct GenericInProcessExecutor<H, HB, I, OT, S>
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
HB: BorrowMut<H>,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
/// The harness function, being executed for each fuzzing loop execution
|
||||
harness_fn: &'a mut H,
|
||||
harness_fn: HB,
|
||||
/// The observers, observing each run
|
||||
observers: OT,
|
||||
// Crash and timeout hah
|
||||
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
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
HB: BorrowMut<H>,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("InProcessExecutor")
|
||||
f.debug_struct("GenericInProcessExecutor")
|
||||
.field("harness_fn", &"<fn>")
|
||||
.field("observers", &self.observers)
|
||||
.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
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
HB: BorrowMut<H>,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
@ -99,16 +112,17 @@ where
|
||||
self.handlers
|
||||
.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();
|
||||
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
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
HB: BorrowMut<H>,
|
||||
I: Input,
|
||||
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
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
HB: BorrowMut<H>,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
@ -136,7 +151,7 @@ where
|
||||
/// * `observers` - the observers observing the target during execution
|
||||
/// This may return an error on unix, if signal handler setup fails
|
||||
pub fn new<EM, OF, Z>(
|
||||
harness_fn: &'a mut H,
|
||||
harness_fn: HB,
|
||||
observers: OT,
|
||||
_fuzzer: &mut Z,
|
||||
_state: &mut S,
|
||||
@ -175,13 +190,13 @@ where
|
||||
/// Retrieve the harness function.
|
||||
#[inline]
|
||||
pub fn harness(&self) -> &H {
|
||||
self.harness_fn
|
||||
self.harness_fn.borrow()
|
||||
}
|
||||
|
||||
/// Retrieve the harness function for a mutable reference.
|
||||
#[inline]
|
||||
pub fn harness_mut(&mut self) -> &mut H {
|
||||
self.harness_fn
|
||||
self.harness_fn.borrow_mut()
|
||||
}
|
||||
|
||||
/// The inprocess handlers
|
||||
@ -305,7 +320,7 @@ impl InProcessHandlers {
|
||||
OF: Feedback<I, S>,
|
||||
S: HasSolutions<I> + HasClientPerfMonitor,
|
||||
Z: HasObjective<I, OF, S>,
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
{
|
||||
#[cfg(unix)]
|
||||
unsafe {
|
||||
@ -1376,7 +1391,7 @@ impl Handler for InProcessForkExecutorGlobalData {
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
pub struct InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
@ -1391,7 +1406,7 @@ where
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
impl<'a, H, I, OT, S, SP> Debug for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
@ -1408,7 +1423,7 @@ where
|
||||
impl<'a, EM, H, I, OT, S, SP, Z> Executor<EM, I, S, Z>
|
||||
for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
@ -1466,7 +1481,7 @@ where
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
impl<'a, H, I, OT, S, SP> InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
@ -1512,7 +1527,7 @@ where
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
impl<'a, H, I, OT, S, SP> HasObservers<I, OT, S> for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
H: FnMut(&I) -> ExitKind + ?Sized,
|
||||
I: Input,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
@ -1652,3 +1667,155 @@ mod tests {
|
||||
.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());
|
||||
}
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::feedbacks::{AllIsNovel, IsNovel, NextPow2IsNovel};
|
||||
@ -679,3 +678,162 @@ mod tests {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
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()
|
||||
}
|
||||
}
|
||||
/// `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 }
|
||||
}
|
||||
}
|
||||
|
||||
/// The Multi Map Observer merge different maps into one observer
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||
@ -977,3 +976,408 @@ where
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
/// `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 }
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
}
|
||||
}
|
||||
|
||||
#[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