Refactor libafl Python bindings (#632)

* SerdeAny MapFeedbackState

* Fix macro syntax

* alloc

* fix

* Metadata calibrate and map feedback

* metadata feedback states

* compile

* fmt

* Register common generic types

* tests

* sugar

* no_std

* fix book

* alloc

* fix fuzzers

* fix

* fmt

* disable python bindings for libafl

* clippy

* fmt

* fixes

* fmt

* compiling python bindings

* no uaf in python observer

* working python observer, feedback and executor

* mutators

* fmt

* nits

* added autofix script

* clippy

* clippy

* more clippy

* fix

* ignore clippy for deserialization

* newlines

* nits

* fmt

* feedbacks

* generators

* methods

* feedbacks

* pyerr

* fix

* fix

* fmt

* python bindings in CI

* fix

* fix

* fix

* autofix

* clippy

Co-authored-by: Dominik Maier <dmnk@google.com>
This commit is contained in:
Andrea Fioraldi 2022-05-25 16:56:06 +02:00 committed by GitHub
parent da537aae83
commit 28edbad618
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 3379 additions and 1986 deletions

View File

@ -96,6 +96,23 @@ jobs:
run: sudo ./libafl_concolic/test/smoke_test_ubuntu_deps.sh run: sudo ./libafl_concolic/test/smoke_test_ubuntu_deps.sh
- name: Run smoke test - name: Run smoke test
run: ./libafl_concolic/test/smoke_test.sh run: ./libafl_concolic/test/smoke_test.sh
bindings:
runs-on: ubuntu-latest
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: Swatinem/rust-cache@v1
- name: set mold linker as default linker
uses: rui314/setup-mold@v1
- name: Install deps
run: sudo apt-get install -y llvm llvm-dev clang ninja-build python3-dev python3-pip python3-venv
- name: Install maturin
run: python3 -m pip install maturin
- uses: actions/checkout@v2
- name: Run a maturin build
run: cd ./bindings/pylibafl && maturin build
fuzzers: fuzzers:
env: env:
CC: ccache clang # use ccache in default CC: ccache clang # use ccache in default

View File

@ -1,14 +1,13 @@
[package] [package]
name = "pylibafl" name = "pylibafl"
version = "0.7.0" version = "0.7.1"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
pyo3 = { version = "0.15", features = ["extension-module"] } pyo3 = { version = "0.15", features = ["extension-module"] }
libafl_qemu = { path = "../../libafl_qemu", version = "0.7", features = ["python"] } libafl_qemu = { path = "../../libafl_qemu", version = "0.7", features = ["python"] }
libafl_sugar = { path = "../../libafl_sugar", version = "0.7", features = ["python"] } libafl_sugar = { path = "../../libafl_sugar", version = "0.7", features = ["python"] }
#libafl = { path = "../../libafl", version = "0.7", features = ["python"] } libafl = { path = "../../libafl", version = "0.7", features = ["python"] }
libafl = { path = "../../libafl", version = "0.7" }
[build-dependencies] [build-dependencies]
pyo3-build-config = { version = "0.15" } pyo3-build-config = { version = "0.15" }

View File

@ -1,22 +1,117 @@
//use libafl; use libafl;
use libafl_qemu; use libafl_qemu;
use libafl_sugar; use libafl_sugar;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyDict;
const LIBAFL_CODE: &str = r#"
class BaseObserver:
def flush(self):
pass
def pre_exec(self, state, input):
pass
def post_exec(self, state, input, exit_kind):
pass
def pre_exec_child(self, state, input):
pass
def post_exec_child(self, state, input, exit_kind):
pass
def name(self):
return type(self).__name__
def as_observer(self):
return Observer.new_py(self)
class BaseFeedback:
def init_state(self, state):
pass
def is_interesting(self, state, mgr, input, observers, exit_kind) -> bool:
return False
def append_metadata(self, state, testcase):
pass
def discard_metadata(self, state, input):
pass
def name(self):
return type(self).__name__
def as_feedback(self):
return Feedback.new_py(self)
class BaseExecutor:
def observers(self) -> ObserversTuple:
raise NotImplementedError('Implement this yourself')
def run_target(self, fuzzer, state, mgr, input) -> ExitKind:
raise NotImplementedError('Implement this yourself')
def as_executor(self):
return Executor.new_py(self)
class BaseStage:
def perform(self, fuzzer, executor, state, manager, corpus_idx):
pass
def as_stage(self):
return Stage.new_py(self)
class BaseMutator:
def mutate(self, state, input, stage_idx):
pass
def post_exec(self, state, stage_idx, corpus_idx):
pass
def as_mutator(self):
return Mutator.new_py(self)
class FnStage(BaseStage):
def __init__(self, fn):
self.fn = fn
def __call__(self, fuzzer, executor, state, manager, corpus_idx):
self.fn(fuzzer, executor, state, manager, corpus_idx)
def perform(self, fuzzer, executor, state, manager, corpus_idx):
self.fn(fuzzer, executor, state, manager, corpus_idx)
def feedback_not(a):
return NotFeedback(a).as_feedback()
def feedback_and(a, b):
return EagerAndFeedback(a, b).as_feedback()
def feedback_and_fast(a, b):
return FastAndFeedback(a, b).as_feedback()
def feedback_or(a, b):
return EagerOrFeedback(a, b).as_feedback()
def feedback_or_fast(a, b):
return FastOrFeedback(a, b).as_feedback()
"#;
#[pymodule] #[pymodule]
#[pyo3(name = "pylibafl")] #[pyo3(name = "pylibafl")]
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
let modules = py.import("sys")?.getattr("modules")?;
let sugar_module = PyModule::new(py, "sugar")?; let sugar_module = PyModule::new(py, "sugar")?;
libafl_sugar::python_module(py, sugar_module)?; libafl_sugar::python_module(py, sugar_module)?;
m.add_submodule(sugar_module)?; m.add_submodule(sugar_module)?;
modules.set_item("pylibafl.sugar", sugar_module)?;
let qemu_module = PyModule::new(py, "qemu")?; let qemu_module = PyModule::new(py, "qemu")?;
libafl_qemu::python_module(py, qemu_module)?; libafl_qemu::python_module(py, qemu_module)?;
m.add_submodule(qemu_module)?; m.add_submodule(qemu_module)?;
//let libafl_module = PyModule::new(py, "libafl")?; modules.set_item("pylibafl.qemu", qemu_module)?;
//libafl::python_module(py, libafl_module)?;
//m.add_submodule(libafl_module)?; let libafl_module = PyModule::new(py, "libafl")?;
libafl::pybind::python_module(py, libafl_module)?;
libafl_module.add("__builtins__", py.import("builtins")?)?;
let locals = PyDict::new(py);
py.run(LIBAFL_CODE, Some(libafl_module.dict()), Some(locals))?;
for (key, val) in locals.iter() {
libafl_module.add(key.extract::<&str>()?, val)?;
}
m.add_submodule(libafl_module)?;
modules.set_item("pylibafl.libafl", libafl_module)?;
Ok(()) Ok(())
} }

74
bindings/pylibafl/test.py Normal file
View File

@ -0,0 +1,74 @@
from pylibafl.libafl import *
import ctypes
class FooObserver(BaseObserver):
def __init__(self):
self.n = 0
def name(self):
return "Foo"
def pre_exec(self, state, input):
if self.n % 10000 == 0:
print("FOO!", self.n, input)
self.n += 1
class FooFeedback(BaseFeedback):
def is_interesting(self, state, mgr, input, observers, exit_kind):
ob = observers.match_name("Foo").unwrap_py()
return ob.n % 10000 == 0
class FooExecutor(BaseExecutor):
def __init__(self, harness, observers: ObserversTuple):
self.h = harness
self.o = observers
def observers(self):
return self.o
def run_target(self, fuzzer, state, mgr, input) -> ExitKind:
return (self.h)(input)
libc = ctypes.cdll.LoadLibrary("libc.so.6")
area_ptr = libc.calloc(1, 4096)
observer = StdMapObserverI8("mymap", area_ptr, 4096)
m = observer.as_map_observer()
observers = ObserversTuple([observer.as_map_observer().as_observer(), FooObserver().as_observer()])
feedback = feedback_or(MaxMapFeedbackI8(m).as_feedback(), FooFeedback().as_feedback())
objective = feedback_and_fast(CrashFeedback().as_feedback(), MaxMapFeedbackI8(m).as_feedback())
fuzzer = StdFuzzer(feedback, objective)
rand = StdRand.with_current_nanos()
state = StdState(rand.as_rand(), InMemoryCorpus().as_corpus(), InMemoryCorpus().as_corpus(), feedback, objective)
monitor = SimpleMonitor(lambda s: print(s))
mgr = SimpleEventManager(monitor.as_monitor())
def harness(buf) -> ExitKind:
#print(buf)
m[0] = 1
if len(buf) > 0 and buf[0] == ord('a'):
m[1] = 1
if len(buf) > 1 and buf[1] == ord('b'):
m[2] = 1
if len(buf) > 2 and buf[2] == ord('c'):
m[3] = 1
return ExitKind.crash()
return ExitKind.ok()
# executor = InProcessExecutor(harness, observers, fuzzer, state, mgr.as_manager())
executor = FooExecutor(harness, observers)
stage = StdMutationalStage(StdHavocMutator().as_mutator())
stage_tuple_list = StagesTuple([stage.as_stage()])
fuzzer.add_input(state, executor.as_executor(), mgr.as_manager(), b'\0\0')
fuzzer.fuzz_loop(executor.as_executor(), state, mgr.as_manager(), stage_tuple_list)

View File

@ -22,7 +22,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]} condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell" script_runner="@shell"
script=''' script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz curl https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz --output libpng-1.6.37.tar.xz
tar -xvf libpng-1.6.37.tar.xz tar -xvf libpng-1.6.37.tar.xz
''' '''

View File

@ -56,6 +56,7 @@ pub fn libafl_main() {
} }
/// The actual fuzzer /// The actual fuzzer
#[cfg(not(test))]
fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> { fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> {
// 'While the stats are state, they are usually used in the broker - which is likely never restarted // 'While the stats are state, they are usually used in the broker - which is likely never restarted
let monitor = MultiMonitor::new(|s| println!("{}", s)); let monitor = MultiMonitor::new(|s| println!("{}", s));

View File

@ -19,7 +19,7 @@ fork = [] # uses the fork() syscall to spawn children, instead of launching a ne
rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng` rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng`
introspection = [] # Include performance statistics of the fuzzing pipeline introspection = [] # Include performance statistics of the fuzzing pipeline
concolic_mutation = ["z3"] # include a simple concolic mutator based on z3 concolic_mutation = ["z3"] # include a simple concolic mutator based on z3
#python = ["pyo3"] python = ["pyo3"]
tui_monitor = ["tui", "crossterm"] # enable TuiMonitor with crossterm tui_monitor = ["tui", "crossterm"] # enable TuiMonitor with crossterm
cli = ["clap"] # expose bolts::cli cli = ["clap"] # expose bolts::cli
qemu_cli = ["cli"] qemu_cli = ["cli"]
@ -84,7 +84,8 @@ wait-timeout = { version = "0.2", optional = true } # used by CommandExecutor to
z3 = { version = "0.11", features = ["static-link-z3"], optional = true } # for concolic mutation z3 = { version = "0.11", features = ["static-link-z3"], optional = true } # for concolic mutation
pyo3 = { version = "0.15", optional = true } pyo3 = { version = "0.15", optional = true, features = ["serde", "macros"] }
concat-idents = "1.1.3"
# AGPL # AGPL
# !!! this create requires nightly # !!! this create requires nightly

View File

@ -100,6 +100,14 @@ use crate::Error;
pub use libc::{c_void, siginfo_t}; pub use libc::{c_void, siginfo_t};
extern "C" { extern "C" {
/// The `libc` `getcontext`
///
/// # Notes
///
/// Somehow, `MacOS` on `aarch64` claims this type uses a 128 bit `int`
/// (@`rustc` 1.59.0)
/// Not much we can about it, for now.
#[allow(improper_ctypes)]
fn getcontext(ucp: *mut ucontext_t) -> c_int; fn getcontext(ucp: *mut ucontext_t) -> c_int;
} }

View File

@ -432,6 +432,7 @@ mod tests {
} }
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
/// `Rand` Python bindings /// `Rand` Python bindings
pub mod pybind { pub mod pybind {
use super::Rand; use super::Rand;
@ -444,7 +445,7 @@ pub mod pybind {
/// Python class for StdRand /// Python class for StdRand
pub struct PythonStdRand { pub struct PythonStdRand {
/// Rust wrapped StdRand object /// Rust wrapped StdRand object
pub std_rand: StdRand, pub inner: StdRand,
} }
#[pymethods] #[pymethods]
@ -452,52 +453,58 @@ pub mod pybind {
#[staticmethod] #[staticmethod]
fn with_current_nanos() -> Self { fn with_current_nanos() -> Self {
Self { Self {
std_rand: StdRand::with_seed(current_nanos()), inner: StdRand::with_seed(current_nanos()),
} }
} }
#[staticmethod] #[staticmethod]
fn with_seed(seed: u64) -> Self { fn with_seed(seed: u64) -> Self {
Self { Self {
std_rand: StdRand::with_seed(seed), inner: StdRand::with_seed(seed),
} }
} }
fn as_rand(slf: Py<Self>) -> PythonRand {
PythonRand::new_std(slf)
}
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
enum PythonRandWrapper { enum PythonRandWrapper {
StdRand(PythonStdRand), Std(Py<PythonStdRand>),
} }
/// Rand Trait binding /// Rand Trait binding
#[pyclass(unsendable, name = "Rand")] #[pyclass(unsendable, name = "Rand")]
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PythonRand { pub struct PythonRand {
rand: PythonRandWrapper, wrapper: PythonRandWrapper,
}
macro_rules! unwrap_me_mut {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonRandWrapper, { Std })
};
} }
#[pymethods] #[pymethods]
impl PythonRand { impl PythonRand {
#[staticmethod] #[staticmethod]
fn new_from_std(py_std_rand: PythonStdRand) -> Self { fn new_std(py_std_rand: Py<PythonStdRand>) -> Self {
Self { Self {
rand: PythonRandWrapper::StdRand(py_std_rand), wrapper: PythonRandWrapper::Std(py_std_rand),
} }
} }
} }
impl Rand for PythonRand { impl Rand for PythonRand {
fn set_seed(&mut self, seed: u64) { fn set_seed(&mut self, seed: u64) {
match &mut self.rand { unwrap_me_mut!(self.wrapper, r, { r.set_seed(seed) });
PythonRandWrapper::StdRand(py_std_rand) => py_std_rand.std_rand.set_seed(seed),
}
} }
#[inline] #[inline]
fn next(&mut self) -> u64 { fn next(&mut self) -> u64 {
match &mut self.rand { unwrap_me_mut!(self.wrapper, r, { r.next() })
PythonRandWrapper::StdRand(py_std_rand) => py_std_rand.std_rand.next(),
}
} }
} }

View File

@ -9,9 +9,11 @@ use core::{
use xxhash_rust::xxh3::xxh3_64; use xxhash_rust::xxh3::xxh3_64;
#[rustversion::nightly] /// Returns if the type `T` is equal to `U`
/// From <https://stackoverflow.com/a/60138532/7658998> /// From <https://stackoverflow.com/a/60138532/7658998>
const fn type_eq<T: ?Sized, U: ?Sized>() -> bool { #[rustversion::nightly]
#[must_use]
pub const fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
// Helper trait. `VALUE` is false, except for the specialization of the // Helper trait. `VALUE` is false, except for the specialization of the
// case where `T == U`. // case where `T == U`.
trait TypeEq<U: ?Sized> { trait TypeEq<U: ?Sized> {
@ -31,8 +33,10 @@ const fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
<T as TypeEq<U>>::VALUE <T as TypeEq<U>>::VALUE
} }
/// Returns if the type `T` is equal to `U`
#[rustversion::not(nightly)] #[rustversion::not(nightly)]
const fn type_eq<T: ?Sized, U: ?Sized>() -> bool { #[must_use]
pub const fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
// BEWARE! This is not unsafe, it is SUPER UNSAFE // BEWARE! This is not unsafe, it is SUPER UNSAFE
true true
} }

View File

@ -137,19 +137,19 @@ where
/// ``CachedOnDiskCorpus`` Python bindings /// ``CachedOnDiskCorpus`` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
pub mod pybind { pub mod pybind {
use std::path::PathBuf; use crate::corpus::pybind::PythonCorpus;
use crate::corpus::CachedOnDiskCorpus; use crate::corpus::CachedOnDiskCorpus;
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[pyclass(unsendable, name = "CachedOnDiskCorpus")] #[pyclass(unsendable, name = "CachedOnDiskCorpus")]
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for CachedOnDiskCorpus /// Python class for CachedOnDiskCorpus
pub struct PythonCachedOnDiskCorpus { pub struct PythonCachedOnDiskCorpus {
/// Rust wrapped CachedOnDiskCorpus object /// Rust wrapped CachedOnDiskCorpus object
pub cached_on_disk_corpus: CachedOnDiskCorpus<BytesInput>, pub inner: CachedOnDiskCorpus<BytesInput>,
} }
#[pymethods] #[pymethods]
@ -157,10 +157,13 @@ pub mod pybind {
#[new] #[new]
fn new(path: String, cache_max_len: usize) -> Self { fn new(path: String, cache_max_len: usize) -> Self {
Self { Self {
cached_on_disk_corpus: CachedOnDiskCorpus::new(PathBuf::from(path), cache_max_len) inner: CachedOnDiskCorpus::new(PathBuf::from(path), cache_max_len).unwrap(),
.unwrap(),
} }
} }
fn as_corpus(slf: Py<Self>) -> PythonCorpus {
PythonCorpus::new_cached_on_disk(slf)
}
} }
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {

View File

@ -91,6 +91,7 @@ where
/// `InMemoryCorpus` Python bindings /// `InMemoryCorpus` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
pub mod pybind { pub mod pybind {
use crate::corpus::pybind::PythonCorpus;
use crate::corpus::InMemoryCorpus; use crate::corpus::InMemoryCorpus;
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use pyo3::prelude::*; use pyo3::prelude::*;
@ -101,7 +102,7 @@ pub mod pybind {
/// Python class for InMemoryCorpus /// Python class for InMemoryCorpus
pub struct PythonInMemoryCorpus { pub struct PythonInMemoryCorpus {
/// Rust wrapped InMemoryCorpus object /// Rust wrapped InMemoryCorpus object
pub in_memory_corpus: InMemoryCorpus<BytesInput>, pub inner: InMemoryCorpus<BytesInput>,
} }
#[pymethods] #[pymethods]
@ -109,9 +110,13 @@ pub mod pybind {
#[new] #[new]
fn new() -> Self { fn new() -> Self {
Self { Self {
in_memory_corpus: InMemoryCorpus::new(), inner: InMemoryCorpus::new(),
} }
} }
fn as_corpus(slf: Py<Self>) -> PythonCorpus {
PythonCorpus::new_in_memory(slf)
}
} }
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {

View File

@ -54,8 +54,10 @@ where
/// `Corpus` Python bindings /// `Corpus` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::corpus::inmemory::pybind::PythonInMemoryCorpus; use crate::corpus::inmemory::pybind::PythonInMemoryCorpus;
use crate::corpus::testcase::pybind::PythonTestcaseWrapper;
use crate::corpus::{Corpus, Testcase}; use crate::corpus::{Corpus, Testcase};
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use crate::Error; use crate::Error;
@ -68,148 +70,138 @@ pub mod pybind {
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
enum PythonCorpusWrapper { enum PythonCorpusWrapper {
InMemory(PythonInMemoryCorpus), InMemory(Py<PythonInMemoryCorpus>),
CachedOnDisk(PythonCachedOnDiskCorpus), CachedOnDisk(Py<PythonCachedOnDiskCorpus>),
OnDisk(PythonOnDiskCorpus), OnDisk(Py<PythonOnDiskCorpus>),
} }
/// Corpus Trait binding /// Corpus Trait binding
#[pyclass(unsendable, name = "Corpus")] #[pyclass(unsendable, name = "Corpus")]
#[allow(clippy::unsafe_derive_deserialize)]
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PythonCorpus { pub struct PythonCorpus {
corpus: PythonCorpusWrapper, wrapper: PythonCorpusWrapper,
}
macro_rules! unwrap_me {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_body!(
$wrapper,
$name,
$body,
PythonCorpusWrapper,
{
InMemory,
CachedOnDisk,
OnDisk
}
)
};
}
macro_rules! unwrap_me_mut {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_mut_body!(
$wrapper,
$name,
$body,
PythonCorpusWrapper,
{
InMemory,
CachedOnDisk,
OnDisk
}
)
};
} }
#[pymethods] #[pymethods]
impl PythonCorpus { impl PythonCorpus {
#[staticmethod] #[staticmethod]
fn new_from_in_memory(py_in_memory_corpus: PythonInMemoryCorpus) -> Self { #[must_use]
pub fn new_in_memory(py_in_memory_corpus: Py<PythonInMemoryCorpus>) -> Self {
Self { Self {
corpus: PythonCorpusWrapper::InMemory(py_in_memory_corpus), wrapper: PythonCorpusWrapper::InMemory(py_in_memory_corpus),
} }
} }
#[staticmethod] #[staticmethod]
fn new_from_cached_on_disk(py_cached_on_disk_corpus: PythonCachedOnDiskCorpus) -> Self { #[must_use]
pub fn new_cached_on_disk(py_cached_on_disk_corpus: Py<PythonCachedOnDiskCorpus>) -> Self {
Self { Self {
corpus: PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus), wrapper: PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus),
} }
} }
#[staticmethod] #[staticmethod]
fn new_from_on_disk(py_on_disk_corpus: PythonOnDiskCorpus) -> Self { #[must_use]
pub fn new_on_disk(py_on_disk_corpus: Py<PythonOnDiskCorpus>) -> Self {
Self { Self {
corpus: PythonCorpusWrapper::OnDisk(py_on_disk_corpus), wrapper: PythonCorpusWrapper::OnDisk(py_on_disk_corpus),
} }
} }
#[pyo3(name = "count")]
fn pycount(&self) -> usize {
self.count()
}
#[pyo3(name = "current")]
fn pycurrent(&self) -> Option<usize> {
*self.current()
}
#[pyo3(name = "get")]
fn pyget(&self, idx: usize) -> PythonTestcaseWrapper {
let t: &mut Testcase<BytesInput> = unwrap_me!(self.wrapper, c, {
c.get(idx)
.map(|v| unsafe { v.as_ptr().as_mut().unwrap() })
.expect("PythonCorpus::get failed")
});
PythonTestcaseWrapper::wrap(t)
}
} }
impl Corpus<BytesInput> for PythonCorpus { impl Corpus<BytesInput> for PythonCorpus {
#[inline] #[inline]
fn count(&self) -> usize { fn count(&self) -> usize {
match &self.corpus { unwrap_me!(self.wrapper, c, { c.count() })
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] #[inline]
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> { fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
match &mut self.corpus { unwrap_me_mut!(self.wrapper, c, { c.add(testcase) })
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] #[inline]
fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> { fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
match &mut self.corpus { unwrap_me_mut!(self.wrapper, c, { c.replace(idx, testcase) })
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] #[inline]
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> { fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
match &mut self.corpus { unwrap_me_mut!(self.wrapper, c, { c.remove(idx) })
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] #[inline]
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> { fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
match &self.corpus { let ptr = unwrap_me!(self.wrapper, c, {
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => { c.get(idx)
py_in_memory_corpus.in_memory_corpus.get(idx) .map(|v| v as *const RefCell<Testcase<BytesInput>>)
} })?;
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => { Ok(unsafe { ptr.as_ref().unwrap() })
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] #[inline]
fn current(&self) -> &Option<usize> { fn current(&self) -> &Option<usize> {
match &self.corpus { let ptr = unwrap_me!(self.wrapper, c, { c.current() as *const Option<usize> });
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => { unsafe { ptr.as_ref().unwrap() }
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] #[inline]
fn current_mut(&mut self) -> &mut Option<usize> { fn current_mut(&mut self) -> &mut Option<usize> {
match &mut self.corpus { let ptr = unwrap_me_mut!(self.wrapper, c, { c.current_mut() as *mut Option<usize> });
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => { unsafe { ptr.as_mut().unwrap() }
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()
}
}
} }
} }

View File

@ -208,19 +208,19 @@ where
#[cfg(feature = "python")] #[cfg(feature = "python")]
/// `OnDiskCorpus` Python bindings /// `OnDiskCorpus` Python bindings
pub mod pybind { pub mod pybind {
use std::path::PathBuf; use crate::corpus::pybind::PythonCorpus;
use crate::corpus::OnDiskCorpus; use crate::corpus::OnDiskCorpus;
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[pyclass(unsendable, name = "OnDiskCorpus")] #[pyclass(unsendable, name = "OnDiskCorpus")]
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for OnDiskCorpus /// Python class for OnDiskCorpus
pub struct PythonOnDiskCorpus { pub struct PythonOnDiskCorpus {
/// Rust wrapped OnDiskCorpus object /// Rust wrapped OnDiskCorpus object
pub on_disk_corpus: OnDiskCorpus<BytesInput>, pub inner: OnDiskCorpus<BytesInput>,
} }
#[pymethods] #[pymethods]
@ -228,9 +228,13 @@ pub mod pybind {
#[new] #[new]
fn new(path: String) -> Self { fn new(path: String) -> Self {
Self { Self {
on_disk_corpus: OnDiskCorpus::new(PathBuf::from(path)).unwrap(), inner: OnDiskCorpus::new(PathBuf::from(path)).unwrap(),
} }
} }
fn as_corpus(slf: Py<Self>) -> PythonCorpus {
PythonCorpus::new_on_disk(slf)
}
} }
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {

View File

@ -345,3 +345,98 @@ impl SchedulerTestcaseMetaData {
} }
crate::impl_serdeany!(SchedulerTestcaseMetaData); crate::impl_serdeany!(SchedulerTestcaseMetaData);
#[cfg(feature = "python")]
#[allow(missing_docs)]
/// `Testcase` Python bindings
pub mod pybind {
use super::{HasMetadata, Testcase};
use crate::bolts::ownedref::OwnedPtrMut;
use crate::inputs::{BytesInput, HasBytesVec};
use crate::pybind::PythonMetadata;
use pyo3::prelude::*;
use pyo3::types::PyDict;
/// `PythonTestcase` with fixed generics
pub type PythonTestcase = Testcase<BytesInput>;
#[pyclass(unsendable, name = "Testcase")]
#[derive(Debug)]
/// Python class for Testcase
pub struct PythonTestcaseWrapper {
/// Rust wrapped Testcase object
pub inner: OwnedPtrMut<PythonTestcase>,
}
impl PythonTestcaseWrapper {
pub fn wrap(r: &mut PythonTestcase) -> Self {
Self {
inner: OwnedPtrMut::Ptr(r),
}
}
#[must_use]
pub fn unwrap(&self) -> &PythonTestcase {
self.inner.as_ref()
}
pub fn unwrap_mut(&mut self) -> &mut PythonTestcase {
self.inner.as_mut()
}
}
#[pymethods]
impl PythonTestcaseWrapper {
#[new]
fn new(input: Vec<u8>) -> Self {
Self {
inner: OwnedPtrMut::Owned(Box::new(PythonTestcase::new(BytesInput::new(input)))),
}
}
fn load_input(&mut self) -> &[u8] {
self.inner
.as_mut()
.load_input()
.expect("Failed to load input")
.bytes()
}
#[getter]
fn exec_time_ms(&self) -> Option<u128> {
self.inner.as_ref().exec_time().map(|t| t.as_millis())
}
#[getter]
fn executions(&self) -> usize {
*self.inner.as_ref().executions()
}
#[getter]
fn fuzz_level(&self) -> usize {
self.inner.as_ref().fuzz_level()
}
#[getter]
fn fuzzed(&self) -> bool {
self.inner.as_ref().fuzzed()
}
fn metadata(&mut self) -> PyObject {
let meta = self.inner.as_mut().metadata_mut();
if !meta.contains::<PythonMetadata>() {
Python::with_gil(|py| {
let dict: Py<PyDict> = PyDict::new(py).into();
meta.insert(PythonMetadata::new(dict.to_object(py)));
});
}
meta.get::<PythonMetadata>().unwrap().map.clone()
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonTestcaseWrapper>()?;
Ok(())
}
}

View File

@ -543,208 +543,99 @@ mod tests {
}; };
} }
} }
/// `EventManager` Python bindings /// `EventManager` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::events::simple::pybind::PythonSimpleEventManager; use crate::events::simple::pybind::PythonSimpleEventManager;
use crate::events::{ use crate::events::{
Event, EventFirer, EventManager, EventManagerId, EventProcessor, EventRestarter, Event, EventFirer, EventManager, EventManagerId, EventProcessor, EventRestarter,
HasEventManagerId, ProgressReporter, HasEventManagerId, ProgressReporter,
}; };
use crate::executors::pybind::PythonExecutor;
use crate::fuzzer::pybind::PythonStdFuzzer;
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use crate::state::pybind::PythonStdState;
use crate::Error; use crate::Error;
use pyo3::prelude::*; use pyo3::prelude::*;
macro_rules! define_python_event_manager { #[derive(Debug, Clone)]
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $std_state_name: ident, $executor_name: ident, $my_std_fuzzer_type_name: ident) => { pub enum PythonEventManagerWrapper {
use crate::executors::pybind::$executor_name; Simple(Py<PythonSimpleEventManager>),
use crate::pybind::$my_std_fuzzer_type_name; }
use crate::state::pybind::$std_state_name;
#[derive(Debug, Clone)] /// EventManager Trait binding
enum $wrapper_name { #[pyclass(unsendable, name = "EventManager")]
Simple(*mut PythonSimpleEventManager), #[derive(Debug, Clone)]
} pub struct PythonEventManager {
pub wrapper: PythonEventManagerWrapper,
}
/// EventManager Trait binding macro_rules! unwrap_me {
#[pyclass(unsendable, name = $py_name_trait)] ($wrapper:expr, $name:ident, $body:block) => {
#[derive(Debug, Clone)] crate::unwrap_me_body!($wrapper, $name, $body, PythonEventManagerWrapper, {
pub struct $struct_name_trait { Simple
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!( macro_rules! unwrap_me_mut {
PythonEventManagerI8, ($wrapper:expr, $name:ident, $body:block) => {
"EventManagerI8", crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonEventManagerWrapper, {
PythonEventManagerWrapperI8, Simple
MyStdStateI8, })
PythonExecutorI8, };
MyStdFuzzerI8 }
);
define_python_event_manager!( #[pymethods]
PythonEventManagerI16, impl PythonEventManager {
"EventManagerI16", #[staticmethod]
PythonEventManagerWrapperI16, #[must_use]
MyStdStateI16, pub fn new_simple(mgr: Py<PythonSimpleEventManager>) -> Self {
PythonExecutorI16, Self {
MyStdFuzzerI16 wrapper: PythonEventManagerWrapper::Simple(mgr),
); }
}
}
define_python_event_manager!( impl EventFirer<BytesInput> for PythonEventManager {
PythonEventManagerI32, fn fire<S>(&mut self, state: &mut S, event: Event<BytesInput>) -> Result<(), Error> {
"EventManagerI32", unwrap_me_mut!(self.wrapper, e, { e.fire(state, event) })
PythonEventManagerWrapperI32, }
MyStdStateI32, }
PythonExecutorI32,
MyStdFuzzerI32
);
define_python_event_manager!( impl<S> EventRestarter<S> for PythonEventManager {}
PythonEventManagerI64,
"EventManagerI64",
PythonEventManagerWrapperI64,
MyStdStateI64,
PythonExecutorI64,
MyStdFuzzerI64
);
define_python_event_manager!( impl EventProcessor<PythonExecutor, BytesInput, PythonStdState, PythonStdFuzzer>
PythonEventManagerU8, for PythonEventManager
"EventManagerU8", {
PythonEventManagerWrapperU8, fn process(
MyStdStateU8, &mut self,
PythonExecutorU8, fuzzer: &mut PythonStdFuzzer,
MyStdFuzzerU8 state: &mut PythonStdState,
); executor: &mut PythonExecutor,
define_python_event_manager!( ) -> Result<usize, Error> {
PythonEventManagerU16, unwrap_me_mut!(self.wrapper, e, { e.process(fuzzer, state, executor) })
"EventManagerU16", }
PythonEventManagerWrapperU16, }
MyStdStateU16,
PythonExecutorU16, impl ProgressReporter<BytesInput> for PythonEventManager {}
MyStdFuzzerU16
); impl HasEventManagerId for PythonEventManager {
define_python_event_manager!( fn mgr_id(&self) -> EventManagerId {
PythonEventManagerU32, unwrap_me!(self.wrapper, e, { e.mgr_id() })
"EventManagerU32", }
PythonEventManagerWrapperU32, }
MyStdStateU32,
PythonExecutorU32, impl EventManager<PythonExecutor, BytesInput, PythonStdState, PythonStdFuzzer>
MyStdFuzzerU32 for PythonEventManager
); {
define_python_event_manager!( }
PythonEventManagerU64,
"EventManagerU64",
PythonEventManagerWrapperU64,
MyStdStateU64,
PythonExecutorU64,
MyStdFuzzerU64
);
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonEventManagerI8>()?; m.add_class::<PythonEventManager>()?;
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(()) Ok(())
} }
} }

View File

@ -425,9 +425,12 @@ where
Ok((state, mgr)) Ok((state, mgr))
} }
} }
/// `SimpleEventManager` Python bindings /// `SimpleEventManager` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::events::pybind::PythonEventManager;
use crate::events::SimpleEventManager; use crate::events::SimpleEventManager;
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use crate::monitors::pybind::PythonMonitor; use crate::monitors::pybind::PythonMonitor;
@ -438,7 +441,7 @@ pub mod pybind {
/// Python class for SimpleEventManager /// Python class for SimpleEventManager
pub struct PythonSimpleEventManager { pub struct PythonSimpleEventManager {
/// Rust wrapped SimpleEventManager object /// Rust wrapped SimpleEventManager object
pub simple_event_manager: SimpleEventManager<BytesInput, PythonMonitor>, pub inner: SimpleEventManager<BytesInput, PythonMonitor>,
} }
#[pymethods] #[pymethods]
@ -446,9 +449,13 @@ pub mod pybind {
#[new] #[new]
fn new(py_monitor: PythonMonitor) -> Self { fn new(py_monitor: PythonMonitor) -> Self {
Self { Self {
simple_event_manager: SimpleEventManager::new(py_monitor), inner: SimpleEventManager::new(py_monitor),
} }
} }
fn as_manager(slf: Py<Self>) -> PythonEventManager {
PythonEventManager::new_simple(slf)
}
} }
/// Register the classes to the python module /// Register the classes to the python module

View File

@ -1673,153 +1673,66 @@ mod tests {
} }
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
/// `InProcess` Python bindings /// `InProcess` Python bindings
pub mod pybind { pub mod pybind {
use crate::bolts::tuples::tuple_list; use crate::events::pybind::PythonEventManager;
use crate::executors::pybind::PythonExecutor;
use crate::executors::{inprocess::OwnedInProcessExecutor, ExitKind}; use crate::executors::{inprocess::OwnedInProcessExecutor, ExitKind};
use crate::fuzzer::pybind::PythonStdFuzzerWrapper;
use crate::inputs::{BytesInput, HasBytesVec}; use crate::inputs::{BytesInput, HasBytesVec};
use crate::observers::pybind::PythonObserversTuple;
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper};
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyBytes; use pyo3::types::PyBytes;
macro_rules! define_python_in_process_executor { #[pyclass(unsendable, name = "InProcessExecutor")]
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $std_state_name: ident, $event_manager_name: ident, $observer_name: ident, $std_fuzzer_name: ident) => { #[derive(Debug)]
use crate::events::pybind::$event_manager_name; /// Python class for OwnedInProcessExecutor (i.e. InProcessExecutor with owned harness)
use crate::fuzzer::pybind::$std_fuzzer_name; pub struct PythonOwnedInProcessExecutor {
use crate::observers::map::pybind::$observer_name; /// Rust wrapped OwnedInProcessExecutor object
use crate::state::pybind::{$my_std_state_type_name, $std_state_name}; pub inner: OwnedInProcessExecutor<BytesInput, PythonObserversTuple, PythonStdState>,
#[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,
($observer_name, ()),
$my_std_state_type_name,
>,
}
#[pymethods]
impl $struct_name {
#[new]
fn new(
harness: PyObject,
py_observer: $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!( #[pymethods]
PythonOwnedInProcessExecutor, impl PythonOwnedInProcessExecutor {
"OwnedInProcessExecutor", #[new]
PythonStdState, fn new(
PythonStdStateI8, harness: PyObject,
PythonEventManagerI8, py_observers: PythonObserversTuple,
PythonMapObserverI8, py_fuzzer: &mut PythonStdFuzzerWrapper,
PythonStdFuzzerI8 py_state: &mut PythonStdStateWrapper,
); py_event_manager: &mut PythonEventManager,
) -> Self {
Self {
inner: 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
}),
py_observers,
py_fuzzer.unwrap_mut(),
py_state.unwrap_mut(),
py_event_manager,
)
.expect("Failed to create the Executor"),
}
}
define_python_in_process_executor!( #[must_use]
PythonOwnedInProcessExecutorI16, pub fn as_executor(slf: Py<Self>) -> PythonExecutor {
"OwnedInProcessExecutorI16", PythonExecutor::new_inprocess(slf)
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 /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonOwnedInProcessExecutorI8>()?; m.add_class::<PythonOwnedInProcessExecutor>()?;
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(()) Ok(())
} }
} }

View File

@ -186,127 +186,253 @@ mod test {
} }
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
/// `Executor` Python bindings /// `Executor` Python bindings
pub mod pybind { pub mod pybind {
use crate::events::pybind::PythonEventManager;
use crate::executors::inprocess::pybind::PythonOwnedInProcessExecutor;
use crate::executors::{Executor, ExitKind, HasObservers}; use crate::executors::{Executor, ExitKind, HasObservers};
use crate::inputs::BytesInput; use crate::fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper};
use crate::inputs::{BytesInput, HasBytesVec};
use crate::observers::pybind::PythonObserversTuple;
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper};
use crate::Error; use crate::Error;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
macro_rules! define_python_executor { #[pyclass(unsendable, name = "ExitKind")]
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident, #[derive(Clone, Debug, Serialize, Deserialize)]
$event_manager_name: ident, $in_process_executor_name: ident, $observer_name: ident) => { pub struct PythonExitKind {
use crate::events::pybind::$event_manager_name; pub inner: ExitKind,
use crate::executors::inprocess::pybind::$in_process_executor_name; }
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
use crate::observers::pybind::$observer_name;
use crate::state::pybind::$my_std_state_type_name;
#[derive(Debug)] impl From<ExitKind> for PythonExitKind {
enum $wrapper_name { fn from(inner: ExitKind) -> Self {
OwnedInProcess(*mut $in_process_executor_name), Self { inner }
}
}
#[pymethods]
impl PythonExitKind {
fn __eq__(&self, other: &PythonExitKind) -> bool {
self.inner == other.inner
}
#[must_use]
fn is_ok(&self) -> bool {
self.inner == ExitKind::Ok
}
#[must_use]
fn is_crash(&self) -> bool {
self.inner == ExitKind::Crash
}
#[must_use]
fn is_oom(&self) -> bool {
self.inner == ExitKind::Oom
}
#[must_use]
fn is_timeout(&self) -> bool {
self.inner == ExitKind::Timeout
}
#[staticmethod]
#[must_use]
fn ok() -> Self {
Self {
inner: ExitKind::Ok,
} }
}
#[pyclass(unsendable, name = $py_name_trait)] #[staticmethod]
#[derive(Debug)] #[must_use]
/// Executor + HasObservers Trait binding fn crash() -> Self {
pub struct $struct_name_trait { Self {
wrapper: $wrapper_name, inner: ExitKind::Crash,
} }
}
impl $struct_name_trait { #[staticmethod]
fn unwrap( #[must_use]
&self, fn oom() -> Self {
) -> &(impl Executor< Self {
$event_manager_name, inner: ExitKind::Oom,
BytesInput, }
$my_std_state_type_name, }
$my_std_fuzzer_type_name,
> + HasObservers<BytesInput, ($observer_name, ()), $my_std_state_type_name>) { #[staticmethod]
unsafe { #[must_use]
match self.wrapper { fn timeout() -> Self {
$wrapper_name::OwnedInProcess(py_wrapper) => &(*py_wrapper).upcast(), Self {
} inner: ExitKind::Timeout,
}
}
}
#[derive(Clone, Debug)]
pub struct PyObjectExecutor {
inner: PyObject,
tuple: PythonObserversTuple,
}
impl PyObjectExecutor {
#[must_use]
pub fn new(obj: PyObject) -> Self {
let tuple = Python::with_gil(|py| -> PyResult<PythonObserversTuple> {
obj.call_method1(py, "observers", ())?.extract(py)
})
.unwrap();
PyObjectExecutor { inner: obj, tuple }
}
}
impl HasObservers<BytesInput, PythonObserversTuple, PythonStdState> for PyObjectExecutor {
#[inline]
fn observers(&self) -> &PythonObserversTuple {
&self.tuple
}
#[inline]
fn observers_mut(&mut self) -> &mut PythonObserversTuple {
&mut self.tuple
}
}
impl Executor<PythonEventManager, BytesInput, PythonStdState, PythonStdFuzzer>
for PyObjectExecutor
{
#[inline]
fn run_target(
&mut self,
fuzzer: &mut PythonStdFuzzer,
state: &mut PythonStdState,
mgr: &mut PythonEventManager,
input: &BytesInput,
) -> Result<ExitKind, Error> {
let ek = Python::with_gil(|py| -> PyResult<_> {
let ek: PythonExitKind = self
.inner
.call_method1(
py,
"run_target",
(
PythonStdFuzzerWrapper::wrap(fuzzer),
PythonStdStateWrapper::wrap(state),
mgr.clone(),
input.bytes(),
),
)?
.extract(py)?;
Ok(ek)
})?;
Ok(ek.inner)
}
}
#[derive(Clone, Debug)]
enum PythonExecutorWrapper {
InProcess(Py<PythonOwnedInProcessExecutor>),
Python(PyObjectExecutor),
}
#[pyclass(unsendable, name = "Executor")]
#[derive(Clone, Debug)]
/// Executor + HasObservers Trait binding
pub struct PythonExecutor {
wrapper: PythonExecutorWrapper,
}
macro_rules! unwrap_me {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_body!($wrapper, $name, $body, PythonExecutorWrapper,
{ InProcess },
{
Python(py_wrapper) => {
let $name = py_wrapper;
$body
} }
} }
)
fn unwrap_mut(
&mut self,
) -> &mut (impl Executor<
$event_manager_name,
BytesInput,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
> + HasObservers<BytesInput, ($observer_name, ()), $my_std_state_type_name>) {
unsafe {
match self.wrapper {
$wrapper_name::OwnedInProcess(py_wrapper) => {
&mut (*py_wrapper).upcast_mut()
}
}
}
}
}
#[pymethods]
impl $struct_name_trait {
#[staticmethod]
fn new_from_inprocess(
owned_inprocess_executor: &mut $in_process_executor_name,
) -> Self {
Self {
wrapper: $wrapper_name::OwnedInProcess(owned_inprocess_executor),
}
}
}
impl<I, S> HasObservers<I, ($observer_name, ()), S> for $struct_name_trait {
// #[inline]
fn observers(&self) -> &($observer_name, ()) {
self.unwrap().observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut ($observer_name, ()) {
self.unwrap_mut().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.unwrap_mut().run_target(fuzzer, state, mgr, input)
}
}
}; };
} }
define_python_executor!( macro_rules! unwrap_me_mut {
PythonExecutor, ($wrapper:expr, $name:ident, $body:block) => {
"Executor", crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonExecutorWrapper,
PythonExecutorWrapper, { InProcess },
PythonStdState, {
PythonStdFuzzer, Python(py_wrapper) => {
PythonEventManager, let $name = py_wrapper;
PythonOwnedInProcessExecutor, $body
PythonObserver }
); }
)
};
}
#[pymethods]
impl PythonExecutor {
#[staticmethod]
#[must_use]
pub fn new_inprocess(owned_inprocess_executor: Py<PythonOwnedInProcessExecutor>) -> Self {
Self {
wrapper: PythonExecutorWrapper::InProcess(owned_inprocess_executor),
}
}
#[staticmethod]
#[must_use]
pub fn new_py(obj: PyObject) -> Self {
Self {
wrapper: PythonExecutorWrapper::Python(PyObjectExecutor::new(obj)),
}
}
#[must_use]
pub fn unwrap_py(&self) -> Option<PyObject> {
match &self.wrapper {
PythonExecutorWrapper::Python(pyo) => Some(pyo.inner.clone()),
PythonExecutorWrapper::InProcess(_) => None,
}
}
}
impl HasObservers<BytesInput, PythonObserversTuple, PythonStdState> for PythonExecutor {
#[inline]
fn observers(&self) -> &PythonObserversTuple {
let ptr = unwrap_me!(self.wrapper, e, {
e.observers() as *const PythonObserversTuple
});
unsafe { ptr.as_ref().unwrap() }
}
#[inline]
fn observers_mut(&mut self) -> &mut PythonObserversTuple {
let ptr = unwrap_me_mut!(self.wrapper, e, {
e.observers_mut() as *mut PythonObserversTuple
});
unsafe { ptr.as_mut().unwrap() }
}
}
impl Executor<PythonEventManager, BytesInput, PythonStdState, PythonStdFuzzer> for PythonExecutor {
#[inline]
fn run_target(
&mut self,
fuzzer: &mut PythonStdFuzzer,
state: &mut PythonStdState,
mgr: &mut PythonEventManager,
input: &BytesInput,
) -> Result<ExitKind, Error> {
unwrap_me_mut!(self.wrapper, e, { e.run_target(fuzzer, state, mgr, input) })
}
}
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonExitKind>()?;
m.add_class::<PythonExecutor>()?; m.add_class::<PythonExecutor>()?;
Ok(()) Ok(())
} }

View File

@ -666,451 +666,117 @@ mod tests {
/// `MapFeedback` Python bindings /// `MapFeedback` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::bolts::{tuples::Named, AsMutIterator, AsRefIterator, HasLen}; use super::{Debug, HasObserverName, MaxMapFeedback};
use crate::observers::{map::OwnedMapObserver, MapObserver, Observer}; use crate::feedbacks::pybind::PythonFeedback;
use crate::Error; use crate::inputs::BytesInput;
use crate::state::pybind::PythonStdState;
use concat_idents::concat_idents;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use std::slice::{Iter, IterMut};
macro_rules! define_python_map_observer { macro_rules! define_python_map_feedback {
($struct_name:ident, $py_name:tt, $struct_name_trait:ident, $py_name_trait:tt, $datatype:ty, $wrapper_name: ident) => { ($struct_name:ident, $py_name:tt, $datatype:ty, $map_observer_type_name: ident, $my_std_state_type_name: ident) => {
use crate::observers::map::pybind::$map_observer_type_name;
#[pyclass(unsendable, name = $py_name)] #[pyclass(unsendable, name = $py_name)]
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Debug, Clone)]
/// Python class for OwnedMapObserver (i.e. StdMapObserver with owned map) /// Python class for MaxMapFeedback
pub struct $struct_name { pub struct $struct_name {
/// Rust wrapped OwnedMapObserver object /// Rust wrapped MaxMapFeedback object
pub inner: OwnedMapObserver<$datatype>, pub inner: MaxMapFeedback<
BytesInput,
$map_observer_type_name, /* PythonMapObserverI8 */
$my_std_state_type_name,
$datatype,
>,
} }
#[pymethods] #[pymethods]
impl $struct_name { impl $struct_name {
#[new] #[new]
fn new(name: String, map: Vec<$datatype>) -> Self { fn new(observer: &$map_observer_type_name) -> Self {
Self { Self {
//TODO: Not leak memory inner: MaxMapFeedback::new(observer),
inner: OwnedMapObserver::new(Box::leak(name.into_boxed_str()), map),
} }
} }
#[must_use]
pub fn as_feedback(slf: Py<Self>) -> PythonFeedback {
concat_idents!(func = new_max_map_,$datatype {
PythonFeedback::func(slf)
})
}
} }
#[derive(Serialize, Deserialize, Debug, Clone)] impl HasObserverName for $struct_name {
enum $wrapper_name { fn observer_name(&self) -> &str {
Owned($struct_name), self.inner.observer_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 {
pub wrapper: $wrapper_name,
}
impl $struct_name_trait {
fn unwrap(&self) -> &impl MapObserver<Entry = $datatype> {
unsafe {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => &py_wrapper.inner,
}
}
}
fn unwrap_mut(&mut self) -> &mut impl MapObserver<Entry = $datatype> {
unsafe {
match &mut self.wrapper {
$wrapper_name::Owned(py_wrapper) => &mut py_wrapper.inner,
}
}
}
fn upcast<S>(&self) -> &impl Observer<BytesInput, S> {
unsafe {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => &py_wrapper.inner,
}
}
}
fn upcast_mut<S>(&mut self) -> &mut impl Observer<BytesInput, S> {
unsafe {
match &mut self.wrapper {
$wrapper_name::Owned(py_wrapper) => &mut py_wrapper.inner,
}
}
}
}
#[pymethods]
impl $struct_name_trait {
#[staticmethod]
fn new_from_owned(owned_map: $struct_name) -> Self {
Self {
wrapper: $wrapper_name::Owned(owned_map),
}
}
}
impl<'it> AsRefIterator<'it> for $struct_name_trait {
type Item = $datatype;
type IntoIter = Iter<'it, $datatype>;
fn as_ref_iter(&'it self) -> Self::IntoIter {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.as_ref_iter(),
}
}
}
impl<'it> AsMutIterator<'it> for $struct_name_trait {
type Item = $datatype;
type IntoIter = IterMut<'it, $datatype>;
fn as_mut_iter(&'it mut self) -> Self::IntoIter {
match &mut self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.as_mut_iter(),
}
}
}
impl MapObserver for $struct_name_trait {
type Entry = $datatype;
#[inline]
fn get(&self, idx: usize) -> &$datatype {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => &py_wrapper.inner.get(idx),
}
}
#[inline]
fn get_mut(&mut self, idx: usize) -> &mut $datatype {
match &mut self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.get_mut(idx),
}
}
#[inline]
fn usable_count(&self) -> usize {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.wrapper.usable_count(),
}
}
fn hash(&self) -> u64 {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.hash(),
}
}
#[inline]
fn initial(&self) -> $datatype {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.initial(),
}
}
#[inline]
fn initial_mut(&mut self) -> &mut $datatype {
match &mut self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.initial_mut(),
}
}
#[inline]
fn set_initial(&mut self, initial: $datatype) {
match &mut self.wrapper {
$wrapper_name::Owned(py_wrapper) => {
py_wrapper.inner.set_initial(initial);
}
}
}
fn to_vec(&self) -> Vec<$datatype> {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.to_vec(),
}
}
}
impl Named for $struct_name_trait {
#[inline]
fn name(&self) -> &str {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.name(),
}
}
}
impl HasLen for $struct_name_trait {
#[inline]
fn len(&self) -> usize {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.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.wrapper {
$wrapper_name::Owned(py_wrapper) => {
py_wrapper.inner.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(())
}
}
#[cfg(feature = "python")]
/// Map Feedback Python bindings
pub mod pybind {
use crate::feedbacks::map::{MapFeedbackMetadata, 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 MapFeedbackMetadata
pub struct $map_feedback_state_struct_name {
/// Rust wrapped MapFeedbackMetadata object
pub map_feedback_state: MapFeedbackMetadata<$datatype>,
}
#[pymethods]
impl $map_feedback_state_struct_name {
#[staticmethod]
fn with_observer(py_observer: &$map_observer_name) -> Self {
Self {
map_feedback_state: MapFeedbackMetadata::with_observer(py_observer),
}
}
}
#[pyclass(unsendable, name = $max_map_feedback_py_name)]
#[derive(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>,
}
impl Clone for $max_map_feedback_struct_name {
fn clone(&self) -> Self {
Self {
max_map_feedback: self.max_map_feedback.clone(),
}
}
}
#[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!( define_python_map_feedback!(
PythonMapFeedbackMetadataI8,
"MapFeedbackMetadataI8",
PythonMaxMapFeedbackI8, PythonMaxMapFeedbackI8,
"MaxMapFeedbackI8", "MaxMapFeedbackI8",
i8, i8,
PythonMapObserverI8, PythonMapObserverI8,
MyStdStateI8 PythonStdState
); );
define_python_map_feedback!( define_python_map_feedback!(
PythonMapFeedbackMetadataI16,
"MapFeedbackMetadataI16",
PythonMaxMapFeedbackI16, PythonMaxMapFeedbackI16,
"MaxMapFeedbackI16", "MaxMapFeedbackI16",
i16, i16,
PythonMapObserverI16, PythonMapObserverI16,
MyStdStateI16 PythonStdState
); );
define_python_map_feedback!( define_python_map_feedback!(
PythonMapFeedbackMetadataI32,
"MapFeedbackMetadataI32",
PythonMaxMapFeedbackI32, PythonMaxMapFeedbackI32,
"MaxMapFeedbackI32", "MaxMapFeedbackI32",
i32, i32,
PythonMapObserverI32, PythonMapObserverI32,
MyStdStateI32 PythonStdState
); );
define_python_map_feedback!( define_python_map_feedback!(
PythonMapFeedbackMetadataI64,
"MapFeedbackMetadataI64",
PythonMaxMapFeedbackI64, PythonMaxMapFeedbackI64,
"MaxMapFeedbackI64", "MaxMapFeedbackI64",
i64, i64,
PythonMapObserverI64, PythonMapObserverI64,
MyStdStateI64 PythonStdState
); );
define_python_map_feedback!( define_python_map_feedback!(
PythonMapFeedbackMetadataU8,
"MapFeedbackMetadataU8",
PythonMaxMapFeedbackU8, PythonMaxMapFeedbackU8,
"MaxMapFeedbackU8", "MaxMapFeedbackU8",
u8, u8,
PythonMapObserverU8, PythonMapObserverU8,
MyStdStateU8 PythonStdState
); );
define_python_map_feedback!( define_python_map_feedback!(
PythonMapFeedbackMetadataU16,
"MapFeedbackMetadataU16",
PythonMaxMapFeedbackU16, PythonMaxMapFeedbackU16,
"MaxMapFeedbackU16", "MaxMapFeedbackU16",
u16, u16,
PythonMapObserverU16, PythonMapObserverU16,
MyStdStateU16 PythonStdState
); );
define_python_map_feedback!( define_python_map_feedback!(
PythonMapFeedbackMetadataU32,
"MapFeedbackMetadataU32",
PythonMaxMapFeedbackU32, PythonMaxMapFeedbackU32,
"MaxMapFeedbackU32", "MaxMapFeedbackU32",
u32, u32,
PythonMapObserverU32, PythonMapObserverU32,
MyStdStateU32 PythonStdState
); );
define_python_map_feedback!( define_python_map_feedback!(
PythonMapFeedbackMetadataU64,
"MapFeedbackMetadataU64",
PythonMaxMapFeedbackU64, PythonMaxMapFeedbackU64,
"MaxMapFeedbackU64", "MaxMapFeedbackU64",
u64, u64,
PythonMapObserverU64, PythonMapObserverU64,
MyStdStateU64 PythonStdState
); );
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonMapFeedbackMetadataI8>()?;
m.add_class::<PythonMapFeedbackMetadataI16>()?;
m.add_class::<PythonMapFeedbackMetadataI32>()?;
m.add_class::<PythonMapFeedbackMetadataI64>()?;
m.add_class::<PythonMapFeedbackMetadataU8>()?;
m.add_class::<PythonMapFeedbackMetadataU16>()?;
m.add_class::<PythonMapFeedbackMetadataU32>()?;
m.add_class::<PythonMapFeedbackMetadataU64>()?;
m.add_class::<PythonMaxMapFeedbackI8>()?; m.add_class::<PythonMaxMapFeedbackI8>()?;
m.add_class::<PythonMaxMapFeedbackI16>()?; m.add_class::<PythonMaxMapFeedbackI16>()?;
m.add_class::<PythonMaxMapFeedbackI32>()?; m.add_class::<PythonMaxMapFeedbackI32>()?;

View File

@ -1038,112 +1038,577 @@ impl From<bool> for ConstFeedback {
/// `Feedback` Python bindings /// `Feedback` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::inputs::BytesInput; use super::{
ConstFeedback, CrashFeedback, Debug, EagerAndFeedback, EagerOrFeedback, FastAndFeedback,
FastOrFeedback, Feedback, NotFeedback, String, ToString,
};
use crate::corpus::testcase::pybind::{PythonTestcase, PythonTestcaseWrapper};
use crate::events::pybind::PythonEventManager;
use crate::executors::pybind::PythonExitKind;
use crate::feedbacks::map::pybind::{
PythonMaxMapFeedbackI16, PythonMaxMapFeedbackI32, PythonMaxMapFeedbackI64,
PythonMaxMapFeedbackI8, PythonMaxMapFeedbackU16, PythonMaxMapFeedbackU32,
PythonMaxMapFeedbackU64, PythonMaxMapFeedbackU8,
};
use crate::inputs::HasBytesVec;
use crate::observers::pybind::PythonObserversTuple;
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper};
use crate::{ use crate::{
bolts::tuples::Named, corpus::Testcase, events::EventFirer, executors::ExitKind, bolts::tuples::Named, corpus::Testcase, events::EventFirer, executors::ExitKind,
feedbacks::Feedback, observers::ObserversTuple, Error, inputs::BytesInput, observers::ObserversTuple, Error,
}; };
use pyo3::prelude::*; use pyo3::prelude::*;
use std::cell::UnsafeCell;
macro_rules! define_python_feedback { #[derive(Debug)]
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $my_std_state_type_name: ident) => { pub struct PyObjectFeedback {
use crate::observers::map::pybind::PythonMaxMapFeedbackI8; inner: PyObject,
use crate::state::pybind::$my_std_state_type_name; name: UnsafeCell<String>,
}
#[derive(Debug)] impl Clone for PyObjectFeedback {
enum $wrapper_name { fn clone(&self) -> PyObjectFeedback {
MaxMapI8(*mut PythonMaxMapFeedbackI8), PyObjectFeedback {
inner: self.inner.clone(),
name: UnsafeCell::new(String::new()),
} }
}
}
#[pyclass(unsendable, name = $py_name_trait)] impl PyObjectFeedback {
#[derive(Debug)] #[must_use]
/// Observer Trait binding pub fn new(obj: PyObject) -> Self {
pub struct $struct_name_trait { PyObjectFeedback {
pub wrapper: $wrapper_name, inner: obj,
name: UnsafeCell::new(String::new()),
} }
}
}
impl $struct_name_trait { // crate::impl_serde_pyobjectwrapper!(PyObjectObserver, inner);
fn unwrap(&self) -> &impl Feedback<BytesInput, $my_std_state_type_name> {
unsafe {
match self.wrapper {
$wrapper_name::MaxMapI8(py_wrapper) => &(*py_wrapper).upcast(),
}
}
}
fn unwrap_mut( impl Named for PyObjectFeedback {
&mut self, fn name(&self) -> &str {
) -> &mut impl Feedback<BytesInput, $my_std_state_type_name> { let s = Python::with_gil(|py| -> PyResult<String> {
unsafe { let s: String = self.inner.call_method0(py, "name")?.extract(py)?;
match self.wrapper { Ok(s)
$wrapper_name::MaxMapI8(py_wrapper) => &mut (*py_wrapper).upcast_mut(), })
} .unwrap();
} unsafe {
} *self.name.get() = s;
&*self.name.get()
}
}
}
impl Feedback<BytesInput, PythonStdState> for PyObjectFeedback {
fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner
.call_method1(py, "init_state", (PythonStdStateWrapper::wrap(state),))?;
Ok(())
})?;
Ok(())
}
fn is_interesting<EM, OT>(
&mut self,
state: &mut PythonStdState,
manager: &mut EM,
input: &BytesInput,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<BytesInput>,
OT: ObserversTuple<BytesInput, PythonStdState>,
{
// SAFETY: We use this observer in Python ony when the ObserverTuple is PythonObserversTuple
let dont_look_at_this: &PythonObserversTuple =
unsafe { &*(observers as *const OT as *const PythonObserversTuple) };
let dont_look_at_this2: &PythonEventManager =
unsafe { &*(manager as *mut EM as *const PythonEventManager) };
Ok(Python::with_gil(|py| -> PyResult<bool> {
let r: bool = self
.inner
.call_method1(
py,
"is_interesting",
(
PythonStdStateWrapper::wrap(state),
dont_look_at_this2.clone(),
input.bytes(),
dont_look_at_this.clone(),
PythonExitKind::from(*exit_kind),
),
)?
.extract(py)?;
Ok(r)
})?)
}
fn append_metadata(
&mut self,
state: &mut PythonStdState,
testcase: &mut PythonTestcase,
) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method1(
py,
"append_metadata",
(
PythonStdStateWrapper::wrap(state),
PythonTestcaseWrapper::wrap(testcase),
),
)?;
Ok(())
})?;
Ok(())
}
fn discard_metadata(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method1(
py,
"discard_metadata",
(PythonStdStateWrapper::wrap(state), input.bytes()),
)?;
Ok(())
})?;
Ok(())
}
}
#[derive(Clone, Debug)]
#[pyclass(unsendable, name = "CrashFeedback")]
pub struct PythonCrashFeedback {
pub inner: CrashFeedback,
}
#[pymethods]
impl PythonCrashFeedback {
#[new]
fn new() -> Self {
Self {
inner: CrashFeedback::new(),
}
}
#[must_use]
pub fn as_feedback(slf: Py<Self>) -> PythonFeedback {
PythonFeedback::new_crash(slf)
}
}
#[derive(Clone, Debug)]
#[pyclass(unsendable, name = "ConstFeedback")]
pub struct PythonConstFeedback {
pub inner: ConstFeedback,
}
#[pymethods]
impl PythonConstFeedback {
#[new]
fn new(v: bool) -> Self {
Self {
inner: ConstFeedback::new(v),
}
}
#[must_use]
pub fn as_feedback(slf: Py<Self>) -> PythonFeedback {
PythonFeedback::new_const(slf)
}
}
#[derive(Debug)]
#[pyclass(unsendable, name = "NotFeedback")]
pub struct PythonNotFeedback {
pub inner: NotFeedback<PythonFeedback, BytesInput, PythonStdState>,
}
#[pymethods]
impl PythonNotFeedback {
#[new]
fn new(feedback: PythonFeedback) -> Self {
Self {
inner: NotFeedback::new(feedback),
}
}
#[must_use]
pub fn as_feedback(slf: Py<Self>) -> PythonFeedback {
PythonFeedback::new_not(slf)
}
}
macro_rules! define_combined {
($feed:ident, $pyname:ident, $pystring:tt, $method:ident) => {
#[derive(Debug)]
#[pyclass(unsendable, name = $pystring)]
pub struct $pyname {
pub inner: $feed<PythonFeedback, PythonFeedback, BytesInput, PythonStdState>,
} }
#[pymethods] #[pymethods]
impl $struct_name_trait { impl $pyname {
#[staticmethod] #[new]
fn new_map(map_feedback: &mut PythonMaxMapFeedbackI8) -> Self { fn new(a: PythonFeedback, b: PythonFeedback) -> Self {
Self { Self {
observer: $wrapper_name::MaxMapI8(map_feedback), inner: $feed::new(a, b),
} }
} }
}
impl Named for $struct_name_trait { #[must_use]
fn name(&self) -> &str { pub fn as_feedback(slf: Py<Self>) -> PythonFeedback {
self.unwrap().name() PythonFeedback::$method(slf)
}
}
impl Feedback<BytesInput, $my_std_state_type_name> for $struct_name_trait {
fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
self.unwrap_mut().init_state(state)
}
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &I,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<I>,
OT: ObserversTuple<I, S>,
{
self.unwrap_mut()
.is_interesting(state, manager, input, observers, exit_kind)
}
fn append_metadata(
&mut self,
state: &mut S,
testcase: &mut Testcase<I>,
) -> Result<(), Error> {
self.unwrap_mut().append_metadata(state, testcase)
}
fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
self.unwrap_mut().discard_metadata(state, input)
} }
} }
}; };
} }
define_python_feedback!( define_combined!(
PythonFeedback, EagerAndFeedback,
"Feedback", PythonEagerAndFeedback,
PythonFeedbackWrapper, "EagerAndFeedback",
PythonStdState, new_and
); );
define_combined!(
FastAndFeedback,
PythonFastAndFeedback,
"FastAndFeedback",
new_fast_and
);
define_combined!(
EagerOrFeedback,
PythonEagerOrFeedback,
"EagerOrFeedback",
new_or
);
define_combined!(
FastOrFeedback,
PythonFastOrFeedback,
"FastOrFeedback",
new_fast_or
);
#[derive(Clone, Debug)]
pub enum PythonFeedbackWrapper {
MaxMapI8(Py<PythonMaxMapFeedbackI8>),
MaxMapI16(Py<PythonMaxMapFeedbackI16>),
MaxMapI32(Py<PythonMaxMapFeedbackI32>),
MaxMapI64(Py<PythonMaxMapFeedbackI64>),
MaxMapU8(Py<PythonMaxMapFeedbackU8>),
MaxMapU16(Py<PythonMaxMapFeedbackU16>),
MaxMapU32(Py<PythonMaxMapFeedbackU32>),
MaxMapU64(Py<PythonMaxMapFeedbackU64>),
Crash(Py<PythonCrashFeedback>),
Const(Py<PythonConstFeedback>),
Not(Py<PythonNotFeedback>),
And(Py<PythonEagerAndFeedback>),
FastAnd(Py<PythonFastAndFeedback>),
Or(Py<PythonEagerOrFeedback>),
FastOr(Py<PythonFastOrFeedback>),
Python(PyObjectFeedback),
}
#[pyclass(unsendable, name = "Feedback")]
#[derive(Debug)]
/// Observer Trait binding
pub struct PythonFeedback {
pub wrapper: PythonFeedbackWrapper,
name: UnsafeCell<String>,
}
macro_rules! unwrap_me {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_body!($wrapper, $name, $body, PythonFeedbackWrapper,
{
MaxMapI8,
MaxMapI16,
MaxMapI32,
MaxMapI64,
MaxMapU8,
MaxMapU16,
MaxMapU32,
MaxMapU64,
Crash,
Const,
Not,
And,
FastAnd,
Or,
FastOr
},
{
Python(py_wrapper) => {
let $name = py_wrapper;
$body
}
}
)
};
}
macro_rules! unwrap_me_mut {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonFeedbackWrapper,
{
MaxMapI8,
MaxMapI16,
MaxMapI32,
MaxMapI64,
MaxMapU8,
MaxMapU16,
MaxMapU32,
MaxMapU64,
Crash,
Const,
Not,
And,
FastAnd,
Or,
FastOr
},
{
Python(py_wrapper) => {
let $name = py_wrapper;
$body
}
}
)
};
}
impl Clone for PythonFeedback {
fn clone(&self) -> PythonFeedback {
PythonFeedback {
wrapper: self.wrapper.clone(),
name: UnsafeCell::new(String::new()),
}
}
}
#[pymethods]
impl PythonFeedback {
#[staticmethod]
#[must_use]
pub fn new_max_map_i8(map_feedback: Py<PythonMaxMapFeedbackI8>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::MaxMapI8(map_feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_max_map_i16(map_feedback: Py<PythonMaxMapFeedbackI16>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::MaxMapI16(map_feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_max_map_i32(map_feedback: Py<PythonMaxMapFeedbackI32>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::MaxMapI32(map_feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_max_map_i64(map_feedback: Py<PythonMaxMapFeedbackI64>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::MaxMapI64(map_feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_max_map_u8(map_feedback: Py<PythonMaxMapFeedbackU8>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::MaxMapU8(map_feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_max_map_u16(map_feedback: Py<PythonMaxMapFeedbackU16>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::MaxMapU16(map_feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_max_map_u32(map_feedback: Py<PythonMaxMapFeedbackU32>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::MaxMapU32(map_feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_max_map_u64(map_feedback: Py<PythonMaxMapFeedbackU64>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::MaxMapU64(map_feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_crash(feedback: Py<PythonCrashFeedback>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::Crash(feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_const(feedback: Py<PythonConstFeedback>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::Const(feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_not(feedback: Py<PythonNotFeedback>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::Not(feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_and(feedback: Py<PythonEagerAndFeedback>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::And(feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_fast_and(feedback: Py<PythonFastAndFeedback>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::FastAnd(feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_or(feedback: Py<PythonEagerOrFeedback>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::Or(feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_fast_or(feedback: Py<PythonFastOrFeedback>) -> Self {
Self {
wrapper: PythonFeedbackWrapper::FastOr(feedback),
name: UnsafeCell::new(String::new()),
}
}
#[staticmethod]
#[must_use]
pub fn new_py(obj: PyObject) -> Self {
Self {
wrapper: PythonFeedbackWrapper::Python(PyObjectFeedback::new(obj)),
name: UnsafeCell::new(String::new()),
}
}
pub fn unwrap_py(&self) -> Option<PyObject> {
match &self.wrapper {
PythonFeedbackWrapper::Python(pyo) => Some(pyo.inner.clone()),
_ => None,
}
}
}
impl Named for PythonFeedback {
fn name(&self) -> &str {
let s = unwrap_me!(self.wrapper, f, { f.name().to_string() });
unsafe {
*self.name.get() = s;
&*self.name.get()
}
}
}
impl Feedback<BytesInput, PythonStdState> for PythonFeedback {
fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, f, {
Feedback::<BytesInput, PythonStdState>::init_state(f, state)
})
}
fn is_interesting<EM, OT>(
&mut self,
state: &mut PythonStdState,
manager: &mut EM,
input: &BytesInput,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<BytesInput>,
OT: ObserversTuple<BytesInput, PythonStdState>,
{
unwrap_me_mut!(self.wrapper, f, {
f.is_interesting(state, manager, input, observers, exit_kind)
})
}
fn append_metadata(
&mut self,
state: &mut PythonStdState,
testcase: &mut Testcase<BytesInput>,
) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, f, { f.append_metadata(state, testcase) })
}
fn discard_metadata(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, f, { f.discard_metadata(state, input) })
}
}
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonCrashFeedback>()?;
m.add_class::<PythonConstFeedback>()?;
m.add_class::<PythonNotFeedback>()?;
m.add_class::<PythonEagerAndFeedback>()?;
m.add_class::<PythonFastAndFeedback>()?;
m.add_class::<PythonEagerOrFeedback>()?;
m.add_class::<PythonFastOrFeedback>()?;
m.add_class::<PythonFeedback>()?; m.add_class::<PythonFeedback>()?;
Ok(()) Ok(())
} }

View File

@ -669,197 +669,104 @@ where
} }
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
/// `Fuzzer` Python bindings /// `Fuzzer` Python bindings
pub mod pybind { pub mod pybind {
use crate::feedbacks::{CrashFeedback, MaxMapFeedback}; use crate::bolts::ownedref::OwnedPtrMut;
use crate::fuzzer::{Fuzzer, StdFuzzer}; use crate::events::pybind::PythonEventManager;
use crate::executors::pybind::PythonExecutor;
use crate::feedbacks::pybind::PythonFeedback;
use crate::fuzzer::{Evaluator, Fuzzer, StdFuzzer};
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use crate::observers::pybind::PythonObserversTuple;
use crate::schedulers::QueueScheduler; use crate::schedulers::QueueScheduler;
use crate::stages::pybind::PythonStagesTuple;
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper};
use pyo3::prelude::*; use pyo3::prelude::*;
macro_rules! define_python_fuzzer { /// `StdFuzzer` with fixed generics
($type_name:ident, $struct_name:ident, $py_name:tt, $datatype:ty, $my_std_state_type_name: ident, $std_state_name: ident, pub type PythonStdFuzzer = StdFuzzer<
$event_manager_name: ident, $map_observer_name: ident, $max_map_feedback_py_name: ident, $executor_name: ident, $stage_tuple_name: ident) => { QueueScheduler,
use crate::events::pybind::$event_manager_name; PythonFeedback,
use crate::executors::pybind::$executor_name; BytesInput,
use crate::feedbacks::map::pybind::$max_map_feedback_py_name; PythonFeedback,
use crate::observers::map::pybind::$map_observer_name; PythonObserversTuple,
use crate::stages::owned::pybind::$stage_tuple_name; PythonStdState,
use crate::state::pybind::{$my_std_state_type_name, $std_state_name}; >;
/// `StdFuzzer` with fixed generics /// Python class for StdFuzzer
pub type $type_name = StdFuzzer< #[pyclass(unsendable, name = "StdFuzzer")]
QueueScheduler, #[derive(Debug)]
MaxMapFeedback<BytesInput, $map_observer_name, $my_std_state_type_name, $datatype>, pub struct PythonStdFuzzerWrapper {
BytesInput, /// Rust wrapped StdFuzzer object
CrashFeedback, pub inner: OwnedPtrMut<PythonStdFuzzer>,
($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(
QueueScheduler::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!( impl PythonStdFuzzerWrapper {
MyStdFuzzerI8, pub fn wrap(r: &mut PythonStdFuzzer) -> Self {
PythonStdFuzzerI8, Self {
"StdFuzzerI8", inner: OwnedPtrMut::Ptr(r),
i8, }
MyStdStateI8, }
PythonStdStateI8,
PythonEventManagerI8,
PythonMapObserverI8,
PythonMaxMapFeedbackI8,
PythonExecutorI8,
PythonStagesOwnedListI8
);
define_python_fuzzer!( #[must_use]
MyStdFuzzerI16, pub fn unwrap(&self) -> &PythonStdFuzzer {
PythonStdFuzzerI16, self.inner.as_ref()
"StdFuzzerI16", }
i16,
MyStdStateI16,
PythonStdStateI16,
PythonEventManagerI16,
PythonMapObserverI16,
PythonMaxMapFeedbackI16,
PythonExecutorI16,
PythonStagesOwnedListI16
);
define_python_fuzzer!( pub fn unwrap_mut(&mut self) -> &mut PythonStdFuzzer {
MyStdFuzzerI32, self.inner.as_mut()
PythonStdFuzzerI32, }
"StdFuzzerI32", }
i32,
MyStdStateI32,
PythonStdStateI32,
PythonEventManagerI32,
PythonMapObserverI32,
PythonMaxMapFeedbackI32,
PythonExecutorI32,
PythonStagesOwnedListI32
);
define_python_fuzzer!( #[pymethods]
MyStdFuzzerI64, impl PythonStdFuzzerWrapper {
PythonStdFuzzerI64, #[new]
"StdFuzzerI64", fn new(py_feedback: PythonFeedback, py_objective: PythonFeedback) -> Self {
i64, Self {
MyStdStateI64, inner: OwnedPtrMut::Owned(Box::new(StdFuzzer::new(
PythonStdStateI64, QueueScheduler::new(),
PythonEventManagerI64, py_feedback,
PythonMapObserverI64, py_objective,
PythonMaxMapFeedbackI64, ))),
PythonExecutorI64, }
PythonStagesOwnedListI64 }
);
define_python_fuzzer!( fn add_input(
MyStdFuzzerU8, &mut self,
PythonStdFuzzerU8, py_state: &mut PythonStdStateWrapper,
"StdFuzzerU8", py_executor: &mut PythonExecutor,
u8, py_mgr: &mut PythonEventManager,
MyStdStateU8, input: Vec<u8>,
PythonStdStateU8, ) -> usize {
PythonEventManagerU8, self.inner
PythonMapObserverU8, .as_mut()
PythonMaxMapFeedbackU8, .add_input(
PythonExecutorU8, py_state.unwrap_mut(),
PythonStagesOwnedListU8 py_executor,
); py_mgr,
BytesInput::new(input),
)
.expect("Failed to add input")
}
define_python_fuzzer!( fn fuzz_loop(
MyStdFuzzerU16, &mut self,
PythonStdFuzzerU16, py_executor: &mut PythonExecutor,
"StdFuzzerU16", py_state: &mut PythonStdStateWrapper,
u16, py_mgr: &mut PythonEventManager,
MyStdStateU16, stages_tuple: &mut PythonStagesTuple,
PythonStdStateU16, ) {
PythonEventManagerU16, self.inner
PythonMapObserverU16, .as_mut()
PythonMaxMapFeedbackU16, .fuzz_loop(stages_tuple, py_executor, py_state.unwrap_mut(), py_mgr)
PythonExecutorU16, .expect("Failed to generate the initial corpus");
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 /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdFuzzerI8>()?; m.add_class::<PythonStdFuzzerWrapper>()?;
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(()) Ok(())
} }
} }

View File

@ -127,88 +127,199 @@ where
} }
/// `Generator` Python bindings /// `Generator` Python bindings
#[allow(missing_docs)]
#[cfg(feature = "python")] #[cfg(feature = "python")]
pub mod pybind { pub mod pybind {
use crate::generators::RandPrintablesGenerator; use crate::generators::{Generator, RandBytesGenerator, RandPrintablesGenerator};
use crate::inputs::{BytesInput, HasBytesVec};
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper};
use crate::Error;
use pyo3::prelude::*; use pyo3::prelude::*;
macro_rules! define_python_event_manager { #[derive(Clone, Debug)]
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident) => { pub struct PyObjectGenerator {
use crate::state::pybind::$my_std_state_type_name; inner: PyObject,
}
#[pyclass(unsendable, name = $py_name)] impl PyObjectGenerator {
/// Python class for RandPrintablesGenerator #[must_use]
#[derive(Debug)] pub fn new(obj: PyObject) -> Self {
pub struct $struct_name { PyObjectGenerator { inner: obj }
/// Rust wrapped SimpleEventManager object }
pub rand_printable_generator: RandPrintablesGenerator<$my_std_state_type_name>, }
impl Generator<BytesInput, PythonStdState> for PyObjectGenerator {
fn generate(&mut self, state: &mut PythonStdState) -> Result<BytesInput, Error> {
let bytes = Python::with_gil(|py| -> PyResult<Vec<u8>> {
self.inner
.call_method1(py, "generate", (PythonStdStateWrapper::wrap(state),))?
.extract(py)
})
.unwrap();
Ok(BytesInput::new(bytes))
}
fn generate_dummy(&self, state: &mut PythonStdState) -> BytesInput {
let bytes = Python::with_gil(|py| -> PyResult<Vec<u8>> {
self.inner
.call_method1(py, "generate_dummy", (PythonStdStateWrapper::wrap(state),))?
.extract(py)
})
.unwrap();
BytesInput::new(bytes)
}
}
#[pyclass(unsendable, name = "RandBytesGenerator")]
#[derive(Debug, Clone)]
/// Python class for RandBytesGenerator
pub struct PythonRandBytesGenerator {
/// Rust wrapped RandBytesGenerator object
pub inner: RandBytesGenerator<PythonStdState>,
}
#[pymethods]
impl PythonRandBytesGenerator {
#[new]
fn new(max_size: usize) -> Self {
Self {
inner: RandBytesGenerator::new(max_size),
} }
}
#[pymethods] fn generate(&mut self, state: &mut PythonStdStateWrapper) -> Vec<u8> {
impl $struct_name { self.inner
#[new] .generate(state.unwrap_mut())
fn new(max_size: usize) -> Self { .expect("PythonRandBytesGenerator::generate failed")
Self { .bytes()
rand_printable_generator: RandPrintablesGenerator::new(max_size), .to_vec()
}
fn as_generator(slf: Py<Self>) -> PythonGenerator {
PythonGenerator::new_rand_bytes(slf)
}
}
#[pyclass(unsendable, name = "RandPrintablesGenerator")]
#[derive(Debug, Clone)]
/// Python class for RandPrintablesGenerator
pub struct PythonRandPrintablesGenerator {
/// Rust wrapped RandPrintablesGenerator object
pub inner: RandPrintablesGenerator<PythonStdState>,
}
#[pymethods]
impl PythonRandPrintablesGenerator {
#[new]
fn new(max_size: usize) -> Self {
Self {
inner: RandPrintablesGenerator::new(max_size),
}
}
fn generate(&mut self, state: &mut PythonStdStateWrapper) -> Vec<u8> {
self.inner
.generate(state.unwrap_mut())
.expect("PythonRandPrintablesGenerator::generate failed")
.bytes()
.to_vec()
}
fn as_generator(slf: Py<Self>) -> PythonGenerator {
PythonGenerator::new_rand_printables(slf)
}
}
#[derive(Debug, Clone)]
enum PythonGeneratorWrapper {
RandBytes(Py<PythonRandBytesGenerator>),
RandPrintables(Py<PythonRandPrintablesGenerator>),
Python(PyObjectGenerator),
}
/// Rand Trait binding
#[pyclass(unsendable, name = "Generator")]
#[derive(Debug, Clone)]
pub struct PythonGenerator {
wrapper: PythonGeneratorWrapper,
}
macro_rules! unwrap_me {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_body!($wrapper, $name, $body, PythonGeneratorWrapper,
{ RandBytes, RandPrintables },
{
Python(py_wrapper) => {
let $name = py_wrapper;
$body
} }
} }
} )
}; };
} }
define_python_event_manager!( macro_rules! unwrap_me_mut {
PythonRandPrintablesGeneratorI8, ($wrapper:expr, $name:ident, $body:block) => {
"RandPrintablesGeneratorI8", crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonGeneratorWrapper,
MyStdStateI8 { RandBytes, RandPrintables },
); {
define_python_event_manager!( Python(py_wrapper) => {
PythonRandPrintablesGeneratorI16, let $name = py_wrapper;
"RandPrintablesGeneratorI16", $body
MyStdStateI16 }
); }
define_python_event_manager!( )
PythonRandPrintablesGeneratorI32, };
"RandPrintablesGeneratorI32", }
MyStdStateI32
);
define_python_event_manager!(
PythonRandPrintablesGeneratorI64,
"RandPrintablesGeneratorI64",
MyStdStateI64
);
define_python_event_manager!( #[pymethods]
PythonRandPrintablesGeneratorU8, impl PythonGenerator {
"RandPrintablesGeneratorU8", #[staticmethod]
MyStdStateU8 fn new_rand_bytes(py_gen: Py<PythonRandBytesGenerator>) -> Self {
); Self {
define_python_event_manager!( wrapper: PythonGeneratorWrapper::RandBytes(py_gen),
PythonRandPrintablesGeneratorU16, }
"RandPrintablesGeneratorU16", }
MyStdStateU16
); #[staticmethod]
define_python_event_manager!( fn new_rand_printables(py_gen: Py<PythonRandPrintablesGenerator>) -> Self {
PythonRandPrintablesGeneratorU32, Self {
"RandPrintablesGeneratorU32", wrapper: PythonGeneratorWrapper::RandPrintables(py_gen),
MyStdStateU32 }
); }
define_python_event_manager!(
PythonRandPrintablesGeneratorU64, #[staticmethod]
"RandPrintablesGeneratorU64", #[must_use]
MyStdStateU64 pub fn new_py(obj: PyObject) -> Self {
); Self {
wrapper: PythonGeneratorWrapper::Python(PyObjectGenerator::new(obj)),
}
}
#[must_use]
pub fn unwrap_py(&self) -> Option<PyObject> {
match &self.wrapper {
PythonGeneratorWrapper::Python(pyo) => Some(pyo.inner.clone()),
_ => None,
}
}
}
impl Generator<BytesInput, PythonStdState> for PythonGenerator {
fn generate(&mut self, state: &mut PythonStdState) -> Result<BytesInput, Error> {
unwrap_me_mut!(self.wrapper, g, { g.generate(state) })
}
fn generate_dummy(&self, state: &mut PythonStdState) -> BytesInput {
unwrap_me!(self.wrapper, g, { g.generate_dummy(state) })
}
}
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonRandPrintablesGeneratorI8>()?; m.add_class::<PythonRandBytesGenerator>()?;
m.add_class::<PythonRandPrintablesGeneratorI16>()?; m.add_class::<PythonRandPrintablesGenerator>()?;
m.add_class::<PythonRandPrintablesGeneratorI32>()?; m.add_class::<PythonGenerator>()?;
m.add_class::<PythonRandPrintablesGeneratorI64>()?;
m.add_class::<PythonRandPrintablesGeneratorU8>()?;
m.add_class::<PythonRandPrintablesGeneratorU16>()?;
m.add_class::<PythonRandPrintablesGeneratorU32>()?;
m.add_class::<PythonRandPrintablesGeneratorU64>()?;
Ok(()) Ok(())
} }
} }

View File

@ -371,6 +371,22 @@ impl From<TryFromSliceError> for Error {
} }
} }
#[cfg(feature = "python")]
impl From<pyo3::PyErr> for Error {
fn from(err: pyo3::PyErr) -> Self {
pyo3::Python::with_gil(|py| {
if err.matches(
py,
pyo3::types::PyType::new::<pyo3::exceptions::PyKeyboardInterrupt>(py),
) {
Self::shutting_down()
} else {
Self::illegal_state(format!("Python exception: {:?}", err))
}
})
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error {} impl std::error::Error for Error {}
@ -464,30 +480,180 @@ pub extern "C" fn external_current_millis() -> u64 {
} }
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::prelude::*; #[allow(missing_docs)]
pub mod pybind {
use super::{
bolts, corpus, events, executors, feedbacks, fuzzer, generators, monitors, mutators,
observers, stages, state,
};
use pyo3::prelude::*;
#[cfg(feature = "python")] #[derive(Debug, Clone)]
#[pymodule] pub struct PythonMetadata {
#[pyo3(name = "libafl")] pub map: PyObject,
/// Register the classes to the python module }
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
observers::map::pybind::register(py, m)?; crate::impl_serde_pyobjectwrapper!(PythonMetadata, map);
feedbacks::map::pybind::register(py, m)?; crate::impl_serdeany!(PythonMetadata);
state::pybind::register(py, m)?;
monitors::pybind::register(py, m)?; impl PythonMetadata {
events::pybind::register(py, m)?; #[must_use]
events::simple::pybind::register(py, m)?; pub fn new(map: PyObject) -> Self {
fuzzer::pybind::register(py, m)?; Self { map }
executors::pybind::register(py, m)?; }
executors::inprocess::pybind::register(py, m)?; }
generators::pybind::register(py, m)?;
corpus::pybind::register(py, m)?; #[macro_export]
corpus::ondisk::pybind::register(py, m)?; macro_rules! unwrap_me_body {
corpus::inmemory::pybind::register(py, m)?; ($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),* }) => {
corpus::cached::pybind::register(py, m)?; match &$wrapper {
bolts::rands::pybind::register(py, m)?; $(
stages::pybind::register(py, m)?; $wrapper_type::$wrapper_option(py_wrapper) => {
stages::owned::pybind::register(py, m)?; Python::with_gil(|py| -> PyResult<_> {
stages::mutational::pybind::register(py, m)?; let borrowed = py_wrapper.borrow(py);
Ok(()) let $name = &borrowed.inner;
Ok($body)
})
.unwrap()
}
)*
}
};
($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),* }, { $($wrapper_optional:tt($pw:ident) => $code_block:block)* }) => {
match &$wrapper {
$(
$wrapper_type::$wrapper_option(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let borrowed = py_wrapper.borrow(py);
let $name = &borrowed.inner;
Ok($body)
})
.unwrap()
}
)*
$($wrapper_type::$wrapper_optional($pw) => { $code_block })*
}
};
}
#[macro_export]
macro_rules! unwrap_me_mut_body {
($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),*}) => {
match &mut $wrapper {
$(
$wrapper_type::$wrapper_option(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
let $name = &mut borrowed.inner;
Ok($body)
})
.unwrap()
}
)*
}
};
($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),*}, { $($wrapper_optional:tt($pw:ident) => $code_block:block)* }) => {
match &mut $wrapper {
$(
$wrapper_type::$wrapper_option(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
let $name = &mut borrowed.inner;
Ok($body)
})
.unwrap()
}
)*
$($wrapper_type::$wrapper_optional($pw) => { $code_block })*
}
};
}
#[macro_export]
macro_rules! impl_serde_pyobjectwrapper {
($struct_name:ident, $inner:tt) => {
const _: () = {
use pyo3::prelude::*;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
impl Serialize for $struct_name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let buf = Python::with_gil(|py| -> PyResult<Vec<u8>> {
let pickle = PyModule::import(py, "pickle")?;
let buf: Vec<u8> =
pickle.getattr("dumps")?.call1((&self.$inner,))?.extract()?;
Ok(buf)
})
.unwrap();
serializer.serialize_bytes(&buf)
}
}
struct PyObjectVisitor;
impl<'de> serde::de::Visitor<'de> for PyObjectVisitor {
type Value = $struct_name;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter
.write_str("Expecting some bytes to deserialize from the Python side")
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let obj = Python::with_gil(|py| -> PyResult<PyObject> {
let pickle = PyModule::import(py, "pickle")?;
let obj = pickle.getattr("loads")?.call1((v,))?.to_object(py);
Ok(obj)
})
.unwrap();
Ok($struct_name::new(obj))
}
}
impl<'de> Deserialize<'de> for $struct_name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_byte_buf(PyObjectVisitor)
}
}
};
};
}
#[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)?;
observers::pybind::register(py, m)?;
feedbacks::map::pybind::register(py, m)?;
feedbacks::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)?;
mutators::pybind::register(py, m)?;
mutators::scheduled::pybind::register(py, m)?;
corpus::pybind::register(py, m)?;
corpus::testcase::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::mutational::pybind::register(py, m)?;
Ok(())
}
} }

View File

@ -815,95 +815,136 @@ impl Default for ClientPerfMonitor {
} }
/// `Monitor` Python bindings /// `Monitor` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::monitors::{Monitor, SimpleMonitor}; use crate::monitors::{Monitor, SimpleMonitor};
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyUnicode;
use super::ClientStats; use super::ClientStats;
use core::time::Duration; use core::time::Duration;
// TODO create a PyObjectFnMut to pass, track stabilization of https://github.com/rust-lang/rust/issues/29625
#[pyclass(unsendable, name = "SimpleMonitor")] #[pyclass(unsendable, name = "SimpleMonitor")]
#[derive(Clone, Debug)]
/// Python class for SimpleMonitor /// Python class for SimpleMonitor
pub struct PythonSimpleMonitor { pub struct PythonSimpleMonitor {
/// Rust wrapped SimpleMonitor object /// Rust wrapped SimpleMonitor object
pub simple_monitor: SimpleMonitor<fn(String)>, pub inner: SimpleMonitor<Box<dyn FnMut(String)>>,
print_fn: PyObject,
}
impl std::fmt::Debug for PythonSimpleMonitor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PythonSimpleMonitor")
.field("print_fn", &self.print_fn)
.finish()
}
}
impl Clone for PythonSimpleMonitor {
fn clone(&self) -> PythonSimpleMonitor {
let py_print_fn = self.print_fn.clone();
let closure = move |s: String| {
Python::with_gil(|py| -> PyResult<()> {
py_print_fn.call1(py, (PyUnicode::new(py, &s),))?;
Ok(())
})
.unwrap();
};
PythonSimpleMonitor {
inner: SimpleMonitor {
print_fn: Box::new(closure),
start_time: self.inner.start_time,
client_stats: self.inner.client_stats.clone(),
},
print_fn: self.print_fn.clone(),
}
}
} }
#[pymethods] #[pymethods]
impl PythonSimpleMonitor { impl PythonSimpleMonitor {
#[new] #[new]
fn new(/*py_print_fn: PyObject */) -> Self { fn new(py_print_fn: PyObject) -> Self {
// TODO: Find a fix to: closures can only be coerced to `fn` types if they let py_print_fn1 = py_print_fn.clone();
// do not capture any variables and print_fn expected to be fn pointer. let closure = move |s: String| {
// fn printf_fn (s: String){ Python::with_gil(|py| -> PyResult<()> {
// Python::with_gil(|py| -> PyResult<()> { py_print_fn1.call1(py, (PyUnicode::new(py, &s),))?;
// print_fn.call1(py, (PyUnicode::new(py, &s),)); Ok(())
// Ok(()) })
// }); .unwrap();
// } };
Self { Self {
simple_monitor: SimpleMonitor::new(|s| println!("{}", s)), inner: SimpleMonitor::new(Box::new(closure)),
print_fn: py_print_fn,
} }
} }
#[must_use]
pub fn as_monitor(slf: Py<Self>) -> PythonMonitor {
PythonMonitor::new_simple(slf)
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum PythonMonitorWrapper { enum PythonMonitorWrapper {
Simple(PythonSimpleMonitor), Simple(Py<PythonSimpleMonitor>),
} }
#[pyclass(unsendable, name = "Monitor")] #[pyclass(unsendable, name = "Monitor")]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// EventManager Trait binding /// EventManager Trait binding
pub struct PythonMonitor { pub struct PythonMonitor {
monitor: PythonMonitorWrapper, wrapper: PythonMonitorWrapper,
} }
impl PythonMonitor { macro_rules! unwrap_me {
fn get_monitor(&self) -> &impl Monitor { ($wrapper:expr, $name:ident, $body:block) => {
match &self.monitor { crate::unwrap_me_body!($wrapper, $name, $body, PythonMonitorWrapper, { Simple })
PythonMonitorWrapper::Simple(py_simple_monitor) => { };
&py_simple_monitor.simple_monitor }
}
}
}
fn get_mut_monitor(&mut self) -> &mut impl Monitor { macro_rules! unwrap_me_mut {
match &mut self.monitor { ($wrapper:expr, $name:ident, $body:block) => {
PythonMonitorWrapper::Simple(py_simple_monitor) => { crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonMonitorWrapper, { Simple })
&mut py_simple_monitor.simple_monitor };
}
}
}
} }
#[pymethods] #[pymethods]
impl PythonMonitor { impl PythonMonitor {
#[staticmethod] #[staticmethod]
fn new_from_simple(simple_monitor: PythonSimpleMonitor) -> Self { #[must_use]
pub fn new_simple(simple_monitor: Py<PythonSimpleMonitor>) -> Self {
Self { Self {
monitor: PythonMonitorWrapper::Simple(simple_monitor), wrapper: PythonMonitorWrapper::Simple(simple_monitor),
} }
} }
} }
impl Monitor for PythonMonitor { impl Monitor for PythonMonitor {
fn client_stats_mut(&mut self) -> &mut Vec<ClientStats> { fn client_stats_mut(&mut self) -> &mut Vec<ClientStats> {
self.get_mut_monitor().client_stats_mut() let ptr = unwrap_me_mut!(self.wrapper, m, {
m.client_stats_mut() as *mut Vec<ClientStats>
});
unsafe { ptr.as_mut().unwrap() }
} }
fn client_stats(&self) -> &[ClientStats] { fn client_stats(&self) -> &[ClientStats] {
self.get_monitor().client_stats() let ptr = unwrap_me!(self.wrapper, m, {
m.client_stats() as *const [ClientStats]
});
unsafe { ptr.as_ref().unwrap() }
} }
/// Time this fuzzing run stated /// Time this fuzzing run stated
fn start_time(&mut self) -> Duration { fn start_time(&mut self) -> Duration {
self.get_mut_monitor().start_time() unwrap_me_mut!(self.wrapper, m, { m.start_time() })
} }
fn display(&mut self, event_msg: String, sender_id: u32) { fn display(&mut self, event_msg: String, sender_id: u32) {
self.get_mut_monitor().display(event_msg, sender_id); unwrap_me_mut!(self.wrapper, m, { m.display(event_msg, sender_id) });
} }
} }
/// Register the classes to the python module /// Register the classes to the python module

View File

@ -207,3 +207,150 @@ where
} }
} }
} }
/// `Mutator` Python bindings
#[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind {
use super::{MutationResult, Mutator};
use crate::inputs::{BytesInput, HasBytesVec};
use crate::mutators::scheduled::pybind::PythonStdHavocMutator;
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper};
use crate::Error;
use pyo3::prelude::*;
#[derive(Clone, Debug)]
pub struct PyObjectMutator {
inner: PyObject,
}
impl PyObjectMutator {
#[must_use]
pub fn new(obj: PyObject) -> Self {
PyObjectMutator { inner: obj }
}
}
impl Mutator<BytesInput, PythonStdState> for PyObjectMutator {
fn mutate(
&mut self,
state: &mut PythonStdState,
input: &mut BytesInput,
stage_idx: i32,
) -> Result<MutationResult, Error> {
let mutated = Python::with_gil(|py| -> PyResult<bool> {
self.inner
.call_method1(
py,
"mutate",
(PythonStdStateWrapper::wrap(state), input.bytes(), stage_idx),
)?
.extract(py)
})?;
Ok(if mutated {
MutationResult::Mutated
} else {
MutationResult::Skipped
})
}
fn post_exec(
&mut self,
state: &mut PythonStdState,
stage_idx: i32,
corpus_idx: Option<usize>,
) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method1(
py,
"post_exec",
(PythonStdStateWrapper::wrap(state), stage_idx, corpus_idx),
)?;
Ok(())
})?;
Ok(())
}
}
#[derive(Debug, Clone)]
pub enum PythonMutatorWrapper {
StdHavoc(Py<PythonStdHavocMutator>),
Python(PyObjectMutator),
}
/// Mutator Trait binding
#[pyclass(unsendable, name = "Mutator")]
#[derive(Debug, Clone)]
pub struct PythonMutator {
pub wrapper: PythonMutatorWrapper,
}
macro_rules! unwrap_me_mut {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonMutatorWrapper, {
StdHavoc
},
{
Python(py_wrapper) => {
let $name = py_wrapper;
$body
}
})
};
}
#[pymethods]
impl PythonMutator {
#[staticmethod]
#[must_use]
pub fn new_std_havoc(mgr: Py<PythonStdHavocMutator>) -> Self {
Self {
wrapper: PythonMutatorWrapper::StdHavoc(mgr),
}
}
#[staticmethod]
#[must_use]
pub fn new_py(obj: PyObject) -> Self {
Self {
wrapper: PythonMutatorWrapper::Python(PyObjectMutator::new(obj)),
}
}
#[must_use]
pub fn unwrap_py(&self) -> Option<PyObject> {
match &self.wrapper {
PythonMutatorWrapper::Python(pyo) => Some(pyo.inner.clone()),
PythonMutatorWrapper::StdHavoc(_) => None,
}
}
}
impl Mutator<BytesInput, PythonStdState> for PythonMutator {
fn mutate(
&mut self,
state: &mut PythonStdState,
input: &mut BytesInput,
stage_idx: i32,
) -> Result<MutationResult, Error> {
unwrap_me_mut!(self.wrapper, m, { m.mutate(state, input, stage_idx) })
}
fn post_exec(
&mut self,
state: &mut PythonStdState,
stage_idx: i32,
corpus_idx: Option<usize>,
) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, m, {
m.post_exec(state, stage_idx, corpus_idx)
})
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonMutator>()?;
Ok(())
}
}

View File

@ -208,9 +208,8 @@ where
} }
} }
/// Get the mutations that compose the Havoc mutator /// Tuple type of the mutations that compose the Havoc mutator
#[must_use] pub type HavocMutationsType = tuple_list_type!(
pub fn havoc_mutations() -> tuple_list_type!(
BitFlipMutator, BitFlipMutator,
ByteFlipMutator, ByteFlipMutator,
ByteIncMutator, ByteIncMutator,
@ -238,7 +237,11 @@ pub fn havoc_mutations() -> tuple_list_type!(
BytesSwapMutator, BytesSwapMutator,
CrossoverInsertMutator, CrossoverInsertMutator,
CrossoverReplaceMutator, CrossoverReplaceMutator,
) { );
/// Get the mutations that compose the Havoc mutator
#[must_use]
pub fn havoc_mutations() -> HavocMutationsType {
tuple_list!( tuple_list!(
BitFlipMutator::new(), BitFlipMutator::new(),
ByteFlipMutator::new(), ByteFlipMutator::new(),
@ -497,3 +500,42 @@ mod tests {
} }
} }
} }
/// `SchedulerMutator` Python bindings
#[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind {
use super::{havoc_mutations, Debug, HavocMutationsType, StdScheduledMutator};
use crate::inputs::BytesInput;
use crate::mutators::pybind::PythonMutator;
use crate::state::pybind::PythonStdState;
use pyo3::prelude::*;
#[pyclass(unsendable, name = "StdHavocMutator")]
#[derive(Debug)]
/// Python class for StdHavocMutator
pub struct PythonStdHavocMutator {
/// Rust wrapped StdHavocMutator object
pub inner: StdScheduledMutator<BytesInput, HavocMutationsType, PythonStdState>,
}
#[pymethods]
impl PythonStdHavocMutator {
#[new]
fn new() -> Self {
Self {
inner: StdScheduledMutator::new(havoc_mutations()),
}
}
fn as_mutator(slf: Py<Self>) -> PythonMutator {
PythonMutator::new_std_havoc(slf)
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdHavocMutator>()?;
Ok(())
}
}

View File

@ -181,7 +181,7 @@ where
/// The Map Observer retrieves the state of a map, /// The Map Observer retrieves the state of a map,
/// that will get updated by the target. /// that will get updated by the target.
/// A well-known example is the AFL-Style coverage map. /// A well-known example is the AFL-Style coverage map.
#[derive(Serialize, Deserialize, Debug)] #[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned")]
#[allow(clippy::unsafe_derive_deserialize)] #[allow(clippy::unsafe_derive_deserialize)]
pub struct StdMapObserver<'a, T> pub struct StdMapObserver<'a, T>
@ -384,20 +384,26 @@ where
{ {
/// Creates a new [`MapObserver`] /// Creates a new [`MapObserver`]
#[must_use] #[must_use]
pub fn new(name: &'static str, map: &'a mut [T]) -> Self { pub fn new<S>(name: S, map: &'a mut [T]) -> Self
where
S: Into<String>,
{
Self { Self {
map: OwnedSliceMut::from(map), map: OwnedSliceMut::from(map),
name: name.to_string(), name: name.into(),
initial: T::default(), initial: T::default(),
} }
} }
/// Creates a new [`MapObserver`] with an owned map /// Creates a new [`MapObserver`] with an owned map
#[must_use] #[must_use]
pub fn new_owned(name: &'static str, map: Vec<T>) -> Self { pub fn new_owned<S>(name: S, map: Vec<T>) -> Self
where
S: Into<String>,
{
Self { Self {
map: OwnedSliceMut::from(map), map: OwnedSliceMut::from(map),
name: name.to_string(), name: name.into(),
initial: T::default(), initial: T::default(),
} }
} }
@ -407,10 +413,13 @@ where
/// # Safety /// # Safety
/// Will dereference the owned slice with up to len elements. /// Will dereference the owned slice with up to len elements.
#[must_use] #[must_use]
pub fn new_from_ownedref(name: &'static str, map: OwnedSliceMut<'a, T>) -> Self { pub fn new_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self
where
S: Into<String>,
{
Self { Self {
map, map,
name: name.to_string(), name: name.into(),
initial: T::default(), initial: T::default(),
} }
} }
@ -419,10 +428,13 @@ where
/// ///
/// # Safety /// # Safety
/// Will dereference the `map_ptr` with up to len elements. /// Will dereference the `map_ptr` with up to len elements.
pub unsafe fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self { pub unsafe fn new_from_ptr<S>(name: S, map_ptr: *mut T, len: usize) -> Self
where
S: Into<String>,
{
StdMapObserver { StdMapObserver {
map: OwnedSliceMut::from_raw_parts_mut(map_ptr, len), map: OwnedSliceMut::from_raw_parts_mut(map_ptr, len),
name: name.to_string(), name: name.into(),
initial: T::default(), initial: T::default(),
} }
} }
@ -1490,26 +1502,128 @@ where
/// `MapObserver` Python bindings /// `MapObserver` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::bolts::{tuples::Named, AsMutIterator, AsRefIterator, HasLen}; use super::{
use crate::observers::{map::OwnedMapObserver, MapObserver, Observer}; AsMutIterator, AsRefIterator, Debug, Error, HasLen, Iter, IterMut, MapObserver, Named,
use crate::Error; Observer, OwnedMapObserver, StdMapObserver, String, Vec,
};
use crate::observers::pybind::PythonObserver;
use concat_idents::concat_idents;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::slice::{Iter, IterMut};
#[macro_export]
macro_rules! mapob_unwrap_me {
($wrapper_name:ident, $wrapper:expr, $name:ident, $body:block) => {
match &$wrapper {
$wrapper_name::Std(py_wrapper) => Python::with_gil(|py| -> PyResult<_> {
let borrowed = py_wrapper.borrow(py);
let $name = &borrowed.inner;
Ok($body)
})
.unwrap(),
$wrapper_name::Owned(py_wrapper) => Python::with_gil(|py| -> PyResult<_> {
let borrowed = py_wrapper.borrow(py);
let $name = &borrowed.inner;
Ok($body)
})
.unwrap(),
$wrapper_name::None => panic!("Serde is not supported ATM"),
}
};
}
#[macro_export]
macro_rules! mapob_unwrap_me_mut {
($wrapper_name:ident, $wrapper:expr, $name:ident, $body:block) => {
match &mut $wrapper {
$wrapper_name::Std(py_wrapper) => Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
let $name = &mut borrowed.inner;
Ok($body)
})
.unwrap(),
$wrapper_name::Owned(py_wrapper) => Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
let $name = &mut borrowed.inner;
Ok($body)
})
.unwrap(),
$wrapper_name::None => panic!("Serde is not supported ATM"),
}
};
}
macro_rules! define_python_map_observer { 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) => { ($struct_name1:ident, $py_name1:tt, $struct_name2:ident, $py_name2:tt, $struct_name_trait:ident, $py_name_trait:tt, $datatype:ty, $wrapper_name: ident) => {
#[pyclass(unsendable, name = $py_name)] #[pyclass(unsendable, name = $py_name1)]
#[allow(clippy::unsafe_derive_deserialize)]
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for StdMapObserver
pub struct $struct_name1 {
/// Rust wrapped StdMapObserver object
pub inner: StdMapObserver<'static, $datatype>,
}
#[pymethods]
impl $struct_name1 {
#[new]
fn new(name: String, ptr: usize, size: usize) -> Self {
Self {
inner: unsafe { StdMapObserver::new_from_ptr(name, ptr as *mut $datatype, size) }
}
}
#[must_use]
pub fn as_map_observer(slf: Py<Self>) -> $struct_name_trait {
$struct_name_trait::new_std(slf)
}
#[must_use]
pub fn as_observer(slf: Py<Self>) -> PythonObserver {
let m = Self::as_map_observer(slf);
Python::with_gil(|py| -> PyResult<PythonObserver> {
let p: Py<_> = Py::new(py, m)?;
Ok($struct_name_trait::as_observer(p))
}).unwrap()
}
fn __getitem__(&self, idx: usize) -> $datatype {
*self.inner.get(idx)
}
fn __setitem__(&mut self, idx: usize, val: $datatype) {
*self.inner.get_mut(idx) = val;
}
#[pyo3(name = "usable_count")]
fn pyusable_count(&self) -> usize {
self.inner.usable_count()
}
#[pyo3(name = "len")]
fn pylen(&self) -> usize {
self.inner.len()
}
#[pyo3(name = "name")]
fn pyname(&self) -> &str {
self.inner.name()
}
}
#[pyclass(unsendable, name = $py_name2)]
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for OwnedMapObserver (i.e. StdMapObserver with owned map) /// Python class for OwnedMapObserver (i.e. StdMapObserver with owned map)
pub struct $struct_name { pub struct $struct_name2 {
/// Rust wrapped OwnedMapObserver object /// Rust wrapped OwnedMapObserver object
pub inner: OwnedMapObserver<$datatype>, pub inner: OwnedMapObserver<$datatype>,
} }
#[pymethods] #[pymethods]
impl $struct_name { impl $struct_name2 {
#[new] #[new]
fn new(name: String, map: Vec<$datatype>) -> Self { fn new(name: String, map: Vec<$datatype>) -> Self {
Self { Self {
@ -1517,11 +1631,56 @@ pub mod pybind {
inner: OwnedMapObserver::new(Box::leak(name.into_boxed_str()), map), inner: OwnedMapObserver::new(Box::leak(name.into_boxed_str()), map),
} }
} }
#[must_use]
pub fn as_map_observer(slf: Py<Self>) -> $struct_name_trait {
$struct_name_trait::new_owned(slf)
}
#[must_use]
pub fn as_observer(slf: Py<Self>) -> PythonObserver {
let m = Self::as_map_observer(slf);
Python::with_gil(|py| -> PyResult<PythonObserver> {
let p: Py<_> = Py::new(py, m)?;
Ok($struct_name_trait::as_observer(p))
}).unwrap()
}
fn __getitem__(&self, idx: usize) -> $datatype {
*self.inner.get(idx)
}
fn __setitem__(&mut self, idx: usize, val: $datatype) {
*self.inner.get_mut(idx) = val;
}
#[pyo3(name = "usable_count")]
fn pyusable_count(&self) -> usize {
self.inner.usable_count()
}
#[pyo3(name = "len")]
fn pylen(&self) -> usize {
self.inner.len()
}
#[pyo3(name = "name")]
fn pyname(&self) -> &str {
self.inner.name()
}
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Debug, Clone)]
enum $wrapper_name { pub enum $wrapper_name {
Owned($struct_name), Std(Py<$struct_name1>),
Owned(Py<$struct_name2>),
None
}
impl Default for $wrapper_name {
fn default() -> Self {
$wrapper_name::None
}
} }
// Should not be exposed to user // Should not be exposed to user
@ -1529,51 +1688,55 @@ pub mod pybind {
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
/// MapObserver + Observer Trait binding /// MapObserver + Observer Trait binding
pub struct $struct_name_trait { pub struct $struct_name_trait {
#[serde(skip)]
pub wrapper: $wrapper_name, pub wrapper: $wrapper_name,
} }
impl $struct_name_trait {
fn unwrap(&self) -> &impl MapObserver<Entry = $datatype> {
unsafe {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => &py_wrapper.inner,
}
}
}
fn unwrap_mut(&mut self) -> &mut impl MapObserver<Entry = $datatype> {
unsafe {
match &mut self.wrapper {
$wrapper_name::Owned(py_wrapper) => &mut py_wrapper.inner,
}
}
}
fn upcast<S>(&self) -> &impl Observer<BytesInput, S> {
unsafe {
match &self.wrapper {
$wrapper_name::Owned(py_wrapper) => &py_wrapper.inner,
}
}
}
fn upcast_mut<S>(&mut self) -> &mut impl Observer<BytesInput, S> {
unsafe {
match &mut self.wrapper {
$wrapper_name::Owned(py_wrapper) => &mut py_wrapper.inner,
}
}
}
}
#[pymethods] #[pymethods]
impl $struct_name_trait { impl $struct_name_trait {
#[staticmethod] #[staticmethod]
fn new_from_owned(owned_map: $struct_name) -> Self { fn new_std(std_map: Py<$struct_name1>) -> Self {
Self {
wrapper: $wrapper_name::Std(std_map),
}
}
#[staticmethod]
fn new_owned(owned_map: Py<$struct_name2>) -> Self {
Self { Self {
wrapper: $wrapper_name::Owned(owned_map), wrapper: $wrapper_name::Owned(owned_map),
} }
} }
#[must_use]
pub fn as_observer(slf: Py<Self>) -> PythonObserver {
concat_idents!(func = new_map_,$datatype {
PythonObserver::func(slf)
})
}
fn __getitem__(&self, idx: usize) -> $datatype {
*self.get(idx)
}
fn __setitem__(&mut self, idx: usize, val: $datatype) {
*self.get_mut(idx) = val;
}
#[pyo3(name = "usable_count")]
fn pyusable_count(&self) -> usize {
self.usable_count()
}
#[pyo3(name = "len")]
fn pylen(&self) -> usize {
self.len()
}
#[pyo3(name = "name")]
fn pyname(&self) -> &str {
self.name()
}
} }
impl<'it> AsRefIterator<'it> for $struct_name_trait { impl<'it> AsRefIterator<'it> for $struct_name_trait {
@ -1581,9 +1744,7 @@ pub mod pybind {
type IntoIter = Iter<'it, $datatype>; type IntoIter = Iter<'it, $datatype>;
fn as_ref_iter(&'it self) -> Self::IntoIter { fn as_ref_iter(&'it self) -> Self::IntoIter {
match &self.wrapper { mapob_unwrap_me!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute::<_, Self::IntoIter>(m.as_ref_iter()) } })
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.as_ref_iter(),
}
} }
} }
@ -1592,9 +1753,7 @@ pub mod pybind {
type IntoIter = IterMut<'it, $datatype>; type IntoIter = IterMut<'it, $datatype>;
fn as_mut_iter(&'it mut self) -> Self::IntoIter { fn as_mut_iter(&'it mut self) -> Self::IntoIter {
match &mut self.wrapper { mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute::<_, Self::IntoIter>(m.as_mut_iter()) } })
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.as_mut_iter(),
}
} }
} }
@ -1603,76 +1762,58 @@ pub mod pybind {
#[inline] #[inline]
fn get(&self, idx: usize) -> &$datatype { fn get(&self, idx: usize) -> &$datatype {
match &self.wrapper { let ptr = mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.get(idx) as *const $datatype });
$wrapper_name::Owned(py_wrapper) => &py_wrapper.inner.get(idx), unsafe { ptr.as_ref().unwrap() }
}
} }
#[inline] #[inline]
fn get_mut(&mut self, idx: usize) -> &mut $datatype { fn get_mut(&mut self, idx: usize) -> &mut $datatype {
match &mut self.wrapper { let ptr = mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.get_mut(idx) as *mut $datatype });
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.get_mut(idx), unsafe { ptr.as_mut().unwrap() }
}
} }
#[inline] #[inline]
fn usable_count(&self) -> usize { fn usable_count(&self) -> usize {
match &self.wrapper { mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.usable_count() })
$wrapper_name::Owned(py_wrapper) => py_wrapper.wrapper.usable_count(),
}
} }
fn hash(&self) -> u64 { fn hash(&self) -> u64 {
match &self.wrapper { mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.hash() })
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.hash(),
}
} }
#[inline] #[inline]
fn initial(&self) -> $datatype { fn initial(&self) -> $datatype {
match &self.wrapper { mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.initial() })
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.initial(),
}
} }
#[inline] #[inline]
fn initial_mut(&mut self) -> &mut $datatype { fn initial_mut(&mut self) -> &mut $datatype {
match &mut self.wrapper { let ptr = mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.initial_mut() as *mut $datatype });
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.initial_mut(), unsafe { ptr.as_mut().unwrap() }
}
} }
#[inline] #[inline]
fn set_initial(&mut self, initial: $datatype) { fn set_initial(&mut self, initial: $datatype) {
match &mut self.wrapper { mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.set_initial(initial) });
$wrapper_name::Owned(py_wrapper) => {
py_wrapper.inner.set_initial(initial);
}
}
} }
fn to_vec(&self) -> Vec<$datatype> { fn to_vec(&self) -> Vec<$datatype> {
match &self.wrapper { mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.to_vec() })
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.to_vec(),
}
} }
} }
impl Named for $struct_name_trait { impl Named for $struct_name_trait {
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
match &self.wrapper { let ptr = mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.name() as *const str });
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.name(), unsafe { ptr.as_ref().unwrap() }
}
} }
} }
impl HasLen for $struct_name_trait { impl HasLen for $struct_name_trait {
#[inline] #[inline]
fn len(&self) -> usize { fn len(&self) -> usize {
match &self.wrapper { mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.len() })
$wrapper_name::Owned(py_wrapper) => py_wrapper.inner.len(),
}
} }
} }
@ -1681,18 +1822,16 @@ pub mod pybind {
Self: MapObserver, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
match &mut self.wrapper { mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.pre_exec(state, input) })
$wrapper_name::Owned(py_wrapper) => {
py_wrapper.inner.pre_exec(_state, _input)
}
}
} }
} }
}; };
} }
define_python_map_observer!( define_python_map_observer!(
PythonStdMapObserverI8,
"StdMapObserverI8",
PythonOwnedMapObserverI8, PythonOwnedMapObserverI8,
"OwnedMapObserverI8", "OwnedMapObserverI8",
PythonMapObserverI8, PythonMapObserverI8,
@ -1701,6 +1840,8 @@ pub mod pybind {
PythonMapObserverWrapperI8 PythonMapObserverWrapperI8
); );
define_python_map_observer!( define_python_map_observer!(
PythonStdMapObserverI16,
"StdMapObserverI16",
PythonOwnedMapObserverI16, PythonOwnedMapObserverI16,
"OwnedMapObserverI16", "OwnedMapObserverI16",
PythonMapObserverI16, PythonMapObserverI16,
@ -1709,6 +1850,8 @@ pub mod pybind {
PythonMapObserverWrapperI16 PythonMapObserverWrapperI16
); );
define_python_map_observer!( define_python_map_observer!(
PythonStdMapObserverI32,
"StdMapObserverI32",
PythonOwnedMapObserverI32, PythonOwnedMapObserverI32,
"OwnedMapObserverI32", "OwnedMapObserverI32",
PythonMapObserverI32, PythonMapObserverI32,
@ -1717,6 +1860,8 @@ pub mod pybind {
PythonMapObserverWrapperI32 PythonMapObserverWrapperI32
); );
define_python_map_observer!( define_python_map_observer!(
PythonStdMapObserverI64,
"StdMapObserverI64",
PythonOwnedMapObserverI64, PythonOwnedMapObserverI64,
"OwnedMapObserverI64", "OwnedMapObserverI64",
PythonMapObserverI64, PythonMapObserverI64,
@ -1726,6 +1871,8 @@ pub mod pybind {
); );
define_python_map_observer!( define_python_map_observer!(
PythonStdMapObserverU8,
"StdMapObserverU8",
PythonOwnedMapObserverU8, PythonOwnedMapObserverU8,
"OwnedMapObserverU8", "OwnedMapObserverU8",
PythonMapObserverU8, PythonMapObserverU8,
@ -1734,6 +1881,8 @@ pub mod pybind {
PythonMapObserverWrapperU8 PythonMapObserverWrapperU8
); );
define_python_map_observer!( define_python_map_observer!(
PythonStdMapObserverU16,
"StdMapObserverU16",
PythonOwnedMapObserverU16, PythonOwnedMapObserverU16,
"OwnedMapObserverU16", "OwnedMapObserverU16",
PythonMapObserverU16, PythonMapObserverU16,
@ -1742,6 +1891,8 @@ pub mod pybind {
PythonMapObserverWrapperU16 PythonMapObserverWrapperU16
); );
define_python_map_observer!( define_python_map_observer!(
PythonStdMapObserverU32,
"StdMapObserverU32",
PythonOwnedMapObserverU32, PythonOwnedMapObserverU32,
"OwnedMapObserverU32", "OwnedMapObserverU32",
PythonMapObserverU32, PythonMapObserverU32,
@ -1750,6 +1901,8 @@ pub mod pybind {
PythonMapObserverWrapperU32 PythonMapObserverWrapperU32
); );
define_python_map_observer!( define_python_map_observer!(
PythonStdMapObserverU64,
"StdMapObserverU64",
PythonOwnedMapObserverU64, PythonOwnedMapObserverU64,
"OwnedMapObserverU64", "OwnedMapObserverU64",
PythonMapObserverU64, PythonMapObserverU64,
@ -1760,21 +1913,29 @@ pub mod pybind {
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdMapObserverI8>()?;
m.add_class::<PythonOwnedMapObserverI8>()?; m.add_class::<PythonOwnedMapObserverI8>()?;
m.add_class::<PythonMapObserverI8>()?; m.add_class::<PythonMapObserverI8>()?;
m.add_class::<PythonStdMapObserverI16>()?;
m.add_class::<PythonOwnedMapObserverI16>()?; m.add_class::<PythonOwnedMapObserverI16>()?;
m.add_class::<PythonMapObserverI16>()?; m.add_class::<PythonMapObserverI16>()?;
m.add_class::<PythonStdMapObserverI32>()?;
m.add_class::<PythonOwnedMapObserverI32>()?; m.add_class::<PythonOwnedMapObserverI32>()?;
m.add_class::<PythonMapObserverI32>()?; m.add_class::<PythonMapObserverI32>()?;
m.add_class::<PythonStdMapObserverI64>()?;
m.add_class::<PythonOwnedMapObserverI64>()?; m.add_class::<PythonOwnedMapObserverI64>()?;
m.add_class::<PythonMapObserverI64>()?; m.add_class::<PythonMapObserverI64>()?;
m.add_class::<PythonStdMapObserverU8>()?;
m.add_class::<PythonOwnedMapObserverU8>()?; m.add_class::<PythonOwnedMapObserverU8>()?;
m.add_class::<PythonMapObserverU8>()?; m.add_class::<PythonMapObserverU8>()?;
m.add_class::<PythonStdMapObserverU16>()?;
m.add_class::<PythonOwnedMapObserverU16>()?; m.add_class::<PythonOwnedMapObserverU16>()?;
m.add_class::<PythonMapObserverU16>()?; m.add_class::<PythonMapObserverU16>()?;
m.add_class::<PythonStdMapObserverU32>()?;
m.add_class::<PythonOwnedMapObserverU32>()?; m.add_class::<PythonOwnedMapObserverU32>()?;
m.add_class::<PythonMapObserverU32>()?; m.add_class::<PythonMapObserverU32>()?;
m.add_class::<PythonStdMapObserverU64>()?;
m.add_class::<PythonOwnedMapObserverU64>()?; m.add_class::<PythonOwnedMapObserverU64>()?;
m.add_class::<PythonMapObserverU64>()?; m.add_class::<PythonMapObserverU64>()?;
Ok(()) Ok(())

View File

@ -292,119 +292,769 @@ where
/// `Observer` Python bindings /// `Observer` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::bolts::tuples::Named; use super::{Debug, Observer, ObserversTuple, String, Vec};
use crate::bolts::tuples::{type_eq, MatchName, Named};
use crate::executors::pybind::PythonExitKind;
use crate::executors::ExitKind; use crate::executors::ExitKind;
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use crate::observers::Observer; use crate::inputs::HasBytesVec;
use crate::observers::map::pybind::{
PythonMapObserverI16, PythonMapObserverI32, PythonMapObserverI64, PythonMapObserverI8,
PythonMapObserverU16, PythonMapObserverU32, PythonMapObserverU64, PythonMapObserverU8,
PythonMapObserverWrapperI16, PythonMapObserverWrapperI32, PythonMapObserverWrapperI64,
PythonMapObserverWrapperI8, PythonMapObserverWrapperU16, PythonMapObserverWrapperU32,
PythonMapObserverWrapperU64, PythonMapObserverWrapperU8,
};
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper};
use crate::Error; use crate::Error;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use std::cell::UnsafeCell;
macro_rules! define_python_observer { #[derive(Debug)]
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $my_std_state_type_name: ident) => { pub struct PyObjectObserver {
use crate::observers::map::pybind::PythonMapObserverI8; inner: PyObject,
use crate::state::pybind::$my_std_state_type_name; name: UnsafeCell<String>,
}
#[derive(Debug)] impl Clone for PyObjectObserver {
enum $wrapper_name { fn clone(&self) -> PyObjectObserver {
MapI8(*mut PythonMapObserverI8), PyObjectObserver {
inner: self.inner.clone(),
name: UnsafeCell::new(String::new()),
} }
}
}
#[pyclass(unsendable, name = $py_name_trait)] impl PyObjectObserver {
#[derive(Debug)] #[must_use]
/// Observer Trait binding pub fn new(obj: PyObject) -> Self {
pub struct $struct_name_trait { PyObjectObserver {
pub wrapper: $wrapper_name, inner: obj,
name: UnsafeCell::new(String::new()),
} }
}
}
impl $struct_name_trait { crate::impl_serde_pyobjectwrapper!(PyObjectObserver, inner);
fn unwrap(&self) -> &impl Observer<BytesInput, $my_std_state_type_name> {
unsafe {
match self.wrapper {
$wrapper_name::MapI8(py_wrapper) => &(*py_wrapper).upcast(),
}
}
}
fn unwrap_mut( impl Named for PyObjectObserver {
&mut self, fn name(&self) -> &str {
) -> &mut impl Observer<BytesInput, $my_std_state_type_name> { let s = Python::with_gil(|py| -> PyResult<String> {
unsafe { let s: String = self.inner.call_method0(py, "name")?.extract(py)?;
match self.wrapper { Ok(s)
$wrapper_name::MapI8(py_wrapper) => &mut (*py_wrapper).upcast_mut(), })
} .unwrap();
} unsafe {
} *self.name.get() = s;
&*self.name.get()
} }
}
}
#[pymethods] impl Observer<BytesInput, PythonStdState> for PyObjectObserver {
impl $struct_name_trait { fn flush(&mut self) -> Result<(), Error> {
#[staticmethod] Python::with_gil(|py| -> PyResult<()> {
fn new_map(map_observer: &mut PythonMapObserverI8) -> Self { self.inner.call_method0(py, "flush")?;
Self { Ok(())
observer: $wrapper_name::MapI8(map_observer), })
} .unwrap();
Ok(())
}
fn pre_exec(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method1(
py,
"pre_exec",
(PythonStdStateWrapper::wrap(state), input.bytes()),
)?;
Ok(())
})?;
Ok(())
}
fn post_exec(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
exit_kind: &ExitKind,
) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method1(
py,
"post_exec",
(
PythonStdStateWrapper::wrap(state),
input.bytes(),
PythonExitKind::from(*exit_kind),
),
)?;
Ok(())
})?;
Ok(())
}
fn pre_exec_child(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method1(
py,
"pre_exec_child",
(PythonStdStateWrapper::wrap(state), input.bytes()),
)?;
Ok(())
})?;
Ok(())
}
fn post_exec_child(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
exit_kind: &ExitKind,
) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method1(
py,
"post_exec_child",
(
PythonStdStateWrapper::wrap(state),
input.bytes(),
PythonExitKind::from(*exit_kind),
),
)?;
Ok(())
})?;
Ok(())
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum PythonObserverWrapper {
MapI8(Py<PythonMapObserverI8>),
MapI16(Py<PythonMapObserverI16>),
MapI32(Py<PythonMapObserverI32>),
MapI64(Py<PythonMapObserverI64>),
MapU8(Py<PythonMapObserverU8>),
MapU16(Py<PythonMapObserverU16>),
MapU32(Py<PythonMapObserverU32>),
MapU64(Py<PythonMapObserverU64>),
Python(PyObjectObserver),
}
#[pyclass(unsendable, name = "Observer")]
#[derive(Serialize, Deserialize, Clone, Debug)]
/// Observer Trait binding
pub struct PythonObserver {
pub wrapper: PythonObserverWrapper,
}
macro_rules! unwrap_me {
($wrapper:expr, $name:ident, $body:block) => {
match &$wrapper {
PythonObserverWrapper::MapI8(py_wrapper) => Python::with_gil(|py| -> PyResult<_> {
let borrowed = py_wrapper.borrow(py);
Ok(crate::mapob_unwrap_me!(
PythonMapObserverWrapperI8,
borrowed.wrapper,
$name,
$body
))
})
.unwrap(),
PythonObserverWrapper::MapI16(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let borrowed = py_wrapper.borrow(py);
Ok(crate::mapob_unwrap_me!(
PythonMapObserverWrapperI16,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
} }
} PythonObserverWrapper::MapI32(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
impl Named for $struct_name_trait { let borrowed = py_wrapper.borrow(py);
fn name(&self) -> &str { Ok(crate::mapob_unwrap_me!(
self.unwrap().name() PythonMapObserverWrapperI32,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
} }
} PythonObserverWrapper::MapI64(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
impl Observer<BytesInput, $my_std_state_type_name> for $struct_name_trait { let borrowed = py_wrapper.borrow(py);
fn flush(&mut self) -> Result<(), Error> { Ok(crate::mapob_unwrap_me!(
self.unwrap_mut().flush() PythonMapObserverWrapperI64,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
} }
PythonObserverWrapper::MapU8(py_wrapper) => Python::with_gil(|py| -> PyResult<_> {
fn pre_exec( let borrowed = py_wrapper.borrow(py);
&mut self, Ok(crate::mapob_unwrap_me!(
state: &mut $my_std_state_type_name, PythonMapObserverWrapperU8,
input: &BytesInput, borrowed.wrapper,
) -> Result<(), Error> { $name,
self.unwrap_mut().pre_exec(state, input) $body
))
})
.unwrap(),
PythonObserverWrapper::MapU16(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let borrowed = py_wrapper.borrow(py);
Ok(crate::mapob_unwrap_me!(
PythonMapObserverWrapperU16,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
} }
PythonObserverWrapper::MapU32(py_wrapper) => {
fn post_exec( Python::with_gil(|py| -> PyResult<_> {
&mut self, let borrowed = py_wrapper.borrow(py);
state: &mut $my_std_state_type_name, Ok(crate::mapob_unwrap_me!(
input: &BytesInput, PythonMapObserverWrapperU32,
exit_kind: &ExitKind, borrowed.wrapper,
) -> Result<(), Error> { $name,
self.unwrap_mut().post_exec(state, input, exit_kind) $body
))
})
.unwrap()
} }
PythonObserverWrapper::MapU64(py_wrapper) => {
fn pre_exec_child( Python::with_gil(|py| -> PyResult<_> {
&mut self, let borrowed = py_wrapper.borrow(py);
state: &mut $my_std_state_type_name, Ok(crate::mapob_unwrap_me!(
input: &BytesInput, PythonMapObserverWrapperU64,
) -> Result<(), Error> { borrowed.wrapper,
self.unwrap_mut().pre_exec(state, input) $name,
$body
))
})
.unwrap()
} }
PythonObserverWrapper::Python(py_wrapper) => {
fn post_exec_child( let $name = py_wrapper;
&mut self, $body
state: &mut $my_std_state_type_name,
input: &BytesInput,
exit_kind: &ExitKind,
) -> Result<(), Error> {
self.unwrap_mut().post_exec_child(state, input, exit_kind)
} }
} }
}; };
} }
define_python_observer!( macro_rules! unwrap_me_mut {
PythonObserver, ($wrapper:expr, $name:ident, $body:block) => {
"Observer", match &mut $wrapper {
PythonObserverWrapper, PythonObserverWrapper::MapI8(py_wrapper) => Python::with_gil(|py| -> PyResult<_> {
PythonStdState, let mut borrowed = py_wrapper.borrow_mut(py);
); Ok(crate::mapob_unwrap_me_mut!(
PythonMapObserverWrapperI8,
borrowed.wrapper,
$name,
$body
))
})
.unwrap(),
PythonObserverWrapper::MapI16(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
Ok(crate::mapob_unwrap_me_mut!(
PythonMapObserverWrapperI16,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
}
PythonObserverWrapper::MapI32(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
Ok(crate::mapob_unwrap_me_mut!(
PythonMapObserverWrapperI32,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
}
PythonObserverWrapper::MapI64(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
Ok(crate::mapob_unwrap_me_mut!(
PythonMapObserverWrapperI64,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
}
PythonObserverWrapper::MapU8(py_wrapper) => Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
Ok(crate::mapob_unwrap_me_mut!(
PythonMapObserverWrapperU8,
borrowed.wrapper,
$name,
$body
))
})
.unwrap(),
PythonObserverWrapper::MapU16(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
Ok(crate::mapob_unwrap_me_mut!(
PythonMapObserverWrapperU16,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
}
PythonObserverWrapper::MapU32(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
Ok(crate::mapob_unwrap_me_mut!(
PythonMapObserverWrapperU32,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
}
PythonObserverWrapper::MapU64(py_wrapper) => {
Python::with_gil(|py| -> PyResult<_> {
let mut borrowed = py_wrapper.borrow_mut(py);
Ok(crate::mapob_unwrap_me_mut!(
PythonMapObserverWrapperU64,
borrowed.wrapper,
$name,
$body
))
})
.unwrap()
}
PythonObserverWrapper::Python(py_wrapper) => {
let $name = py_wrapper;
$body
}
}
};
}
#[pymethods]
impl PythonObserver {
#[staticmethod]
#[must_use]
pub fn new_map_i8(map_observer: Py<PythonMapObserverI8>) -> Self {
Self {
wrapper: PythonObserverWrapper::MapI8(map_observer),
}
}
#[staticmethod]
#[must_use]
pub fn new_map_i16(map_observer: Py<PythonMapObserverI16>) -> Self {
Self {
wrapper: PythonObserverWrapper::MapI16(map_observer),
}
}
#[staticmethod]
#[must_use]
pub fn new_map_i32(map_observer: Py<PythonMapObserverI32>) -> Self {
Self {
wrapper: PythonObserverWrapper::MapI32(map_observer),
}
}
#[staticmethod]
#[must_use]
pub fn new_map_i64(map_observer: Py<PythonMapObserverI64>) -> Self {
Self {
wrapper: PythonObserverWrapper::MapI64(map_observer),
}
}
#[staticmethod]
#[must_use]
pub fn new_map_u8(map_observer: Py<PythonMapObserverU8>) -> Self {
Self {
wrapper: PythonObserverWrapper::MapU8(map_observer),
}
}
#[staticmethod]
#[must_use]
pub fn new_map_u16(map_observer: Py<PythonMapObserverU16>) -> Self {
Self {
wrapper: PythonObserverWrapper::MapU16(map_observer),
}
}
#[staticmethod]
#[must_use]
pub fn new_map_u32(map_observer: Py<PythonMapObserverU32>) -> Self {
Self {
wrapper: PythonObserverWrapper::MapU32(map_observer),
}
}
#[staticmethod]
#[must_use]
pub fn new_map_u64(map_observer: Py<PythonMapObserverU64>) -> Self {
Self {
wrapper: PythonObserverWrapper::MapU64(map_observer),
}
}
#[staticmethod]
#[must_use]
pub fn new_py(py_observer: PyObject) -> Self {
Self {
wrapper: PythonObserverWrapper::Python(PyObjectObserver::new(py_observer)),
}
}
pub fn unwrap_py(&self) -> Option<PyObject> {
match &self.wrapper {
PythonObserverWrapper::Python(pyo) => Some(pyo.inner.clone()),
_ => None,
}
}
}
impl Named for PythonObserver {
fn name(&self) -> &str {
let ptr = unwrap_me!(self.wrapper, o, { o.name() as *const str });
unsafe { ptr.as_ref().unwrap() }
}
}
impl Observer<BytesInput, PythonStdState> for PythonObserver {
fn flush(&mut self) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, o, {
Observer::<BytesInput, PythonStdState>::flush(o)
})
}
fn pre_exec(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, o, { o.pre_exec(state, input) })
}
fn post_exec(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
exit_kind: &ExitKind,
) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, o, { o.post_exec(state, input, exit_kind) })
}
fn pre_exec_child(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, o, { o.pre_exec_child(state, input) })
}
fn post_exec_child(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
exit_kind: &ExitKind,
) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, o, {
o.post_exec_child(state, input, exit_kind)
})
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[pyclass(unsendable, name = "ObserversTuple")]
pub struct PythonObserversTuple {
list: Vec<PythonObserver>,
}
#[pymethods]
impl PythonObserversTuple {
#[new]
fn new(list: Vec<PythonObserver>) -> Self {
Self { list }
}
fn len(&self) -> usize {
self.list.len()
}
fn __getitem__(&self, idx: usize) -> PythonObserver {
self.list[idx].clone()
}
#[pyo3(name = "match_name")]
fn pymatch_name(&self, name: &str) -> Option<PythonObserver> {
for ob in &self.list {
if ob.name() == name {
return Some(ob.clone());
}
}
None
}
}
impl ObserversTuple<BytesInput, PythonStdState> for PythonObserversTuple {
fn pre_exec_all(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
) -> Result<(), Error> {
for ob in &mut self.list {
ob.pre_exec(state, input)?;
}
Ok(())
}
fn post_exec_all(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
exit_kind: &ExitKind,
) -> Result<(), Error> {
for ob in &mut self.list {
ob.post_exec(state, input, exit_kind)?;
}
Ok(())
}
fn pre_exec_child_all(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
) -> Result<(), Error> {
for ob in &mut self.list {
ob.pre_exec_child(state, input)?;
}
Ok(())
}
fn post_exec_child_all(
&mut self,
state: &mut PythonStdState,
input: &BytesInput,
exit_kind: &ExitKind,
) -> Result<(), Error> {
for ob in &mut self.list {
ob.post_exec_child(state, input, exit_kind)?;
}
Ok(())
}
}
impl MatchName for PythonObserversTuple {
fn match_name<T>(&self, name: &str) -> Option<&T> {
unsafe {
let mut r = None;
for ob in &self.list {
Python::with_gil(|py| -> PyResult<_> {
match &ob.wrapper {
PythonObserverWrapper::MapI8(py_wrapper) => {
if type_eq::<PythonMapObserverI8, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow(py)) as *const T)
.as_ref();
}
}
PythonObserverWrapper::MapI16(py_wrapper) => {
if type_eq::<PythonMapObserverI16, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow(py)) as *const T)
.as_ref();
}
}
PythonObserverWrapper::MapI32(py_wrapper) => {
if type_eq::<PythonMapObserverI32, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow(py)) as *const T)
.as_ref();
}
}
PythonObserverWrapper::MapI64(py_wrapper) => {
if type_eq::<PythonMapObserverI64, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow(py)) as *const T)
.as_ref();
}
}
PythonObserverWrapper::MapU8(py_wrapper) => {
if type_eq::<PythonMapObserverU8, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow(py)) as *const T)
.as_ref();
}
}
PythonObserverWrapper::MapU16(py_wrapper) => {
if type_eq::<PythonMapObserverU16, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow(py)) as *const T)
.as_ref();
}
}
PythonObserverWrapper::MapU32(py_wrapper) => {
if type_eq::<PythonMapObserverU32, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow(py)) as *const T)
.as_ref();
}
}
PythonObserverWrapper::MapU64(py_wrapper) => {
if type_eq::<PythonMapObserverU64, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow(py)) as *const T)
.as_ref();
}
}
PythonObserverWrapper::Python(py_wrapper) => {
if type_eq::<PyObjectObserver, T>() && py_wrapper.name() == name {
r = (py_wrapper as *const _ as *const T).as_ref();
}
}
}
Ok(())
})
.unwrap();
}
r
}
}
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> {
unsafe {
let mut r = None;
for ob in &mut self.list {
Python::with_gil(|py| -> PyResult<_> {
match &mut ob.wrapper {
PythonObserverWrapper::MapI8(py_wrapper) => {
if type_eq::<PythonMapObserverI8, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow_mut(py))
as *mut T)
.as_mut();
}
}
PythonObserverWrapper::MapI16(py_wrapper) => {
if type_eq::<PythonMapObserverI16, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow_mut(py))
as *mut T)
.as_mut();
}
}
PythonObserverWrapper::MapI32(py_wrapper) => {
if type_eq::<PythonMapObserverI32, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow_mut(py))
as *mut T)
.as_mut();
}
}
PythonObserverWrapper::MapI64(py_wrapper) => {
if type_eq::<PythonMapObserverI64, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow_mut(py))
as *mut T)
.as_mut();
}
}
PythonObserverWrapper::MapU8(py_wrapper) => {
if type_eq::<PythonMapObserverU8, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow_mut(py))
as *mut T)
.as_mut();
}
}
PythonObserverWrapper::MapU16(py_wrapper) => {
if type_eq::<PythonMapObserverU16, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow_mut(py))
as *mut T)
.as_mut();
}
}
PythonObserverWrapper::MapU32(py_wrapper) => {
if type_eq::<PythonMapObserverU32, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow_mut(py))
as *mut T)
.as_mut();
}
}
PythonObserverWrapper::MapU64(py_wrapper) => {
if type_eq::<PythonMapObserverU64, T>()
&& py_wrapper.borrow(py).name() == name
{
r = (std::ptr::addr_of!(*(*py_wrapper).borrow_mut(py))
as *mut T)
.as_mut();
}
}
PythonObserverWrapper::Python(py_wrapper) => {
if type_eq::<PyObjectObserver, T>() && py_wrapper.name() == name {
r = (py_wrapper as *mut _ as *mut T).as_mut();
}
}
}
Ok(())
})
.unwrap();
}
r
}
}
}
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonObserver>()?; m.add_class::<PythonObserver>()?;
m.add_class::<PythonObserversTuple>()?;
Ok(()) Ok(())
} }
} }

View File

@ -259,187 +259,174 @@ where
/// `Stage` Python bindings /// `Stage` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::impl_asany; use crate::events::pybind::PythonEventManager;
use crate::stages::Stage; use crate::executors::pybind::PythonExecutor;
use crate::fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper};
use crate::stages::mutational::pybind::PythonStdMutationalStage;
use crate::stages::{Stage, StagesTuple};
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper};
use crate::Error; use crate::Error;
use pyo3::prelude::*; use pyo3::prelude::*;
use super::owned::AnyStage; #[derive(Clone, Debug)]
pub struct PyObjectStage {
inner: PyObject,
}
macro_rules! define_python_stage { impl PyObjectStage {
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $std_havoc_mutations_stage_name: ident, $my_std_state_type_name: ident, #[must_use]
$my_std_fuzzer_type_name: ident, $executor_name: ident, $event_manager_name: ident) => { pub fn new(obj: PyObject) -> Self {
use crate::events::pybind::$event_manager_name; PyObjectStage { inner: obj }
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)] impl Stage<PythonExecutor, PythonEventManager, PythonStdState, PythonStdFuzzer> for PyObjectStage {
enum $wrapper_name { #[inline]
StdHavocMutations(*mut $std_havoc_mutations_stage_name), fn perform(
} &mut self,
fuzzer: &mut PythonStdFuzzer,
executor: &mut PythonExecutor,
state: &mut PythonStdState,
manager: &mut PythonEventManager,
corpus_idx: usize,
) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method1(
py,
"perform",
(
PythonStdFuzzerWrapper::wrap(fuzzer),
executor.clone(),
PythonStdStateWrapper::wrap(state),
manager.clone(),
corpus_idx,
),
)?;
Ok(())
})?;
Ok(())
}
}
/// Stage Trait binding #[derive(Clone, Debug)]
#[pyclass(unsendable, name = $py_name_trait)] pub enum PythonStageWrapper {
#[derive(Debug)] StdMutational(Py<PythonStdMutationalStage>),
pub struct $struct_name_trait { Python(PyObjectStage),
stage: $wrapper_name, }
}
#[pymethods] /// Stage Trait binding
impl $struct_name_trait { #[pyclass(unsendable, name = "Stage")]
#[staticmethod] #[derive(Clone, Debug)]
fn new_from_std_scheduled( pub struct PythonStage {
py_std_havoc_mutations_stage: &mut $std_havoc_mutations_stage_name, wrapper: PythonStageWrapper,
) -> Self { }
Self {
stage: $wrapper_name::StdHavocMutations(py_std_havoc_mutations_stage), macro_rules! unwrap_me_mut {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonStageWrapper,
{ StdMutational },
{
Python(py_wrapper) => {
let $name = py_wrapper;
$body
} }
} }
} )
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!( #[pymethods]
PythonStageI8, impl PythonStage {
"StageI8", #[staticmethod]
PythonStageWrapperI8, #[must_use]
PythonStdScheduledHavocMutationsStageI8, pub fn new_std_mutational(
MyStdStateI8, py_std_havoc_mutations_stage: Py<PythonStdMutationalStage>,
MyStdFuzzerI8, ) -> Self {
PythonExecutorI8, Self {
PythonEventManagerI8 wrapper: PythonStageWrapper::StdMutational(py_std_havoc_mutations_stage),
); }
}
define_python_stage!( #[staticmethod]
PythonStageI16, #[must_use]
"StageI16", pub fn new_py(obj: PyObject) -> Self {
PythonStageWrapperI16, Self {
PythonStdScheduledHavocMutationsStageI16, wrapper: PythonStageWrapper::Python(PyObjectStage::new(obj)),
MyStdStateI16, }
MyStdFuzzerI16, }
PythonExecutorI16,
PythonEventManagerI16
);
define_python_stage!( #[must_use]
PythonStageI32, pub fn unwrap_py(&self) -> Option<PyObject> {
"StageI32", match &self.wrapper {
PythonStageWrapperI32, PythonStageWrapper::Python(pyo) => Some(pyo.inner.clone()),
PythonStdScheduledHavocMutationsStageI32, PythonStageWrapper::StdMutational(_) => None,
MyStdStateI32, }
MyStdFuzzerI32, }
PythonExecutorI32, }
PythonEventManagerI32
);
define_python_stage!( impl Stage<PythonExecutor, PythonEventManager, PythonStdState, PythonStdFuzzer> for PythonStage {
PythonStageI64, #[inline]
"StageI64", #[allow(clippy::let_and_return)]
PythonStageWrapperI64, fn perform(
PythonStdScheduledHavocMutationsStageI64, &mut self,
MyStdStateI64, fuzzer: &mut PythonStdFuzzer,
MyStdFuzzerI64, executor: &mut PythonExecutor,
PythonExecutorI64, state: &mut PythonStdState,
PythonEventManagerI64 manager: &mut PythonEventManager,
); corpus_idx: usize,
) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, s, {
s.perform(fuzzer, executor, state, manager, corpus_idx)
})
}
}
define_python_stage!( #[derive(Clone, Debug)]
PythonStageU8, #[pyclass(unsendable, name = "StagesTuple")]
"StageU8", pub struct PythonStagesTuple {
PythonStageWrapperU8, list: Vec<PythonStage>,
PythonStdScheduledHavocMutationsStageU8, }
MyStdStateU8,
MyStdFuzzerU8, #[pymethods]
PythonExecutorU8, impl PythonStagesTuple {
PythonEventManagerU8 #[new]
); fn new(list: Vec<PythonStage>) -> Self {
define_python_stage!( Self { list }
PythonStageU16, }
"StageU16",
PythonStageWrapperU16, fn len(&self) -> usize {
PythonStdScheduledHavocMutationsStageU16, self.list.len()
MyStdStateU16, }
MyStdFuzzerU16,
PythonExecutorU16, fn __getitem__(&self, idx: usize) -> PythonStage {
PythonEventManagerU16 self.list[idx].clone()
); }
define_python_stage!( }
PythonStageU32,
"StageU32", impl StagesTuple<PythonExecutor, PythonEventManager, PythonStdState, PythonStdFuzzer>
PythonStageWrapperU32, for PythonStagesTuple
PythonStdScheduledHavocMutationsStageU32, {
MyStdStateU32, fn perform_all(
MyStdFuzzerU32, &mut self,
PythonExecutorU32, fuzzer: &mut PythonStdFuzzer,
PythonEventManagerU32 executor: &mut PythonExecutor,
); state: &mut PythonStdState,
define_python_stage!( manager: &mut PythonEventManager,
PythonStageU64, corpus_idx: usize,
"StageU64", ) -> Result<(), Error> {
PythonStageWrapperU64, for s in &mut self.list {
PythonStdScheduledHavocMutationsStageU64, s.perform(fuzzer, executor, state, manager, corpus_idx)?;
MyStdStateU64, }
MyStdFuzzerU64, Ok(())
PythonExecutorU64, }
PythonEventManagerU64 }
);
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStageI8>()?; m.add_class::<PythonStage>()?;
m.add_class::<PythonStageI16>()?; m.add_class::<PythonStagesTuple>()?;
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(()) Ok(())
} }
} }

View File

@ -163,161 +163,51 @@ where
} }
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
/// `StdMutationalStage` Python bindings /// `StdMutationalStage` Python bindings
pub mod pybind { pub mod pybind {
use crate::bolts::tuples::tuple_list_type; use crate::events::pybind::PythonEventManager;
use crate::executors::pybind::PythonExecutor;
use crate::fuzzer::pybind::PythonStdFuzzer;
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
pub use crate::mutators::mutations::*; use crate::mutators::pybind::PythonMutator;
pub use crate::mutators::mutations::*; use crate::stages::pybind::PythonStage;
use crate::mutators::{havoc_mutations, StdScheduledMutator};
use crate::stages::StdMutationalStage; use crate::stages::StdMutationalStage;
use crate::state::pybind::PythonStdState;
use pyo3::prelude::*; use pyo3::prelude::*;
type HavocMutationsType = tuple_list_type!( #[pyclass(unsendable, name = "StdMutationalStage")]
BitFlipMutator, #[derive(Debug)]
ByteFlipMutator, /// Python class for StdMutationalStage
ByteIncMutator, pub struct PythonStdMutationalStage {
ByteDecMutator, /// Rust wrapped StdMutationalStage object
ByteNegMutator, pub inner: StdMutationalStage<
ByteRandMutator, PythonExecutor,
ByteAddMutator, PythonEventManager,
WordAddMutator, BytesInput,
DwordAddMutator, PythonMutator,
QwordAddMutator, PythonStdState,
ByteInterestingMutator, PythonStdFuzzer,
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!( #[pymethods]
PythonStdScheduledHavocMutationsStageI8, impl PythonStdMutationalStage {
"StdScheduledHavocMutationsStageI8", #[new]
MyStdStateI8, fn new(mutator: PythonMutator) -> Self {
MyStdFuzzerI8, Self {
PythonExecutorI8, inner: StdMutationalStage::new(mutator),
PythonEventManagerI8 }
); }
define_python_std_mutational_stage!( fn as_stage(slf: Py<Self>) -> PythonStage {
PythonStdScheduledHavocMutationsStageI16, PythonStage::new_std_mutational(slf)
"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 /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdScheduledHavocMutationsStageI8>()?; m.add_class::<PythonStdMutationalStage>()?;
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(()) Ok(())
} }
} }

View File

@ -42,147 +42,3 @@ impl<E, EM, S, Z> StagesOwnedList<E, EM, S, Z> {
Self { list } Self { list }
} }
} }
#[cfg(feature = "python")]
/// `StagesOwnedList` Python bindings
pub mod pybind {
use crate::stages::owned::StagesOwnedList;
use pyo3::prelude::*;
macro_rules! define_python_stage_owned_list {
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident, $event_manager_name: ident,
$executor_name: ident, $stage_name: ident) => {
use crate::events::pybind::$event_manager_name;
use crate::executors::pybind::$executor_name;
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
use crate::stages::pybind::$stage_name;
use crate::state::pybind::$my_std_state_type_name;
#[pyclass(unsendable, name = $py_name)]
/// Python class for StagesOwnedList
#[allow(missing_debug_implementations)]
pub struct $struct_name {
/// Rust wrapped StagesOwnedList object
pub stages_owned_list: StagesOwnedList<
$executor_name,
$event_manager_name,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
>,
}
#[pymethods]
impl $struct_name {
//TODO: Add new from list
#[new]
fn new(stage: &$stage_name) -> Self {
// TODO: Be safe
unsafe {
Self {
stages_owned_list: StagesOwnedList {
list: vec![Box::new(std::mem::transmute_copy::<
$stage_name,
$stage_name,
>(stage))],
},
}
}
}
}
};
}
define_python_stage_owned_list!(
PythonStagesOwnedListI8,
"StagesOwnedListI8",
MyStdStateI8,
MyStdFuzzerI8,
PythonEventManagerI8,
PythonExecutorI8,
PythonStageI8
);
define_python_stage_owned_list!(
PythonStagesOwnedListI16,
"StagesOwnedListI16",
MyStdStateI16,
MyStdFuzzerI16,
PythonEventManagerI16,
PythonExecutorI16,
PythonStageI16
);
define_python_stage_owned_list!(
PythonStagesOwnedListI32,
"StagesOwnedListI32",
MyStdStateI32,
MyStdFuzzerI32,
PythonEventManagerI32,
PythonExecutorI32,
PythonStageI32
);
define_python_stage_owned_list!(
PythonStagesOwnedListI64,
"StagesOwnedListI64",
MyStdStateI64,
MyStdFuzzerI64,
PythonEventManagerI64,
PythonExecutorI64,
PythonStageI64
);
define_python_stage_owned_list!(
PythonStagesOwnedListU8,
"StagesOwnedListU8",
MyStdStateU8,
MyStdFuzzerU8,
PythonEventManagerU8,
PythonExecutorU8,
PythonStageU8
);
define_python_stage_owned_list!(
PythonStagesOwnedListU16,
"StagesOwnedListU16",
MyStdStateU16,
MyStdFuzzerU16,
PythonEventManagerU16,
PythonExecutorU16,
PythonStageU16
);
define_python_stage_owned_list!(
PythonStagesOwnedListU32,
"StagesOwnedListU32",
MyStdStateU32,
MyStdFuzzerU32,
PythonEventManagerU32,
PythonExecutorU32,
PythonStageU32
);
define_python_stage_owned_list!(
PythonStagesOwnedListU64,
"StagesOwnedListU64",
MyStdStateU64,
MyStdFuzzerU64,
PythonEventManagerU64,
PythonExecutorU64,
PythonStageU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStagesOwnedListI8>()?;
m.add_class::<PythonStagesOwnedListI16>()?;
m.add_class::<PythonStagesOwnedListI32>()?;
m.add_class::<PythonStagesOwnedListI64>()?;
m.add_class::<PythonStagesOwnedListU8>()?;
m.add_class::<PythonStagesOwnedListU16>()?;
m.add_class::<PythonStagesOwnedListU32>()?;
m.add_class::<PythonStagesOwnedListU64>()?;
Ok(())
}
}

View File

@ -652,72 +652,137 @@ where
} }
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)]
/// `State` Python bindings /// `State` Python bindings
pub mod pybind { pub mod pybind {
use crate::bolts::ownedref::OwnedPtrMut;
use crate::bolts::rands::pybind::PythonRand; use crate::bolts::rands::pybind::PythonRand;
use crate::bolts::tuples::tuple_list;
use crate::corpus::pybind::PythonCorpus; use crate::corpus::pybind::PythonCorpus;
use crate::events::pybind::PythonEventManager;
use crate::executors::pybind::PythonExecutor;
use crate::feedbacks::pybind::PythonFeedback; use crate::feedbacks::pybind::PythonFeedback;
use crate::fuzzer::pybind::PythonStdFuzzerWrapper;
use crate::generators::pybind::PythonGenerator;
use crate::inputs::BytesInput; use crate::inputs::BytesInput;
use crate::state::StdState; use crate::pybind::PythonMetadata;
use crate::state::{
HasCorpus, HasExecutions, HasMaxSize, HasMetadata, HasRand, HasSolutions, StdState,
};
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyDict;
use std::path::PathBuf;
macro_rules! define_python_state { /// `StdState` with fixed generics
($type_name:ident, $struct_name:ident, $py_name:tt) => { pub type PythonStdState = StdState<PythonCorpus, BytesInput, PythonRand, PythonCorpus>;
use crate::events::pybind::$event_manager_name;
use crate::executors::pybind::$executor_name;
use crate::fuzzer::pybind::$fuzzer_name;
use crate::generators::pybind::$rand_printable_generator;
/// `StdState` with fixed generics #[pyclass(unsendable, name = "StdState")]
pub type $type_name = StdState<PythonCorpus, BytesInput, PythonRand, PythonCorpus>; #[derive(Debug)]
/// Python class for StdState
#[pyclass(unsendable, name = $py_name)] pub struct PythonStdStateWrapper {
#[derive(Debug)] /// Rust wrapped StdState object
/// Python class for StdState pub inner: OwnedPtrMut<PythonStdState>,
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,
feedback: &mut PythonFeedback,
objective: &mut PythonFeedback,
) -> Self {
Self {
std_state: StdState::new(py_rand, corpus, solutions, feedback, objective),
}
}
fn generate_initial_inputs(
&mut self,
py_fuzzer: &mut PythonFuzzer,
py_executor: &mut PythonExecutor,
py_generator: &mut PythonGenerator,
py_mgr: &mut PythonEventManager,
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!(PythonStdState, PythonStdStateWrapper, "StdState",); impl PythonStdStateWrapper {
pub fn wrap(r: &mut PythonStdState) -> Self {
Self {
inner: OwnedPtrMut::Ptr(r),
}
}
#[must_use]
pub fn unwrap(&self) -> &PythonStdState {
self.inner.as_ref()
}
pub fn unwrap_mut(&mut self) -> &mut PythonStdState {
self.inner.as_mut()
}
}
#[pymethods]
impl PythonStdStateWrapper {
#[new]
fn new(
py_rand: PythonRand,
corpus: PythonCorpus,
solutions: PythonCorpus,
feedback: &mut PythonFeedback,
objective: &mut PythonFeedback,
) -> Self {
Self {
inner: OwnedPtrMut::Owned(Box::new(
StdState::new(py_rand, corpus, solutions, feedback, objective)
.expect("Failed to create a new StdState"),
)),
}
}
fn metadata(&mut self) -> PyObject {
let meta = self.inner.as_mut().metadata_mut();
if !meta.contains::<PythonMetadata>() {
Python::with_gil(|py| {
let dict: Py<PyDict> = PyDict::new(py).into();
meta.insert(PythonMetadata::new(dict.to_object(py)));
});
}
meta.get::<PythonMetadata>().unwrap().map.clone()
}
fn rand(&self) -> PythonRand {
self.inner.as_ref().rand().clone()
}
fn corpus(&self) -> PythonCorpus {
self.inner.as_ref().corpus().clone()
}
fn solutions(&self) -> PythonCorpus {
self.inner.as_ref().solutions().clone()
}
fn executions(&self) -> usize {
*self.inner.as_ref().executions()
}
fn max_size(&self) -> usize {
self.inner.as_ref().max_size()
}
fn generate_initial_inputs(
&mut self,
py_fuzzer: &mut PythonStdFuzzerWrapper,
py_executor: &mut PythonExecutor,
py_generator: &mut PythonGenerator,
py_mgr: &mut PythonEventManager,
num: usize,
) {
self.inner
.as_mut()
.generate_initial_inputs(
py_fuzzer.unwrap_mut(),
py_executor,
py_generator,
py_mgr,
num,
)
.expect("Failed to generate the initial corpus");
}
#[allow(clippy::needless_pass_by_value)]
fn load_initial_inputs(
&mut self,
py_fuzzer: &mut PythonStdFuzzerWrapper,
py_executor: &mut PythonExecutor,
py_mgr: &mut PythonEventManager,
in_dirs: Vec<PathBuf>,
) {
self.inner
.as_mut()
.load_initial_inputs(py_fuzzer.unwrap_mut(), py_executor, py_mgr, &in_dirs)
.expect("Failed to load the initial corpus");
}
}
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {

View File

@ -3,9 +3,6 @@ use core::ptr::addr_of_mut;
use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi};
use rangemap::RangeMap; use rangemap::RangeMap;
#[cfg(target_arch = "aarch64")]
use std::ffi::c_void;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use frida_gum::instruction_writer::X86Register; use frida_gum::instruction_writer::X86Register;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]