diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 1d1da3ae84..5b038c4006 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -229,31 +229,6 @@ jobs: - name: Run smoke test run: ./libafl_concolic/test/smoke_test.sh - bindings: - runs-on: ubuntu-latest - steps: - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - - name: Remove existing clang and LLVM - run: sudo apt purge llvm* clang* - - name: Install LLVM and Clang - uses: KyleMayes/install-llvm-action@v1 - with: - directory: ${{ runner.temp }}/llvm - version: 17 - - name: Install deps - run: sudo apt-get install -y ninja-build python3-dev python3-pip python3-venv libz3-dev - - name: Install maturin - run: python3 -m pip install maturin - - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 - - name: Run a maturin build - run: export LLVM_CONFIG=llvm-config-16 && cd ./bindings/pylibafl && python3 -m venv .env && . .env/bin/activate && pip install --upgrade --force-reinstall . && ./test.sh - - name: Run python test - run: . ./bindings/pylibafl/.env/bin/activate && cd ./fuzzers/baby_fuzzer && python3 baby_fuzzer.py 2>&1 | grep "Bye" - fuzzers: strategy: matrix: diff --git a/bindings/pylibafl/.gitignore b/bindings/pylibafl/.gitignore deleted file mode 100644 index 849ddff3b7..0000000000 --- a/bindings/pylibafl/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist/ diff --git a/bindings/pylibafl/Cargo.toml b/bindings/pylibafl/Cargo.toml deleted file mode 100644 index 9a1a034caa..0000000000 --- a/bindings/pylibafl/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "pylibafl" -version = "0.11.2" -edition = "2021" - -[dependencies] -pyo3 = { version = "0.18.3", features = ["extension-module"] } -pyo3-log = "0.8.1" -libafl_sugar = { path = "../../libafl_sugar", version = "0.11.2", features = ["python"] } -libafl = { path = "../../libafl", version = "0.11.2", features = ["python"] } -libafl_bolts = { path = "../../libafl_bolts", version = "0.11.2", features = ["python"] } - -[target.'cfg(target_os = "linux")'.dependencies] -libafl_qemu = { path = "../../libafl_qemu", version = "0.11.2", features = ["python"] } - -[build-dependencies] -pyo3-build-config = { version = "0.17" } - -[lib] -name = "pylibafl" -crate-type = ["cdylib"] - -[profile.dev] -panic = "abort" diff --git a/bindings/pylibafl/README.md b/bindings/pylibafl/README.md deleted file mode 100644 index 3e3922251e..0000000000 --- a/bindings/pylibafl/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# How to use python bindings -## First time setup -```bash -# Install maturin -pip install maturin -# Create virtual environment -python3 -m venv .env -``` -## Build bindings -``` -# Activate virtual environment -source .env/bin/activate -# Build python module -maturin develop -``` -This is going to install `pylibafl` python module into this venv. - -## Use bindings -### Example: Running baby_fuzzer in fuzzers/baby_fuzzer/baby_fuzzer.py -First, make sure the python virtual environment is activated. If not, run `source .env/bin/activate -`. Running `pip freeze` at this point should display the following (versions may differ): -``` -maturin==0.12.6 -pylibafl==0.7.0 -toml==0.10.2 -``` -Then simply run -``` -python PATH_TO_BABY_FUZZER/baby_fuzzer.py -``` -The crashes directory will be created in the directory from which you ran the command. diff --git a/bindings/pylibafl/pyproject.toml b/bindings/pylibafl/pyproject.toml deleted file mode 100644 index 7e62ce01e8..0000000000 --- a/bindings/pylibafl/pyproject.toml +++ /dev/null @@ -1,26 +0,0 @@ -[build-system] -requires = ["maturin[patchelf]>=0.14.10,<0.15"] -build-backend = "maturin" - -[project] -name = "PyLibAFL" -version = "0.10.1" -description = "Advanced Fuzzing Library for Python" -readme = "README.md" -requires-python = ">=3.8" -license = {text = "Apache-2.0"} -classifiers = [ - "License :: OSI Approved :: Apache Software License", - "License :: OSI Approved :: MIT License", - "Programming Language :: Rust", - "Topic :: Security", -] - -[project.urls] -repository = "https://github.com/AFLplusplus/LibAFL.git" - -[tool.maturin] -bindings = "pylibafl" -manifest-path = "Cargo.toml" -python-source = "python" -all-features = true diff --git a/bindings/pylibafl/src/lib.rs b/bindings/pylibafl/src/lib.rs deleted file mode 100644 index 914fca662b..0000000000 --- a/bindings/pylibafl/src/lib.rs +++ /dev/null @@ -1,120 +0,0 @@ -use pyo3::{prelude::*, 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, observers, 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): - pass - def post_exec(self, state, 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] -#[pyo3(name = "pylibafl")] -pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { - pyo3_log::init(); - - let modules = py.import("sys")?.getattr("modules")?; - - let sugar_module = PyModule::new(py, "sugar")?; - libafl_sugar::python_module(py, sugar_module)?; - m.add_submodule(sugar_module)?; - modules.set_item("pylibafl.sugar", sugar_module)?; - - #[cfg(target_os = "linux")] - { - let qemu_module = PyModule::new(py, "qemu")?; - libafl_qemu::python_module(py, qemu_module)?; - m.add_submodule(qemu_module)?; - modules.set_item("pylibafl.qemu", qemu_module)?; - } - - let bolts_module = PyModule::new(py, "libafl_bolts")?; - libafl_bolts::pybind::python_module(py, bolts_module)?; - m.add_submodule(bolts_module)?; - modules.set_item("pylibafl.libafl_bolts", bolts_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(()) -} diff --git a/bindings/pylibafl/test.py b/bindings/pylibafl/test.py deleted file mode 100644 index ecfe35ec90..0000000000 --- a/bindings/pylibafl/test.py +++ /dev/null @@ -1,109 +0,0 @@ -from pylibafl.libafl import * -import ctypes -import platform - -MAP_SIZE = 4096 - - -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) - - -if platform.system() == "Darwin": - libc = ctypes.cdll.LoadLibrary("libc.dylib") -else: - libc = ctypes.cdll.LoadLibrary("libc.so.6") - -# Get a buffer to use for our map observer -libc.calloc.restype = ctypes.c_void_p -area_ptr = libc.calloc(1, MAP_SIZE) - -observer = StdMapObserverI8("mymap", area_ptr, MAP_SIZE) - -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: - """ - The harness fn that the fuzzer will execute in a loop - """ - # print(buf) - - # set the observer map byte from python - 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") - -print("Starting to fuzz from python!") - -fuzzer.fuzz_loop(executor.as_executor(), state, mgr.as_manager(), stage_tuple_list) diff --git a/bindings/pylibafl/test.sh b/bindings/pylibafl/test.sh deleted file mode 100755 index 720488b14c..0000000000 --- a/bindings/pylibafl/test.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -timeout 10 python3 ./test.py -export exit_code=$? -if [ $exit_code -eq 124 ]; then - # 124 = timeout happened. All good. - exit 0 -else - exit $exit_code -fi - diff --git a/fuzzers/python_qemu/fuzz.c b/fuzzers/python_qemu/fuzz.c deleted file mode 100644 index 2f4632db1b..0000000000 --- a/fuzzers/python_qemu/fuzz.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include - -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - // printf("Got %ld bytes.\n", Size); - if (Size >= 4 && *(uint32_t *)Data == 0xaabbccdd) { abort(); } - return 0; -} - -int main() { - char buf[10] = {0}; - LLVMFuzzerTestOneInput(buf, 10); -} diff --git a/fuzzers/python_qemu/fuzzer.py b/fuzzers/python_qemu/fuzzer.py deleted file mode 100644 index fd0245a497..0000000000 --- a/fuzzers/python_qemu/fuzzer.py +++ /dev/null @@ -1,43 +0,0 @@ -# from the maturin venv, after running 'maturin develop' in the pylibafl directory - -from pylibafl import sugar, qemu -import lief - -MAX_SIZE = 0x100 -BINARY_PATH = './a.out' - -emu = qemu.Emulator(['qemu-x86_64', BINARY_PATH], []) - -elf = lief.parse(BINARY_PATH) -test_one_input = elf.get_function_address("LLVMFuzzerTestOneInput") -if elf.is_pie: - test_one_input += emu.load_addr() -print('LLVMFuzzerTestOneInput @ 0x%x' % test_one_input) - -emu.set_breakpoint(test_one_input) -emu.run() - -sp = emu.read_reg(qemu.regs.Rsp) -print('SP = 0x%x' % sp) - -retaddr = int.from_bytes(emu.read_mem(sp, 8), 'little') -print('RET = 0x%x' % retaddr) - -inp = emu.map_private(0, MAX_SIZE, qemu.mmap.ReadWrite) -assert(inp > 0) - -emu.remove_breakpoint(test_one_input) -emu.set_breakpoint(retaddr) - -def harness(b): - if len(b) > MAX_SIZE: - b = b[:MAX_SIZE] - emu.write_mem(inp, b) - emu.write_reg(qemu.regs.Rsi, len(b)) - emu.write_reg(qemu.regs.Rdi, inp) - emu.write_reg(qemu.regs.Rsp, sp) - emu.write_reg(qemu.regs.Rip, test_one_input) - emu.run() - -fuzz = sugar.QemuBytesCoverageSugar(['./in'], './out', 3456, [0,1,2,3]) -fuzz.run(emu, harness) diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 7774f7916f..02baecb3d1 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -32,9 +32,6 @@ introspection = [] ## Collects stats about scalability scalability_introspection = [] -## Will build the `pyo3` bindings -python = ["pyo3", "concat-idents", "libafl_bolts/python"] - ## Expose `libafl::prelude` for access without additional using directives prelude = ["libafl_bolts/prelude"] @@ -181,7 +178,6 @@ wait-timeout = { version = "0.2", optional = true } # used by CommandExecutor to z3 = { version = "0.12.0", features = ["static-link-z3"], optional = true } # for concolic mutation -pyo3 = { version = "0.18", optional = true, features = ["serde", "macros"] } concat-idents = { version = "1.1.3", optional = true } libcasr = { version = "2.7", optional = true } diff --git a/libafl/src/corpus/cached.rs b/libafl/src/corpus/cached.rs index d801f64e68..6385f7687a 100644 --- a/libafl/src/corpus/cached.rs +++ b/libafl/src/corpus/cached.rs @@ -248,47 +248,3 @@ where &self.inner } } - -/// ``CachedOnDiskCorpus`` Python bindings -#[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -pub mod pybind { - use alloc::string::String; - use std::path::PathBuf; - - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use crate::{ - corpus::{pybind::PythonCorpus, CachedOnDiskCorpus}, - inputs::BytesInput, - }; - - #[pyclass(unsendable, name = "CachedOnDiskCorpus")] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - /// Python class for CachedOnDiskCorpus - pub struct PythonCachedOnDiskCorpus { - /// Rust wrapped CachedOnDiskCorpus object - pub inner: CachedOnDiskCorpus, - } - - #[pymethods] - impl PythonCachedOnDiskCorpus { - #[new] - fn new(path: String, cache_max_len: usize) -> Self { - Self { - inner: CachedOnDiskCorpus::new(PathBuf::from(path), cache_max_len).unwrap(), - } - } - - fn as_corpus(slf: Py) -> PythonCorpus { - PythonCorpus::new_cached_on_disk(slf) - } - } - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/corpus/inmemory.rs b/libafl/src/corpus/inmemory.rs index a81a75d4ed..7bcae71f95 100644 --- a/libafl/src/corpus/inmemory.rs +++ b/libafl/src/corpus/inmemory.rs @@ -426,44 +426,3 @@ where } } } - -/// `InMemoryCorpus` Python bindings -#[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -pub mod pybind { - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use crate::{ - corpus::{pybind::PythonCorpus, InMemoryCorpus}, - inputs::BytesInput, - }; - - #[pyclass(unsendable, name = "InMemoryCorpus")] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - /// Python class for InMemoryCorpus - pub struct PythonInMemoryCorpus { - /// Rust wrapped InMemoryCorpus object - pub inner: InMemoryCorpus, - } - - #[pymethods] - impl PythonInMemoryCorpus { - #[new] - fn new() -> Self { - Self { - inner: InMemoryCorpus::new(), - } - } - - fn as_corpus(slf: Py) -> PythonCorpus { - PythonCorpus::new_in_memory(slf) - } - } - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index 75fad60d27..91e7ca0154 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -437,47 +437,3 @@ where &self.dir_path } } - -#[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -/// `InMemoryOnDiskCorpus` Python bindings -pub mod pybind { - use alloc::string::String; - use std::path::PathBuf; - - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use crate::{ - corpus::{pybind::PythonCorpus, InMemoryOnDiskCorpus}, - inputs::BytesInput, - }; - - #[pyclass(unsendable, name = "InMemoryOnDiskCorpus")] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - /// Python class for InMemoryOnDiskCorpus - pub struct PythonInMemoryOnDiskCorpus { - /// Rust wrapped InMemoryOnDiskCorpus object - pub inner: InMemoryOnDiskCorpus, - } - - #[pymethods] - impl PythonInMemoryOnDiskCorpus { - #[new] - fn new(path: String) -> Self { - Self { - inner: InMemoryOnDiskCorpus::new(PathBuf::from(path)).unwrap(), - } - } - - fn as_corpus(slf: Py) -> PythonCorpus { - PythonCorpus::new_in_memory_on_disk(slf) - } - } - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 1dee0655ca..8c677b6a5d 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -200,243 +200,3 @@ where } } } - -/// `Corpus` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - use std::cell::RefCell; - - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use crate::{ - corpus::{ - cached::pybind::PythonCachedOnDiskCorpus, inmemory::pybind::PythonInMemoryCorpus, - inmemory_ondisk::pybind::PythonInMemoryOnDiskCorpus, - ondisk::pybind::PythonOnDiskCorpus, testcase::pybind::PythonTestcaseWrapper, Corpus, - CorpusId, HasTestcase, Testcase, - }, - inputs::{BytesInput, UsesInput}, - Error, - }; - - #[derive(Serialize, Deserialize, Debug, Clone)] - enum PythonCorpusWrapper { - InMemory(Py), - CachedOnDisk(Py), - OnDisk(Py), - InMemoryOnDisk(Py), - } - - /// Corpus Trait binding - #[pyclass(unsendable, name = "Corpus")] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct PythonCorpus { - wrapper: PythonCorpusWrapper, - } - - macro_rules! unwrap_me { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_body!( - $wrapper, - $name, - $body, - PythonCorpusWrapper, - { - InMemory, - InMemoryOnDisk, - CachedOnDisk, - OnDisk - } - ) - }; - } - - macro_rules! unwrap_me_mut { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_mut_body!( - $wrapper, - $name, - $body, - PythonCorpusWrapper, - { - InMemory, - InMemoryOnDisk, - CachedOnDisk, - OnDisk - } - ) - }; - } - - #[pymethods] - impl PythonCorpus { - #[staticmethod] - #[must_use] - pub fn new_in_memory(py_in_memory_corpus: Py) -> Self { - Self { - wrapper: PythonCorpusWrapper::InMemory(py_in_memory_corpus), - } - } - - #[staticmethod] - #[must_use] - pub fn new_cached_on_disk(py_cached_on_disk_corpus: Py) -> Self { - Self { - wrapper: PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus), - } - } - - #[staticmethod] - #[must_use] - pub fn new_on_disk(py_on_disk_corpus: Py) -> Self { - Self { - wrapper: PythonCorpusWrapper::OnDisk(py_on_disk_corpus), - } - } - - #[staticmethod] - #[must_use] - pub fn new_in_memory_on_disk( - py_in_memory_on_disk_corpus: Py, - ) -> Self { - Self { - wrapper: PythonCorpusWrapper::InMemoryOnDisk(py_in_memory_on_disk_corpus), - } - } - - #[pyo3(name = "count")] - fn pycount(&self) -> usize { - self.count() - } - - #[pyo3(name = "current")] - fn pycurrent(&self) -> Option { - self.current().map(|x| x.0) - } - - #[pyo3(name = "get")] - fn pyget(&self, idx: usize) -> PythonTestcaseWrapper { - let t: &mut Testcase = unwrap_me!(self.wrapper, c, { - c.get(CorpusId::from(idx)) - .map(|v| unsafe { v.as_ptr().as_mut().unwrap() }) - .expect("PythonCorpus::get failed") - }); - PythonTestcaseWrapper::wrap(t) - } - } - - impl UsesInput for PythonCorpus { - type Input = BytesInput; - } - - impl Corpus for PythonCorpus { - #[inline] - fn count(&self) -> usize { - unwrap_me!(self.wrapper, c, { c.count() }) - } - - #[inline] - fn add(&mut self, testcase: Testcase) -> Result { - unwrap_me_mut!(self.wrapper, c, { c.add(testcase) }) - } - - #[inline] - fn replace( - &mut self, - idx: CorpusId, - testcase: Testcase, - ) -> Result, Error> { - unwrap_me_mut!(self.wrapper, c, { c.replace(idx, testcase) }) - } - - #[inline] - fn remove(&mut self, idx: CorpusId) -> Result, Error> { - unwrap_me_mut!(self.wrapper, c, { c.remove(idx) }) - } - - #[inline] - fn get(&self, idx: CorpusId) -> Result<&RefCell>, Error> { - let ptr = unwrap_me!(self.wrapper, c, { - c.get(idx) - .map(core::ptr::from_ref::>>) - })?; - Ok(unsafe { ptr.as_ref().unwrap() }) - } - - #[inline] - fn current(&self) -> &Option { - let ptr = unwrap_me!(self.wrapper, c, { core::ptr::from_ref(c.current()) }); - unsafe { ptr.as_ref().unwrap() } - } - - #[inline] - fn current_mut(&mut self) -> &mut Option { - let ptr = unwrap_me_mut!(self.wrapper, c, { core::ptr::from_mut(c.current_mut()) }); - unsafe { ptr.as_mut().unwrap() } - } - - fn next(&self, idx: CorpusId) -> Option { - unwrap_me!(self.wrapper, c, { c.next(idx) }) - } - - fn prev(&self, idx: CorpusId) -> Option { - unwrap_me!(self.wrapper, c, { c.prev(idx) }) - } - - fn first(&self) -> Option { - unwrap_me!(self.wrapper, c, { c.first() }) - } - - fn last(&self) -> Option { - unwrap_me!(self.wrapper, c, { c.last() }) - } - - fn load_input_into(&self, testcase: &mut Testcase) -> Result<(), Error> { - unwrap_me!(self.wrapper, c, { c.load_input_into(testcase) }) - } - - fn store_input_from(&self, testcase: &Testcase) -> Result<(), Error> { - unwrap_me!(self.wrapper, c, { c.store_input_from(testcase) }) - } - - /*fn ids<'a>(&'a self) -> CorpusIdIterator<'a, Self> { - CorpusIdIterator { - corpus: self, - cur: self.first(), - cur_back: self.last(), - } - } - - fn random_id(&self, next_random: u64) -> CorpusId { - let nth = (next_random as usize) % self.count(); - self.ids() - .nth(nth) - .expect("Failed to get a random CorpusId") - }*/ - } - - impl HasTestcase for PythonCorpus { - fn testcase( - &self, - id: CorpusId, - ) -> Result::Input>>, Error> { - Ok(self.get(id)?.borrow()) - } - - fn testcase_mut( - &self, - id: CorpusId, - ) -> Result::Input>>, Error> { - Ok(self.get(id)?.borrow_mut()) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 08b9a519c2..fc0a901e45 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -260,47 +260,3 @@ where &self.dir_path } } - -#[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -/// `OnDiskCorpus` Python bindings -pub mod pybind { - use alloc::string::String; - use std::path::PathBuf; - - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use crate::{ - corpus::{pybind::PythonCorpus, OnDiskCorpus}, - inputs::BytesInput, - }; - - #[pyclass(unsendable, name = "OnDiskCorpus")] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - /// Python class for OnDiskCorpus - pub struct PythonOnDiskCorpus { - /// Rust wrapped OnDiskCorpus object - pub inner: OnDiskCorpus, - } - - #[pymethods] - impl PythonOnDiskCorpus { - #[new] - fn new(path: String) -> Self { - Self { - inner: OnDiskCorpus::new(PathBuf::from(path)).unwrap(), - } - } - - fn as_corpus(slf: Py) -> PythonCorpus { - PythonCorpus::new_on_disk(slf) - } - } - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/corpus/testcase.rs b/libafl/src/corpus/testcase.rs index 4d06586e2c..7aa7723408 100644 --- a/libafl/src/corpus/testcase.rs +++ b/libafl/src/corpus/testcase.rs @@ -485,91 +485,3 @@ where } } } - -#[cfg(feature = "python")] -#[allow(missing_docs)] -/// `Testcase` Python bindings -pub mod pybind { - use alloc::{boxed::Box, vec::Vec}; - - use libafl_bolts::ownedref::OwnedMutPtr; - use pyo3::{prelude::*, types::PyDict}; - - use super::{HasMetadata, Testcase}; - use crate::{inputs::BytesInput, pybind::PythonMetadata}; - - /// `PythonTestcase` with fixed generics - pub type PythonTestcase = Testcase; - - #[pyclass(unsendable, name = "Testcase")] - #[derive(Debug)] - /// Python class for Testcase - pub struct PythonTestcaseWrapper { - /// Rust wrapped Testcase object - pub inner: OwnedMutPtr, - } - - impl PythonTestcaseWrapper { - pub fn wrap(r: &mut PythonTestcase) -> Self { - Self { - inner: OwnedMutPtr::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) -> Self { - Self { - inner: OwnedMutPtr::Owned(Box::new(PythonTestcase::new(BytesInput::new(input)))), - } - } - - #[getter] - fn exec_time_ms(&self) -> Option { - self.inner.as_ref().exec_time().map(|t| t.as_millis()) - } - - #[getter] - fn executions(&self) -> u64 { - *self.inner.as_ref().executions() - } - - #[getter] - fn parent_id(&self) -> Option { - self.inner.as_ref().parent_id().map(|x| x.0) - } - - #[getter] - fn scheduled_count(&self) -> usize { - self.inner.as_ref().scheduled_count() - } - - fn metadata(&mut self) -> PyObject { - let meta = self.inner.as_mut().metadata_map_mut(); - if !meta.contains::() { - Python::with_gil(|py| { - let dict: Py = PyDict::new(py).into(); - meta.insert(PythonMetadata::new(dict.to_object(py))); - }); - } - meta.get::().unwrap().map.clone() - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 345f5f1ece..d91223b44f 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -911,100 +911,3 @@ mod tests { }; } } - -/// `EventManager` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - use pyo3::prelude::*; - - use crate::{ - events::{ - simple::pybind::PythonSimpleEventManager, Event, EventFirer, EventManager, - EventManagerId, EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter, - }, - executors::pybind::PythonExecutor, - fuzzer::pybind::PythonStdFuzzer, - inputs::BytesInput, - state::{pybind::PythonStdState, UsesState}, - Error, - }; - - #[derive(Debug, Clone)] - pub enum PythonEventManagerWrapper { - Simple(Py), - } - - /// EventManager Trait binding - #[pyclass(unsendable, name = "EventManager")] - #[derive(Debug, Clone)] - pub struct PythonEventManager { - pub wrapper: PythonEventManagerWrapper, - } - - macro_rules! unwrap_me { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_body!($wrapper, $name, $body, PythonEventManagerWrapper, { - Simple - }) - }; - } - - macro_rules! unwrap_me_mut { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_mut_body!($wrapper, $name, $body, PythonEventManagerWrapper, { - Simple - }) - }; - } - - #[pymethods] - impl PythonEventManager { - #[staticmethod] - #[must_use] - pub fn new_simple(mgr: Py) -> Self { - Self { - wrapper: PythonEventManagerWrapper::Simple(mgr), - } - } - } - - impl UsesState for PythonEventManager { - type State = PythonStdState; - } - - impl EventFirer for PythonEventManager { - fn fire(&mut self, state: &mut Self::State, event: Event) -> Result<(), Error> { - unwrap_me_mut!(self.wrapper, e, { e.fire(state, event) }) - } - } - - impl EventRestarter for PythonEventManager {} - - impl EventProcessor for PythonEventManager { - fn process( - &mut self, - fuzzer: &mut PythonStdFuzzer, - state: &mut PythonStdState, - executor: &mut PythonExecutor, - ) -> Result { - unwrap_me_mut!(self.wrapper, e, { e.process(fuzzer, state, executor) }) - } - } - - impl ProgressReporter for PythonEventManager {} - - impl HasEventManagerId for PythonEventManager { - fn mgr_id(&self) -> EventManagerId { - unwrap_me!(self.wrapper, e, { e.mgr_id() }) - } - } - - impl EventManager for PythonEventManager {} - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/events/simple.rs b/libafl/src/events/simple.rs index a6ab1bde70..52fd880afd 100644 --- a/libafl/src/events/simple.rs +++ b/libafl/src/events/simple.rs @@ -601,45 +601,3 @@ where Ok((state, mgr)) } } - -/// `SimpleEventManager` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -pub mod pybind { - use pyo3::prelude::*; - - use crate::{ - events::{pybind::PythonEventManager, SimpleEventManager}, - monitors::pybind::PythonMonitor, - state::pybind::PythonStdState, - }; - - #[pyclass(unsendable, name = "SimpleEventManager")] - #[derive(Debug)] - /// Python class for SimpleEventManager - pub struct PythonSimpleEventManager { - /// Rust wrapped SimpleEventManager object - pub inner: SimpleEventManager, - } - - #[pymethods] - impl PythonSimpleEventManager { - #[new] - fn new(py_monitor: PythonMonitor) -> Self { - Self { - inner: SimpleEventManager::new(py_monitor), - } - } - - fn as_manager(slf: Py) -> PythonEventManager { - PythonEventManager::new_simple(slf) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index cd8903e797..66d9a197be 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -565,74 +565,3 @@ mod tests { .unwrap(); } } - -#[cfg(feature = "python")] -#[allow(missing_docs)] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -/// `InProcess` Python bindings -pub mod pybind { - use alloc::boxed::Box; - - use libafl_bolts::tuples::tuple_list; - use pyo3::{prelude::*, types::PyBytes}; - - use crate::{ - events::pybind::PythonEventManager, - executors::{inprocess::OwnedInProcessExecutor, pybind::PythonExecutor, ExitKind}, - fuzzer::pybind::PythonStdFuzzerWrapper, - inputs::{BytesInput, HasBytesVec}, - observers::pybind::PythonObserversTuple, - state::pybind::{PythonStdState, PythonStdStateWrapper}, - }; - - #[pyclass(unsendable, name = "InProcessExecutor")] - #[derive(Debug)] - /// Python class for OwnedInProcessExecutor (i.e. InProcessExecutor with owned harness) - pub struct PythonOwnedInProcessExecutor { - /// Rust wrapped OwnedInProcessExecutor object - pub inner: OwnedInProcessExecutor, - } - - #[pymethods] - impl PythonOwnedInProcessExecutor { - #[new] - fn new( - harness: PyObject, - py_observers: PythonObserversTuple, - py_fuzzer: &mut PythonStdFuzzerWrapper, - py_state: &mut PythonStdStateWrapper, - py_event_manager: &mut PythonEventManager, - ) -> Self { - Self { - inner: OwnedInProcessExecutor::generic( - tuple_list!(), - 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"), - } - } - - #[must_use] - pub fn as_executor(slf: Py) -> PythonExecutor { - PythonExecutor::new_inprocess(slf) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index 66ddb54a39..824b8d58e7 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -257,274 +257,3 @@ pub mod test { .unwrap(); } } - -#[cfg(feature = "python")] -#[allow(missing_docs)] -/// `Executor` Python bindings -pub mod pybind { - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use crate::{ - events::pybind::PythonEventManager, - executors::{ - inprocess::pybind::PythonOwnedInProcessExecutor, Executor, ExitKind, HasObservers, - }, - fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper}, - inputs::HasBytesVec, - observers::{pybind::PythonObserversTuple, UsesObservers}, - state::{ - pybind::{PythonStdState, PythonStdStateWrapper}, - UsesState, - }, - Error, - }; - - #[pyclass(unsendable, name = "ExitKind")] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct PythonExitKind { - pub inner: ExitKind, - } - - impl From for PythonExitKind { - fn from(inner: ExitKind) -> Self { - 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, - } - } - - #[staticmethod] - #[must_use] - fn crash() -> Self { - Self { - inner: ExitKind::Crash, - } - } - - #[staticmethod] - #[must_use] - fn oom() -> Self { - Self { - inner: ExitKind::Oom, - } - } - - #[staticmethod] - #[must_use] - fn timeout() -> Self { - 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 { - obj.call_method1(py, "observers", ())?.extract(py) - }) - .unwrap(); - PyObjectExecutor { inner: obj, tuple } - } - } - - impl UsesState for PyObjectExecutor { - type State = PythonStdState; - } - - impl UsesObservers for PyObjectExecutor { - type Observers = PythonObserversTuple; - } - - impl HasObservers for PyObjectExecutor { - #[inline] - fn observers(&self) -> &PythonObserversTuple { - &self.tuple - } - - #[inline] - fn observers_mut(&mut self) -> &mut PythonObserversTuple { - &mut self.tuple - } - } - - impl Executor for PyObjectExecutor { - #[inline] - fn run_target( - &mut self, - fuzzer: &mut PythonStdFuzzer, - state: &mut Self::State, - mgr: &mut PythonEventManager, - input: &Self::Input, - ) -> Result { - 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), - 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) => { - libafl_bolts::unwrap_me_body!($wrapper, $name, $body, PythonExecutorWrapper, - { InProcess }, - { - Python(py_wrapper) => { - let $name = py_wrapper; - $body - } - } - ) - }; - } - - macro_rules! unwrap_me_mut { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_mut_body!($wrapper, $name, $body, PythonExecutorWrapper, - { InProcess }, - { - Python(py_wrapper) => { - let $name = py_wrapper; - $body - } - } - ) - }; - } - - #[pymethods] - impl PythonExecutor { - #[staticmethod] - #[must_use] - pub fn new_inprocess(owned_inprocess_executor: Py) -> 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 { - match &self.wrapper { - PythonExecutorWrapper::Python(pyo) => Some(pyo.inner.clone()), - PythonExecutorWrapper::InProcess(_) => None, - } - } - } - - impl UsesState for PythonExecutor { - type State = PythonStdState; - } - - impl UsesObservers for PythonExecutor { - type Observers = PythonObserversTuple; - } - - impl HasObservers for PythonExecutor { - #[inline] - fn observers(&self) -> &PythonObserversTuple { - let ptr = unwrap_me!(self.wrapper, e, { core::ptr::from_ref(e.observers()) }); - unsafe { ptr.as_ref().unwrap() } - } - - #[inline] - fn observers_mut(&mut self) -> &mut PythonObserversTuple { - let ptr = unwrap_me_mut!(self.wrapper, e, { core::ptr::from_mut(e.observers_mut()) }); - unsafe { ptr.as_mut().unwrap() } - } - } - - impl Executor for PythonExecutor { - #[inline] - fn run_target( - &mut self, - fuzzer: &mut PythonStdFuzzer, - state: &mut Self::State, - mgr: &mut PythonEventManager, - input: &Self::Input, - ) -> Result { - unwrap_me_mut!(self.wrapper, e, { e.run_target(fuzzer, state, mgr, input) }) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index f70b87c413..69e777d8f8 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -854,127 +854,3 @@ mod tests { assert!(!NextPow2IsNovel::is_novel(255_u8, 255)); } } - -/// `MapFeedback` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - use concat_idents::concat_idents; - use pyo3::prelude::*; - - use super::{Debug, HasObserverName, MaxMapFeedback}; - use crate::{feedbacks::pybind::PythonFeedback, state::pybind::PythonStdState}; - - macro_rules! define_python_map_feedback { - ($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)] - #[derive(Debug, Clone)] - /// Python class for MaxMapFeedback - pub struct $struct_name { - /// Rust wrapped MaxMapFeedback object - pub inner: MaxMapFeedback< - $map_observer_type_name, /* PythonMapObserverI8 */ - $my_std_state_type_name, - $datatype, - >, - } - - #[pymethods] - impl $struct_name { - #[new] - fn new(observer: &$map_observer_type_name) -> Self { - Self { - inner: MaxMapFeedback::new(observer), - } - } - - #[must_use] - pub fn as_feedback(slf: Py) -> PythonFeedback { - concat_idents!(func = new_max_map_,$datatype { - PythonFeedback::func(slf) - }) - } - } - - impl HasObserverName for $struct_name { - fn observer_name(&self) -> &str { - self.inner.observer_name() - } - } - }; - } - - define_python_map_feedback!( - PythonMaxMapFeedbackI8, - "MaxMapFeedbackI8", - i8, - PythonMapObserverI8, - PythonStdState - ); - define_python_map_feedback!( - PythonMaxMapFeedbackI16, - "MaxMapFeedbackI16", - i16, - PythonMapObserverI16, - PythonStdState - ); - define_python_map_feedback!( - PythonMaxMapFeedbackI32, - "MaxMapFeedbackI32", - i32, - PythonMapObserverI32, - PythonStdState - ); - define_python_map_feedback!( - PythonMaxMapFeedbackI64, - "MaxMapFeedbackI64", - i64, - PythonMapObserverI64, - PythonStdState - ); - - define_python_map_feedback!( - PythonMaxMapFeedbackU8, - "MaxMapFeedbackU8", - u8, - PythonMapObserverU8, - PythonStdState - ); - define_python_map_feedback!( - PythonMaxMapFeedbackU16, - "MaxMapFeedbackU16", - u16, - PythonMapObserverU16, - PythonStdState - ); - define_python_map_feedback!( - PythonMaxMapFeedbackU32, - "MaxMapFeedbackU32", - u32, - PythonMapObserverU32, - PythonStdState - ); - define_python_map_feedback!( - PythonMaxMapFeedbackU64, - "MaxMapFeedbackU64", - u64, - PythonMapObserverU64, - PythonStdState - ); - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index ce63e5f58a..1627054931 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -1034,604 +1034,3 @@ impl From for ConstFeedback { } } } - -/// `Feedback` Python bindings -#[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -#[allow(missing_docs)] -pub mod pybind { - use core::ptr; - use std::cell::UnsafeCell; - - use libafl_bolts::Named; - use pyo3::prelude::*; - - use super::{ - ConstFeedback, CrashFeedback, Debug, EagerAndFeedback, EagerOrFeedback, FastAndFeedback, - FastOrFeedback, Feedback, NotFeedback, String, ToString, - }; - use crate::{ - corpus::{testcase::pybind::PythonTestcaseWrapper, Testcase}, - events::{pybind::PythonEventManager, EventFirer}, - executors::{pybind::PythonExitKind, ExitKind}, - feedbacks::map::pybind::{ - PythonMaxMapFeedbackI16, PythonMaxMapFeedbackI32, PythonMaxMapFeedbackI64, - PythonMaxMapFeedbackI8, PythonMaxMapFeedbackU16, PythonMaxMapFeedbackU32, - PythonMaxMapFeedbackU64, PythonMaxMapFeedbackU8, - }, - inputs::{BytesInput, HasBytesVec}, - observers::{pybind::PythonObserversTuple, ObserversTuple}, - state::pybind::{PythonStdState, PythonStdStateWrapper}, - Error, - }; - - #[derive(Debug)] - pub struct PyObjectFeedback { - inner: PyObject, - name: UnsafeCell, - } - - impl Clone for PyObjectFeedback { - fn clone(&self) -> PyObjectFeedback { - PyObjectFeedback { - inner: self.inner.clone(), - name: UnsafeCell::new(String::new()), - } - } - } - - impl PyObjectFeedback { - #[must_use] - pub fn new(obj: PyObject) -> Self { - PyObjectFeedback { - inner: obj, - name: UnsafeCell::new(String::new()), - } - } - } - - // crate::impl_serde_pyobjectwrapper!(PyObjectObserver, inner); - - impl Named for PyObjectFeedback { - fn name(&self) -> &str { - let s = Python::with_gil(|py| -> PyResult { - let s: String = self.inner.call_method0(py, "name")?.extract(py)?; - Ok(s) - }) - .unwrap(); - unsafe { - *self.name.get() = s; - &*self.name.get() - } - } - } - - impl Feedback 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( - &mut self, - state: &mut PythonStdState, - manager: &mut EM, - input: &BytesInput, - observers: &OT, - exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - // # Safety - // We use this observer in Python ony when the ObserverTuple is PythonObserversTuple - let dont_look_at_this: &PythonObserversTuple = - unsafe { &*(ptr::from_ref(observers) as *const PythonObserversTuple) }; - let dont_look_at_this2: &PythonEventManager = - unsafe { &*(ptr::from_mut(manager) as *const PythonEventManager) }; - Ok(Python::with_gil(|py| -> PyResult { - 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, - _manager: &mut EM, - observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - { - // # Safety - // We use this observer in Python ony when the ObserverTuple is PythonObserversTuple - let dont_look_at_this: &PythonObserversTuple = - unsafe { &*(ptr::from_ref(observers) as *const PythonObserversTuple) }; - Python::with_gil(|py| -> PyResult<()> { - self.inner.call_method1( - py, - "append_metadata", - ( - PythonStdStateWrapper::wrap(state), - dont_look_at_this.clone(), - 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) -> 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) -> PythonFeedback { - PythonFeedback::new_const(slf) - } - } - - #[derive(Debug)] - #[pyclass(unsendable, name = "NotFeedback")] - pub struct PythonNotFeedback { - pub inner: NotFeedback, - } - - #[pymethods] - impl PythonNotFeedback { - #[new] - fn new(feedback: PythonFeedback) -> Self { - Self { - inner: NotFeedback::new(feedback), - } - } - - #[must_use] - pub fn as_feedback(slf: Py) -> 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, - } - - #[pymethods] - impl $pyname { - #[new] - fn new(a: PythonFeedback, b: PythonFeedback) -> Self { - Self { - inner: $feed::new(a, b), - } - } - - #[must_use] - pub fn as_feedback(slf: Py) -> PythonFeedback { - PythonFeedback::$method(slf) - } - } - }; - } - - define_combined!( - EagerAndFeedback, - PythonEagerAndFeedback, - "EagerAndFeedback", - 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), - MaxMapI16(Py), - MaxMapI32(Py), - MaxMapI64(Py), - MaxMapU8(Py), - MaxMapU16(Py), - MaxMapU32(Py), - MaxMapU64(Py), - Crash(Py), - Const(Py), - Not(Py), - And(Py), - FastAnd(Py), - Or(Py), - FastOr(Py), - Python(PyObjectFeedback), - } - - #[pyclass(unsendable, name = "Feedback")] - #[derive(Debug)] - /// Observer Trait binding - pub struct PythonFeedback { - pub wrapper: PythonFeedbackWrapper, - name: UnsafeCell, - } - - macro_rules! unwrap_me { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::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) => { - libafl_bolts::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) -> Self { - Self { - wrapper: PythonFeedbackWrapper::MaxMapI8(map_feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_max_map_i16(map_feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::MaxMapI16(map_feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_max_map_i32(map_feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::MaxMapI32(map_feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_max_map_i64(map_feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::MaxMapI64(map_feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_max_map_u8(map_feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::MaxMapU8(map_feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_max_map_u16(map_feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::MaxMapU16(map_feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_max_map_u32(map_feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::MaxMapU32(map_feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_max_map_u64(map_feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::MaxMapU64(map_feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_crash(feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::Crash(feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_const(feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::Const(feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_not(feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::Not(feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_and(feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::And(feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_fast_and(feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::FastAnd(feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_or(feedback: Py) -> Self { - Self { - wrapper: PythonFeedbackWrapper::Or(feedback), - name: UnsafeCell::new(String::new()), - } - } - - #[staticmethod] - #[must_use] - pub fn new_fast_or(feedback: Py) -> 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 { - 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 for PythonFeedback { - fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> { - unwrap_me_mut!(self.wrapper, f, { - Feedback::::init_state(f, state) - }) - } - - fn is_interesting( - &mut self, - state: &mut PythonStdState, - manager: &mut EM, - input: &BytesInput, - observers: &OT, - exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - unwrap_me_mut!(self.wrapper, f, { - f.is_interesting(state, manager, input, observers, exit_kind) - }) - } - - fn append_metadata( - &mut self, - state: &mut PythonStdState, - manager: &mut EM, - observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { - unwrap_me_mut!(self.wrapper, f, { - f.append_metadata(state, manager, observers, 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 - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index 7f7c491a7d..2a9ab3c086 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -811,110 +811,3 @@ pub mod test { } } } - -#[cfg(feature = "python")] -#[allow(missing_docs)] -/// `Fuzzer` Python bindings -pub mod pybind { - use alloc::{boxed::Box, vec::Vec}; - - use libafl_bolts::ownedref::OwnedMutPtr; - use pyo3::prelude::*; - - use crate::{ - events::pybind::PythonEventManager, - executors::pybind::PythonExecutor, - feedbacks::pybind::PythonFeedback, - fuzzer::{Evaluator, Fuzzer, StdFuzzer}, - inputs::BytesInput, - observers::pybind::PythonObserversTuple, - schedulers::QueueScheduler, - stages::pybind::PythonStagesTuple, - state::pybind::{PythonStdState, PythonStdStateWrapper}, - }; - - /// `StdFuzzer` with fixed generics - pub type PythonStdFuzzer = StdFuzzer< - QueueScheduler, - PythonFeedback, - PythonFeedback, - PythonObserversTuple, - >; - - /// Python class for StdFuzzer - #[pyclass(unsendable, name = "StdFuzzer")] - #[derive(Debug)] - pub struct PythonStdFuzzerWrapper { - /// Rust wrapped StdFuzzer object - pub inner: OwnedMutPtr, - } - - impl PythonStdFuzzerWrapper { - pub fn wrap(r: &mut PythonStdFuzzer) -> Self { - Self { - inner: OwnedMutPtr::Ptr(r), - } - } - - #[must_use] - pub fn unwrap(&self) -> &PythonStdFuzzer { - self.inner.as_ref() - } - - pub fn unwrap_mut(&mut self) -> &mut PythonStdFuzzer { - self.inner.as_mut() - } - } - - #[pymethods] - impl PythonStdFuzzerWrapper { - #[new] - fn new(py_feedback: PythonFeedback, py_objective: PythonFeedback) -> Self { - Self { - inner: OwnedMutPtr::Owned(Box::new(StdFuzzer::new( - QueueScheduler::new(), - py_feedback, - py_objective, - ))), - } - } - - fn add_input( - &mut self, - py_state: &mut PythonStdStateWrapper, - py_executor: &mut PythonExecutor, - py_mgr: &mut PythonEventManager, - input: Vec, - ) -> usize { - self.inner - .as_mut() - .add_input( - py_state.unwrap_mut(), - py_executor, - py_mgr, - BytesInput::new(input), - ) - .expect("Failed to add input") - .0 - } - - fn fuzz_loop( - &mut self, - py_executor: &mut PythonExecutor, - py_state: &mut PythonStdStateWrapper, - py_mgr: &mut PythonEventManager, - stages_tuple: &mut PythonStagesTuple, - ) { - self.inner - .as_mut() - .fuzz_loop(stages_tuple, py_executor, py_state.unwrap_mut(), py_mgr) - .expect("Failed to generate the initial corpus"); - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/generators/mod.rs b/libafl/src/generators/mod.rs index e980745818..4255f16a9d 100644 --- a/libafl/src/generators/mod.rs +++ b/libafl/src/generators/mod.rs @@ -166,179 +166,3 @@ where } } } - -/// `Generator` Python bindings -#[allow(missing_docs)] -#[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -pub mod pybind { - use alloc::vec::Vec; - - use pyo3::prelude::*; - - use crate::{ - generators::{Generator, RandBytesGenerator, RandPrintablesGenerator}, - inputs::{BytesInput, HasBytesVec}, - state::pybind::{PythonStdState, PythonStdStateWrapper}, - Error, - }; - - #[derive(Clone, Debug)] - pub struct PyObjectGenerator { - inner: PyObject, - } - - impl PyObjectGenerator { - #[must_use] - pub fn new(obj: PyObject) -> Self { - PyObjectGenerator { inner: obj } - } - } - - impl Generator for PyObjectGenerator { - fn generate(&mut self, state: &mut PythonStdState) -> Result { - let bytes = Python::with_gil(|py| -> PyResult> { - self.inner - .call_method1(py, "generate", (PythonStdStateWrapper::wrap(state),))? - .extract(py) - }) - .unwrap(); - Ok(BytesInput::new(bytes)) - } - } - - #[pyclass(unsendable, name = "RandBytesGenerator")] - #[derive(Debug, Clone)] - /// Python class for RandBytesGenerator - pub struct PythonRandBytesGenerator { - /// Rust wrapped RandBytesGenerator object - pub inner: RandBytesGenerator, - } - - #[pymethods] - impl PythonRandBytesGenerator { - #[new] - fn new(max_size: usize) -> Self { - Self { - inner: RandBytesGenerator::new(max_size), - } - } - - fn generate(&mut self, state: &mut PythonStdStateWrapper) -> Vec { - self.inner - .generate(state.unwrap_mut()) - .expect("PythonRandBytesGenerator::generate failed") - .bytes() - .to_vec() - } - - fn as_generator(slf: Py) -> 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, - } - - #[pymethods] - impl PythonRandPrintablesGenerator { - #[new] - fn new(max_size: usize) -> Self { - Self { - inner: RandPrintablesGenerator::new(max_size), - } - } - - fn generate(&mut self, state: &mut PythonStdStateWrapper) -> Vec { - self.inner - .generate(state.unwrap_mut()) - .expect("PythonRandPrintablesGenerator::generate failed") - .bytes() - .to_vec() - } - - fn as_generator(slf: Py) -> PythonGenerator { - PythonGenerator::new_rand_printables(slf) - } - } - - #[derive(Debug, Clone)] - enum PythonGeneratorWrapper { - RandBytes(Py), - RandPrintables(Py), - Python(PyObjectGenerator), - } - - /// Rand Trait binding - #[pyclass(unsendable, name = "Generator")] - #[derive(Debug, Clone)] - pub struct PythonGenerator { - wrapper: PythonGeneratorWrapper, - } - - macro_rules! unwrap_me_mut { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_mut_body!($wrapper, $name, $body, PythonGeneratorWrapper, - { RandBytes, RandPrintables }, - { - Python(py_wrapper) => { - let $name = py_wrapper; - $body - } - } - ) - }; - } - - #[pymethods] - impl PythonGenerator { - #[staticmethod] - fn new_rand_bytes(py_gen: Py) -> Self { - Self { - wrapper: PythonGeneratorWrapper::RandBytes(py_gen), - } - } - - #[staticmethod] - fn new_rand_printables(py_gen: Py) -> Self { - Self { - wrapper: PythonGeneratorWrapper::RandPrintables(py_gen), - } - } - - #[staticmethod] - #[must_use] - pub fn new_py(obj: PyObject) -> Self { - Self { - wrapper: PythonGeneratorWrapper::Python(PyObjectGenerator::new(obj)), - } - } - - #[must_use] - pub fn unwrap_py(&self) -> Option { - match &self.wrapper { - PythonGeneratorWrapper::Python(pyo) => Some(pyo.inner.clone()), - _ => None, - } - } - } - - impl Generator for PythonGenerator { - fn generate(&mut self, state: &mut PythonStdState) -> Result { - unwrap_me_mut!(self.wrapper, g, { g.generate(state) }) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index c70469c5b4..019acd0594 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -233,58 +233,3 @@ mod tests { assert_eq!(state.corpus().count(), corpus_deserialized.count()); } } - -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - use pyo3::prelude::*; - - use super::{ - corpus, events, executors, feedbacks, fuzzer, generators, monitors, mutators, observers, - stages, state, - }; - - #[derive(Debug, Clone)] - pub struct PythonMetadata { - pub map: PyObject, - } - - libafl_bolts::impl_serde_pyobjectwrapper!(PythonMetadata, map); - libafl_bolts::impl_serdeany!(PythonMetadata); - - impl PythonMetadata { - #[must_use] - pub fn new(map: PyObject) -> Self { - Self { map } - } - } - - #[pymodule] - #[pyo3(name = "libafl")] - /// Register the classes to the python module - pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { - libafl_bolts::rands::pybind::register(py, m)?; - 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)?; - stages::pybind::register(py, m)?; - stages::mutational::pybind::register(py, m)?; - Ok(()) - } -} diff --git a/libafl/src/monitors/mod.rs b/libafl/src/monitors/mod.rs index c37f051e60..7c1ba6a998 100644 --- a/libafl/src/monitors/mod.rs +++ b/libafl/src/monitors/mod.rs @@ -1306,175 +1306,3 @@ impl Default for ClientPerfMonitor { Self::new() } } -/// `Monitor` Python bindings -#[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -#[allow(missing_docs)] -pub mod pybind { - use alloc::{boxed::Box, vec::Vec}; - use core::time::Duration; - - use libafl_bolts::ClientId; - use pyo3::{prelude::*, types::PyUnicode}; - - use super::ClientStats; - use crate::monitors::{Monitor, SimpleMonitor}; - - /// A [`SimpleMonitor`] type with a boxed `FnMut` for printing - pub type SimpleBoxedFnMonitor = SimpleMonitor>; - - // TODO create a PyObjectFnMut to pass, track stabilization of https://github.com/rust-lang/rust/issues/29625 - - #[pyclass(unsendable, name = "SimpleMonitor")] - /// Python class for SimpleMonitor - pub struct PythonSimpleMonitor { - /// Rust wrapped SimpleMonitor object - pub inner: SimpleBoxedFnMonitor, - 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_non_exhaustive() - } - } - - impl Clone for PythonSimpleMonitor { - fn clone(&self) -> PythonSimpleMonitor { - let py_print_fn = self.print_fn.clone(); - let closure = move |s: &str| { - 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, - print_user_monitor: false, - client_stats: self.inner.client_stats.clone(), - }, - print_fn: self.print_fn.clone(), - } - } - } - - #[pymethods] - impl PythonSimpleMonitor { - #[new] - fn new(py_print_fn: PyObject) -> Self { - let py_print_fn1 = py_print_fn.clone(); - let closure = move |s: &str| { - Python::with_gil(|py| -> PyResult<()> { - py_print_fn1.call1(py, (PyUnicode::new(py, s),))?; - Ok(()) - }) - .unwrap(); - }; - Self { - inner: SimpleMonitor::new(Box::new(closure)), - print_fn: py_print_fn, - } - } - - #[must_use] - pub fn as_monitor(slf: Py) -> PythonMonitor { - PythonMonitor::new_simple(slf) - } - } - - #[derive(Clone, Debug)] - enum PythonMonitorWrapper { - Simple(Py), - } - - #[pyclass(unsendable, name = "Monitor")] - #[derive(Clone, Debug)] - /// EventManager Trait binding - pub struct PythonMonitor { - wrapper: PythonMonitorWrapper, - } - - macro_rules! unwrap_me { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_body!($wrapper, $name, $body, PythonMonitorWrapper, { Simple }) - }; - } - - macro_rules! unwrap_me_mut { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_mut_body!($wrapper, $name, $body, PythonMonitorWrapper, { - Simple - }) - }; - } - - #[pymethods] - impl PythonMonitor { - #[staticmethod] - #[must_use] - pub fn new_simple(simple_monitor: Py) -> Self { - Self { - wrapper: PythonMonitorWrapper::Simple(simple_monitor), - } - } - } - - impl Monitor for PythonMonitor { - fn client_stats_mut(&mut self) -> &mut Vec { - let ptr = unwrap_me_mut!(self.wrapper, m, { - core::ptr::from_mut(m.client_stats_mut()) - }); - unsafe { ptr.as_mut().unwrap() } - } - - fn client_stats(&self) -> &[ClientStats] { - let ptr = unwrap_me!(self.wrapper, m, { core::ptr::from_ref(m.client_stats()) }); - unsafe { ptr.as_ref().unwrap() } - } - - /// Time this fuzzing run stated - fn start_time(&self) -> Duration { - unwrap_me!(self.wrapper, m, { m.start_time() }) - } - - /// set start time - fn set_start_time(&mut self, time: Duration) { - unwrap_me_mut!(self.wrapper, m, { m.set_start_time(time) }); - } - - fn display(&mut self, event_msg: &str, sender_id: ClientId) { - unwrap_me_mut!(self.wrapper, m, { m.display(event_msg, sender_id) }); - } - } - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} - -#[cfg(test)] -mod test { - use crate::monitors::prettify_float; - #[test] - fn test_prettify_float() { - assert_eq!(prettify_float(123423123.0), "123.4M"); - assert_eq!(prettify_float(12342312.3), "12.34M"); - assert_eq!(prettify_float(1234231.23), "1.234M"); - assert_eq!(prettify_float(123423.123), "123.4k"); - assert_eq!(prettify_float(12342.3123), "12.34k"); - assert_eq!(prettify_float(1234.23123), "1.234k"); - assert_eq!(prettify_float(123.423123), "123.4"); - assert_eq!(prettify_float(12.3423123), "12.34"); - assert_eq!(prettify_float(1.23423123), "1.234"); - assert_eq!(prettify_float(0.123423123), "0.123"); - assert_eq!(prettify_float(0.0123423123), "0.012"); - } -} diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index 6828f5fbf7..7a45850a1a 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -407,197 +407,3 @@ impl IntoVec>> for Vec>> { self } } - -/// `Mutator` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - use core::ffi::CStr; - - use libafl_bolts::Named; - use pyo3::{prelude::*, AsPyPointer}; - - use super::{MutationResult, Mutator}; - use crate::{ - corpus::CorpusId, - inputs::{BytesInput, HasBytesVec}, - mutators::scheduled::pybind::PythonStdHavocMutator, - state::pybind::{PythonStdState, PythonStdStateWrapper}, - Error, - }; - - #[derive(Clone, Debug)] - pub struct PyObjectMutator { - inner: PyObject, - } - - impl PyObjectMutator { - #[must_use] - pub fn new(obj: PyObject) -> Self { - PyObjectMutator { inner: obj } - } - } - - impl Named for PyObjectMutator { - fn name(&self) -> &str { - unsafe { CStr::from_ptr((*(*self.inner.as_ptr()).ob_type).tp_name) } - .to_str() - .unwrap() - } - } - - impl Mutator for PyObjectMutator { - fn mutate( - &mut self, - state: &mut PythonStdState, - input: &mut BytesInput, - ) -> Result { - let mutated = Python::with_gil(|py| -> PyResult { - self.inner - .call_method1( - py, - "mutate", - (PythonStdStateWrapper::wrap(state), input.bytes()), - )? - .extract(py) - })?; - Ok(if mutated { - MutationResult::Mutated - } else { - MutationResult::Skipped - }) - } - - fn post_exec( - &mut self, - state: &mut PythonStdState, - - corpus_idx: Option, - ) -> Result<(), Error> { - Python::with_gil(|py| -> PyResult<()> { - self.inner.call_method1( - py, - "post_exec", - (PythonStdStateWrapper::wrap(state), corpus_idx.map(|x| x.0)), - )?; - Ok(()) - })?; - Ok(()) - } - } - - #[derive(Debug, Clone)] - pub enum PythonMutatorWrapper { - StdHavoc(Py), - 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) => { - libafl_bolts::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) -> 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 { - match &self.wrapper { - PythonMutatorWrapper::Python(pyo) => Some(pyo.inner.clone()), - PythonMutatorWrapper::StdHavoc(_) => None, - } - } - } - - impl Named for PythonMutator { - fn name(&self) -> &str { - match &self.wrapper { - PythonMutatorWrapper::Python(pyo) => pyo.name(), - PythonMutatorWrapper::StdHavoc(_) => "StdHavocPythonMutator", - } - } - } - - impl Mutator for PythonMutator { - fn mutate( - &mut self, - state: &mut PythonStdState, - input: &mut BytesInput, - ) -> Result { - unwrap_me_mut!(self.wrapper, m, { m.mutate(state, input) }) - } - - fn post_exec( - &mut self, - state: &mut PythonStdState, - - corpus_idx: Option, - ) -> Result<(), Error> { - unwrap_me_mut!(self.wrapper, m, { m.post_exec(state, corpus_idx) }) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use alloc::{boxed::Box, vec::Vec}; - - use libafl_bolts::{rands::StdRand, tuples::IntoVec}; - - use crate::{ - corpus::InMemoryCorpus, - inputs::BytesInput, - mutators::{havoc_mutations, Mutator, MutatorsTuple}, - state::StdState, - }; - - type TestStdStateType = - StdState, StdRand, InMemoryCorpus>; - - #[test] - fn test_tuple_into_vec() { - let mutators = havoc_mutations::(); - let names_before = MutatorsTuple::::names(&mutators); - - let mutators = havoc_mutations::(); - let mutators_vec: Vec>> = mutators.into_vec(); - assert_eq!(names_before, mutators_vec.names()); - } -} diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index eeee1b94b1..f6230a3e3c 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -568,44 +568,3 @@ mod tests { } } } - -/// `SchedulerMutator` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -pub mod pybind { - use pyo3::prelude::*; - - use super::{havoc_mutations, Debug, HavocMutationsType, StdScheduledMutator}; - use crate::{ - inputs::BytesInput, mutators::pybind::PythonMutator, state::pybind::PythonStdState, - }; - - #[pyclass(unsendable, name = "StdHavocMutator")] - #[derive(Debug)] - /// Python class for StdHavocMutator - pub struct PythonStdHavocMutator { - /// Rust wrapped StdHavocMutator object - pub inner: StdScheduledMutator, PythonStdState>, - } - - #[pymethods] - impl PythonStdHavocMutator { - #[new] - fn new() -> Self { - Self { - inner: StdScheduledMutator::new(havoc_mutations()), - } - } - - fn as_mutator(slf: Py) -> PythonMutator { - PythonMutator::new_std_havoc(slf) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/observers/map.rs b/libafl/src/observers/map.rs index 652c2b5aac..a2d2435fa3 100644 --- a/libafl/src/observers/map.rs +++ b/libafl/src/observers/map.rs @@ -2138,7 +2138,6 @@ where } /// Exact copy of `StdMapObserver` that owns its map -/// Used for python bindings #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(bound = "T: serde::de::DeserializeOwned")] #[allow(clippy::unsafe_derive_deserialize)] @@ -2366,468 +2365,3 @@ where } } } - -/// `MapObserver` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - use concat_idents::concat_idents; - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use super::{ - AsIter, AsIterMut, AsMutSlice, AsSlice, Debug, Error, HasLen, Iter, IterMut, MapObserver, - Named, Observer, OwnedMapObserver, StdMapObserver, String, Vec, - }; - use crate::{inputs::UsesInput, observers::pybind::PythonObserver}; - - #[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 { - ($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_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, false>, - } - - #[pymethods] - impl $struct_name1 { - #[new] - fn new(name: String, ptr: usize, size: usize) -> Self { - Self { - inner: unsafe { StdMapObserver::from_mut_ptr(name, ptr as *mut $datatype, size) } - } - } - - #[must_use] - pub fn as_map_observer(slf: Py) -> $struct_name_trait { - $struct_name_trait::new_std(slf) - } - - #[must_use] - pub fn as_observer(slf: Py) -> PythonObserver { - let m = Self::as_map_observer(slf); - Python::with_gil(|py| -> PyResult { - 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)] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - /// Python class for OwnedMapObserver (i.e. StdMapObserver with owned map) - pub struct $struct_name2 { - /// Rust wrapped OwnedMapObserver object - pub inner: OwnedMapObserver<$datatype>, - } - - #[pymethods] - impl $struct_name2 { - #[new] - fn new(name: String, map: Vec<$datatype>) -> Self { - Self { - //TODO: Not leak memory - inner: OwnedMapObserver::new(alloc::boxed::Box::leak(name.into_boxed_str()), map), - } - } - - #[must_use] - pub fn as_map_observer(slf: Py) -> $struct_name_trait { - $struct_name_trait::new_owned(slf) - } - - #[must_use] - pub fn as_observer(slf: Py) -> PythonObserver { - let m = Self::as_map_observer(slf); - Python::with_gil(|py| -> PyResult { - 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(Debug, Clone)] - pub enum $wrapper_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 - #[pyclass(unsendable, name = $py_name_trait)] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - /// MapObserver + Observer Trait binding - pub struct $struct_name_trait { - #[serde(skip)] - pub wrapper: $wrapper_name, - } - - #[pymethods] - impl $struct_name_trait { - #[staticmethod] - 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 { - wrapper: $wrapper_name::Owned(owned_map), - } - } - - #[must_use] - pub fn as_observer(slf: Py) -> 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> AsIter<'it> for $struct_name_trait { - type Item = $datatype; - type IntoIter = Iter<'it, $datatype>; - - fn as_iter(&'it self) -> Self::IntoIter { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute::<_, Self::IntoIter>(m.as_iter()) } }) - } - } - - impl<'it> AsIterMut<'it> for $struct_name_trait { - type Item = $datatype; - type IntoIter = IterMut<'it, $datatype>; - - fn as_iter_mut(&'it mut self) -> Self::IntoIter { - mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute::<_, Self::IntoIter>(m.as_iter_mut()) } }) - } - } - - impl AsSlice for $struct_name_trait { - type Entry = $datatype; - fn as_slice(&self) -> &[$datatype] { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute(m.as_slice()) }} ) - } - } - - impl AsMutSlice for $struct_name_trait { - type Entry = $datatype; - fn as_mut_slice(&mut self) -> &mut [$datatype] { - mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { unsafe { std::mem::transmute(m.as_mut_slice()) }} ) - } - } - - impl MapObserver for $struct_name_trait { - type Entry = $datatype; - - #[inline] - fn get(&self, idx: usize) -> &$datatype { - let ptr = mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.get(idx) as *const $datatype }); - unsafe { ptr.as_ref().unwrap() } - } - - #[inline] - fn get_mut(&mut self, idx: usize) -> &mut $datatype { - let ptr = mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.get_mut(idx) as *mut $datatype }); - unsafe { ptr.as_mut().unwrap() } - } - - #[inline] - fn count_bytes(&self) -> u64 { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.count_bytes() }) - } - #[inline] - fn usable_count(&self) -> usize { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.usable_count() }) - } - - fn hash(&self) -> u64 { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.hash() }) - } - - #[inline] - fn initial(&self) -> $datatype { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.initial() }) - } - - #[inline] - fn reset_map(&mut self) -> Result<(), Error> { - mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.reset_map() }) - } - - #[inline] - fn to_vec(&self) -> Vec<$datatype> { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.to_vec() }) - } - - #[inline] - fn how_many_set(&self, indexes: &[usize]) -> usize { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.how_many_set(indexes) }) - } - } - - impl Named for $struct_name_trait { - #[inline] - fn name(&self) -> &str { - let ptr = mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.name() as *const str }); - unsafe { ptr.as_ref().unwrap() } - } - } - - impl HasLen for $struct_name_trait { - #[inline] - fn len(&self) -> usize { - mapob_unwrap_me!($wrapper_name, self.wrapper, m, { m.len() }) - } - } - - impl Observer for $struct_name_trait - where - Self: MapObserver, - S: UsesInput, - { - #[inline] - fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { - mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.pre_exec(state, input) }) - } - } - }; - } - - define_python_map_observer!( - PythonStdMapObserverI8, - "StdMapObserverI8", - PythonOwnedMapObserverI8, - "OwnedMapObserverI8", - PythonMapObserverI8, - "MapObserverI8", - i8, - PythonMapObserverWrapperI8 - ); - define_python_map_observer!( - PythonStdMapObserverI16, - "StdMapObserverI16", - PythonOwnedMapObserverI16, - "OwnedMapObserverI16", - PythonMapObserverI16, - "MapObserverI16", - i16, - PythonMapObserverWrapperI16 - ); - define_python_map_observer!( - PythonStdMapObserverI32, - "StdMapObserverI32", - PythonOwnedMapObserverI32, - "OwnedMapObserverI32", - PythonMapObserverI32, - "MapObserverI32", - i32, - PythonMapObserverWrapperI32 - ); - define_python_map_observer!( - PythonStdMapObserverI64, - "StdMapObserverI64", - PythonOwnedMapObserverI64, - "OwnedMapObserverI64", - PythonMapObserverI64, - "MapObserverI64", - i64, - PythonMapObserverWrapperI64 - ); - - define_python_map_observer!( - PythonStdMapObserverU8, - "StdMapObserverU8", - PythonOwnedMapObserverU8, - "OwnedMapObserverU8", - PythonMapObserverU8, - "MapObserverU8", - u8, - PythonMapObserverWrapperU8 - ); - define_python_map_observer!( - PythonStdMapObserverU16, - "StdMapObserverU16", - PythonOwnedMapObserverU16, - "OwnedMapObserverU16", - PythonMapObserverU16, - "MapObserverU16", - u16, - PythonMapObserverWrapperU16 - ); - define_python_map_observer!( - PythonStdMapObserverU32, - "StdMapObserverU32", - PythonOwnedMapObserverU32, - "OwnedMapObserverU32", - PythonMapObserverU32, - "MapObserverU32", - u32, - PythonMapObserverWrapperU32 - ); - define_python_map_observer!( - PythonStdMapObserverU64, - "StdMapObserverU64", - PythonOwnedMapObserverU64, - "OwnedMapObserverU64", - PythonMapObserverU64, - "MapObserverU64", - u64, - PythonMapObserverWrapperU64 - ); - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 2a5f904d83..edcf4c903d 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -526,798 +526,6 @@ where { } -/// `Observer` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - use alloc::vec::Vec; - use core::ptr; - use std::cell::UnsafeCell; - - use libafl_bolts::{ - tuples::{type_eq, MatchName}, - Named, - }; - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use super::{Debug, Observer, ObserversTuple, String}; - use crate::{ - executors::{pybind::PythonExitKind, ExitKind}, - inputs::{BytesInput, HasBytesVec}, - observers::map::pybind::{ - PythonMapObserverI16, PythonMapObserverI32, PythonMapObserverI64, PythonMapObserverI8, - PythonMapObserverU16, PythonMapObserverU32, PythonMapObserverU64, PythonMapObserverU8, - PythonMapObserverWrapperI16, PythonMapObserverWrapperI32, PythonMapObserverWrapperI64, - PythonMapObserverWrapperI8, PythonMapObserverWrapperU16, PythonMapObserverWrapperU32, - PythonMapObserverWrapperU64, PythonMapObserverWrapperU8, - }, - state::pybind::{PythonStdState, PythonStdStateWrapper}, - Error, - }; - - #[derive(Debug)] - pub struct PyObjectObserver { - inner: PyObject, - name: UnsafeCell, - } - - impl Clone for PyObjectObserver { - fn clone(&self) -> PyObjectObserver { - PyObjectObserver { - inner: self.inner.clone(), - name: UnsafeCell::new(String::new()), - } - } - } - - impl PyObjectObserver { - #[must_use] - pub fn new(obj: PyObject) -> Self { - PyObjectObserver { - inner: obj, - name: UnsafeCell::new(String::new()), - } - } - } - - libafl_bolts::impl_serde_pyobjectwrapper!(PyObjectObserver, inner); - - impl Named for PyObjectObserver { - fn name(&self) -> &str { - let s = Python::with_gil(|py| -> PyResult { - let s: String = self.inner.call_method0(py, "name")?.extract(py)?; - Ok(s) - }) - .unwrap(); - unsafe { - *self.name.get() = s; - &*self.name.get() - } - } - } - - impl Observer for PyObjectObserver { - fn flush(&mut self) -> Result<(), Error> { - Python::with_gil(|py| -> PyResult<()> { - self.inner.call_method0(py, "flush")?; - Ok(()) - }) - .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), - MapI16(Py), - MapI32(Py), - MapI64(Py), - MapU8(Py), - MapU16(Py), - MapU32(Py), - MapU64(Py), - Python(PyObjectObserver), - } - - #[pyclass(unsendable, name = "Observer")] - #[allow(clippy::unsafe_derive_deserialize)] - #[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<_> { - let borrowed = py_wrapper.borrow(py); - Ok(crate::mapob_unwrap_me!( - PythonMapObserverWrapperI32, - borrowed.wrapper, - $name, - $body - )) - }) - .unwrap() - } - PythonObserverWrapper::MapI64(py_wrapper) => { - Python::with_gil(|py| -> PyResult<_> { - let borrowed = py_wrapper.borrow(py); - Ok(crate::mapob_unwrap_me!( - PythonMapObserverWrapperI64, - borrowed.wrapper, - $name, - $body - )) - }) - .unwrap() - } - PythonObserverWrapper::MapU8(py_wrapper) => Python::with_gil(|py| -> PyResult<_> { - let borrowed = py_wrapper.borrow(py); - Ok(crate::mapob_unwrap_me!( - PythonMapObserverWrapperU8, - borrowed.wrapper, - $name, - $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) => { - Python::with_gil(|py| -> PyResult<_> { - let borrowed = py_wrapper.borrow(py); - Ok(crate::mapob_unwrap_me!( - PythonMapObserverWrapperU32, - borrowed.wrapper, - $name, - $body - )) - }) - .unwrap() - } - PythonObserverWrapper::MapU64(py_wrapper) => { - Python::with_gil(|py| -> PyResult<_> { - let borrowed = py_wrapper.borrow(py); - Ok(crate::mapob_unwrap_me!( - PythonMapObserverWrapperU64, - borrowed.wrapper, - $name, - $body - )) - }) - .unwrap() - } - PythonObserverWrapper::Python(py_wrapper) => { - let $name = py_wrapper; - $body - } - } - }; - } - - macro_rules! unwrap_me_mut { - ($wrapper:expr, $name:ident, $body:block) => { - match &mut $wrapper { - PythonObserverWrapper::MapI8(py_wrapper) => Python::with_gil(|py| -> PyResult<_> { - 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) -> Self { - Self { - wrapper: PythonObserverWrapper::MapI8(map_observer), - } - } - #[staticmethod] - #[must_use] - pub fn new_map_i16(map_observer: Py) -> Self { - Self { - wrapper: PythonObserverWrapper::MapI16(map_observer), - } - } - #[staticmethod] - #[must_use] - pub fn new_map_i32(map_observer: Py) -> Self { - Self { - wrapper: PythonObserverWrapper::MapI32(map_observer), - } - } - #[staticmethod] - #[must_use] - pub fn new_map_i64(map_observer: Py) -> Self { - Self { - wrapper: PythonObserverWrapper::MapI64(map_observer), - } - } - - #[staticmethod] - #[must_use] - pub fn new_map_u8(map_observer: Py) -> Self { - Self { - wrapper: PythonObserverWrapper::MapU8(map_observer), - } - } - #[staticmethod] - #[must_use] - pub fn new_map_u16(map_observer: Py) -> Self { - Self { - wrapper: PythonObserverWrapper::MapU16(map_observer), - } - } - #[staticmethod] - #[must_use] - pub fn new_map_u32(map_observer: Py) -> Self { - Self { - wrapper: PythonObserverWrapper::MapU32(map_observer), - } - } - #[staticmethod] - #[must_use] - pub fn new_map_u64(map_observer: Py) -> 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 { - 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, { ptr::from_ref::(o.name()) }); - unsafe { ptr.as_ref().unwrap() } - } - } - - impl Observer for PythonObserver { - fn flush(&mut self) -> Result<(), Error> { - unwrap_me_mut!(self.wrapper, o, { Observer::::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)] - #[allow(clippy::unsafe_derive_deserialize)] - #[pyclass(unsendable, name = "ObserversTuple")] - pub struct PythonObserversTuple { - list: Vec, - } - - #[pymethods] - impl PythonObserversTuple { - #[new] - fn new(list: Vec) -> 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 { - for ob in &self.list { - if *ob.name() == *name { - return Some(ob.clone()); - } - } - None - } - } - - impl ObserversTuple 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(()) - } - - // TODO: expose stdout/stderr to python - #[inline] - fn observes_stdout(&self) -> bool { - false - } - - #[inline] - fn observes_stderr(&self) -> bool { - false - } - - #[inline] - fn observe_stderr(&mut self, _: &[u8]) {} - - #[inline] - fn observe_stdout(&mut self, _: &[u8]) {} - } - - impl MatchName for PythonObserversTuple { - fn match_name(&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::() - && 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::() - && 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::() - && 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::() - && 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::() - && 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::() - && 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::() - && 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::() - && 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::() && py_wrapper.name() == name { - r = (ptr::from_ref(py_wrapper) as *const T).as_ref(); - } - } - } - Ok(()) - }) - .unwrap(); - } - r - } - } - - fn match_name_mut(&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::() - && 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::() - && 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::() - && 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::() - && 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::() - && 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::() - && 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::() - && 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::() - && py_wrapper.borrow(py).name() == name - { - r = (ptr::addr_of!(*(*py_wrapper).borrow_mut(py)) as *mut T) - .as_mut(); - } - } - PythonObserverWrapper::Python(py_wrapper) => { - if type_eq::() && py_wrapper.name() == name { - r = (ptr::from_mut(py_wrapper) as *mut T).as_mut(); - } - } - } - Ok(()) - }) - .unwrap(); - } - r - } - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} - #[cfg(feature = "std")] #[cfg(test)] mod tests { diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index dd402bd485..f37691da93 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -644,248 +644,6 @@ impl ExecutionCountRestartHelper { } } -/// `Stage` Python bindings -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - use alloc::vec::Vec; - - use libafl_bolts::Named; - use pyo3::prelude::*; - - use crate::{ - corpus::HasCurrentCorpusIdx, - events::pybind::PythonEventManager, - executors::pybind::PythonExecutor, - fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper}, - stages::{ - mutational::pybind::PythonStdMutationalStage, HasCurrentStage, RetryRestartHelper, - Stage, StagesTuple, - }, - state::{ - pybind::{PythonStdState, PythonStdStateWrapper}, - UsesState, - }, - Error, - }; - - #[derive(Clone, Debug)] - pub struct PyObjectStage { - inner: PyObject, - } - - impl PyObjectStage { - #[must_use] - pub fn new(obj: PyObject) -> Self { - PyObjectStage { inner: obj } - } - } - - impl UsesState for PyObjectStage { - type State = PythonStdState; - } - - impl Named for PyObjectStage { - fn name(&self) -> &str { - "PyObjectStage" - } - } - - impl Stage for PyObjectStage { - #[inline] - fn perform( - &mut self, - fuzzer: &mut PythonStdFuzzer, - executor: &mut PythonExecutor, - state: &mut PythonStdState, - manager: &mut PythonEventManager, - ) -> Result<(), Error> { - let Some(corpus_idx) = state.current_corpus_idx()? else { - return Err(Error::illegal_state( - "state is not currently processing a corpus index", - )); - }; - - Python::with_gil(|py| -> PyResult<()> { - self.inner.call_method1( - py, - "perform", - ( - PythonStdFuzzerWrapper::wrap(fuzzer), - executor.clone(), - PythonStdStateWrapper::wrap(state), - manager.clone(), - corpus_idx.0, - ), - )?; - Ok(()) - })?; - Ok(()) - } - - fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result { - // we don't support resumption in python, and maybe can't? - RetryRestartHelper::restart_progress_should_run(state, self, 2) - } - - fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { - RetryRestartHelper::clear_restart_progress(state, self) - } - } - - #[derive(Clone, Debug)] - pub enum PythonStageWrapper { - StdMutational(Py), - Python(PyObjectStage), - } - - /// Stage Trait binding - #[pyclass(unsendable, name = "Stage")] - #[derive(Clone, Debug)] - pub struct PythonStage { - wrapper: PythonStageWrapper, - } - - macro_rules! unwrap_me_mut { - ($wrapper:expr, $name:ident, $body:block) => { - libafl_bolts::unwrap_me_mut_body!($wrapper, $name, $body, PythonStageWrapper, - { StdMutational }, - { - Python(py_wrapper) => { - let $name = py_wrapper; - $body - } - } - ) - }; - } - - #[pymethods] - impl PythonStage { - #[staticmethod] - #[must_use] - pub fn new_std_mutational( - py_std_havoc_mutations_stage: Py, - ) -> Self { - Self { - wrapper: PythonStageWrapper::StdMutational(py_std_havoc_mutations_stage), - } - } - - #[staticmethod] - #[must_use] - pub fn new_py(obj: PyObject) -> Self { - Self { - wrapper: PythonStageWrapper::Python(PyObjectStage::new(obj)), - } - } - - #[must_use] - pub fn unwrap_py(&self) -> Option { - match &self.wrapper { - PythonStageWrapper::Python(pyo) => Some(pyo.inner.clone()), - PythonStageWrapper::StdMutational(_) => None, - } - } - } - - impl UsesState for PythonStage { - type State = PythonStdState; - } - - impl Named for PythonStage { - fn name(&self) -> &str { - "PythonStage" - } - } - - impl Stage for PythonStage { - #[inline] - #[allow(clippy::let_and_return)] - fn perform( - &mut self, - fuzzer: &mut PythonStdFuzzer, - executor: &mut PythonExecutor, - state: &mut PythonStdState, - manager: &mut PythonEventManager, - ) -> Result<(), Error> { - unwrap_me_mut!(self.wrapper, s, { - s.perform_restartable(fuzzer, executor, state, manager) - }) - } - - #[inline] - fn restart_progress_should_run( - &mut self, - state: &mut PythonStdState, - ) -> Result { - // TODO we need to apply MutationalStage-like resumption here. - // For now, make sure we don't get stuck crashing on a single test - RetryRestartHelper::restart_progress_should_run(state, self, 3) - } - - #[inline] - fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { - RetryRestartHelper::clear_restart_progress(state, self) - } - } - - #[derive(Clone, Debug)] - #[pyclass(unsendable, name = "StagesTuple")] - pub struct PythonStagesTuple { - list: Vec, - } - - #[pymethods] - impl PythonStagesTuple { - #[new] - fn new(list: Vec) -> Self { - Self { list } - } - - fn len(&self) -> usize { - self.list.len() - } - - fn __getitem__(&self, idx: usize) -> PythonStage { - self.list[idx].clone() - } - } - - impl StagesTuple - for PythonStagesTuple - { - fn perform_all( - &mut self, - fuzzer: &mut PythonStdFuzzer, - executor: &mut PythonExecutor, - state: &mut PythonStdState, - manager: &mut PythonEventManager, - ) -> Result<(), Error> { - for (i, s) in self.list.iter_mut().enumerate() { - if let Some(continued) = state.current_stage()? { - assert!(continued >= i); - if continued > i { - continue; - } - } else { - state.set_stage(i)?; - } - s.perform_restartable(fuzzer, executor, state, manager)?; - state.clear_stage()?; - } - Ok(()) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} - #[cfg(test)] pub mod test { use core::marker::PhantomData; diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 39d250c45a..eb7e5dd9e8 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -403,54 +403,3 @@ where } } } - -#[cfg(feature = "python")] -#[allow(missing_docs)] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -/// `StdMutationalStage` Python bindings -pub mod pybind { - use pyo3::prelude::*; - - use crate::{ - events::pybind::PythonEventManager, - executors::pybind::PythonExecutor, - fuzzer::pybind::PythonStdFuzzer, - inputs::BytesInput, - mutators::pybind::PythonMutator, - stages::{pybind::PythonStage, StdMutationalStage}, - }; - - #[pyclass(unsendable, name = "StdMutationalStage")] - #[derive(Debug)] - /// Python class for StdMutationalStage - pub struct PythonStdMutationalStage { - /// Rust wrapped StdMutationalStage object - pub inner: StdMutationalStage< - PythonExecutor, - PythonEventManager, - BytesInput, - PythonMutator, - PythonStdFuzzer, - >, - } - - #[pymethods] - impl PythonStdMutationalStage { - #[new] - fn new(mutator: PythonMutator) -> Self { - Self { - inner: StdMutationalStage::new(mutator), - } - } - - fn as_stage(slf: Py) -> PythonStage { - PythonStage::new_std_mutational(slf) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index ae5b5c759e..17088bc7a4 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -1361,146 +1361,3 @@ pub mod test { .expect("couldn't instantiate the test state") } } - -#[cfg(feature = "python")] -#[allow(missing_docs)] -/// `State` Python bindings -pub mod pybind { - use alloc::{boxed::Box, vec::Vec}; - use std::path::PathBuf; - - use libafl_bolts::{ownedref::OwnedMutPtr, rands::pybind::PythonRand}; - use pyo3::{prelude::*, types::PyDict}; - - use crate::{ - corpus::pybind::PythonCorpus, - events::pybind::PythonEventManager, - executors::pybind::PythonExecutor, - feedbacks::pybind::PythonFeedback, - fuzzer::pybind::PythonStdFuzzerWrapper, - generators::pybind::PythonGenerator, - inputs::BytesInput, - pybind::PythonMetadata, - state::{ - HasCorpus, HasExecutions, HasMaxSize, HasMetadata, HasRand, HasSolutions, StdState, - }, - }; - - /// `StdState` with fixed generics - pub type PythonStdState = StdState; - - #[pyclass(unsendable, name = "StdState")] - #[derive(Debug)] - /// Python class for StdState - pub struct PythonStdStateWrapper { - /// Rust wrapped StdState object - pub inner: OwnedMutPtr, - } - - impl PythonStdStateWrapper { - pub fn wrap(r: &mut PythonStdState) -> Self { - Self { - inner: OwnedMutPtr::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: OwnedMutPtr::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_map_mut(); - if !meta.contains::() { - Python::with_gil(|py| { - let dict: Py = PyDict::new(py).into(); - meta.insert(PythonMetadata::new(dict.to_object(py))); - }); - } - meta.get::().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) -> u64 { - *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, - ) { - 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 - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl_bolts/Cargo.toml b/libafl_bolts/Cargo.toml index 8e24ea3a8d..9be219fe9b 100644 --- a/libafl_bolts/Cargo.toml +++ b/libafl_bolts/Cargo.toml @@ -35,9 +35,6 @@ derive = ["libafl_derive"] ## If set, libafl_bolt's `rand` implementations will implement `rand::Rng` rand_trait = ["rand_core"] -## Will build the `pyo3` bindings -python = ["pyo3", "std"] - ## Expose `libafl::prelude` for direct access to all types without additional `use` directives prelude = [] @@ -116,8 +113,6 @@ uuid = { version = "1.4", optional = true, features = ["serde", "v4"] } clap = {version = "4.5", features = ["derive", "wrap_help"], optional = true} # CLI parsing, for libafl_bolts::cli / the `cli` feature log = "0.4.20" -pyo3 = { version = "0.18", optional = true, features = ["serde", "macros"] } - # optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) serial_test = { version = "2", optional = true, default-features = false, features = ["logging"] } diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index 26271a8af3..9501095a5d 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -611,22 +611,6 @@ impl From for Error { } } -#[cfg(feature = "python")] -impl From for Error { - fn from(err: pyo3::PyErr) -> Self { - pyo3::Python::with_gil(|py| { - if err.matches( - py, - pyo3::types::PyType::new::(py), - ) { - Self::shutting_down() - } else { - Self::illegal_state(format!("Python exception: {err:?}")) - } - }) - } -} - #[cfg(all(not(nightly), feature = "std"))] impl std::error::Error for Error {} @@ -1038,148 +1022,6 @@ pub unsafe fn set_error_print_panic_hook(new_stderr: RawFd) { })); } -#[cfg(feature = "python")] -#[allow(missing_docs)] -pub mod pybind { - - use pyo3::{pymodule, types::PyModule, PyResult, Python}; - - #[macro_export] - macro_rules! unwrap_me_body { - ($wrapper:expr, $name:ident, $body:block, $wrapper_type:ident, { $($wrapper_option:tt),* }) => { - 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: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 alloc::vec::Vec; - - use pyo3::prelude::*; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - impl Serialize for $struct_name { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let buf = Python::with_gil(|py| -> PyResult> { - let pickle = PyModule::import(py, "pickle")?; - let buf: Vec = - 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(self, v: Vec) -> Result - where - E: serde::de::Error, - { - let obj = Python::with_gil(|py| -> PyResult { - 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(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_byte_buf(PyObjectVisitor) - } - } - }; - }; - } - - #[pymodule] - #[pyo3(name = "libafl_bolts")] - /// Register the classes to the python module - pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { - crate::rands::pybind::register(py, m)?; - Ok(()) - } -} - #[cfg(test)] mod tests { diff --git a/libafl_bolts/src/rands.rs b/libafl_bolts/src/rands.rs index 430a4af0fc..e19143d0d3 100644 --- a/libafl_bolts/src/rands.rs +++ b/libafl_bolts/src/rands.rs @@ -433,92 +433,3 @@ mod tests { log::info!("random value: {}", mutator.rng.next_u32()); } } - -#[cfg(feature = "python")] -#[allow(clippy::unnecessary_fallible_conversions, unused_qualifications)] -#[allow(missing_docs)] -/// `Rand` Python bindings -pub mod pybind { - use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; - - use super::Rand; - use crate::{current_nanos, rands::StdRand}; - - #[pyclass(unsendable, name = "StdRand")] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - /// Python class for StdRand - pub struct PythonStdRand { - /// Rust wrapped StdRand object - pub inner: StdRand, - } - - #[pymethods] - impl PythonStdRand { - #[staticmethod] - fn with_current_nanos() -> Self { - Self { - inner: StdRand::with_seed(current_nanos()), - } - } - - #[staticmethod] - fn with_seed(seed: u64) -> Self { - Self { - inner: StdRand::with_seed(seed), - } - } - - fn as_rand(slf: Py) -> PythonRand { - PythonRand::new_std(slf) - } - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - enum PythonRandWrapper { - Std(Py), - } - - /// Rand Trait binding - #[pyclass(unsendable, name = "Rand")] - #[allow(clippy::unsafe_derive_deserialize)] - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct PythonRand { - wrapper: PythonRandWrapper, - } - - macro_rules! unwrap_me_mut { - ($wrapper:expr, $name:ident, $body:block) => { - crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonRandWrapper, { Std }) - }; - } - - #[pymethods] - impl PythonRand { - #[staticmethod] - fn new_std(py_std_rand: Py) -> Self { - Self { - wrapper: PythonRandWrapper::Std(py_std_rand), - } - } - } - - impl Rand for PythonRand { - fn set_seed(&mut self, seed: u64) { - unwrap_me_mut!(self.wrapper, r, { r.set_seed(seed) }); - } - - #[inline] - fn next(&mut self) -> u64 { - unwrap_me_mut!(self.wrapper, r, { r.next() }) - } - } - - /// Register the classes to the python module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl_qemu/Cargo.toml b/libafl_qemu/Cargo.toml index 5f34422e9a..b375b7d6d2 100644 --- a/libafl_qemu/Cargo.toml +++ b/libafl_qemu/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"] [package.metadata.docs.rs] -features = ["document-features", "default", "python", "x86_64", "usermode"] +features = ["document-features", "default", "x86_64", "usermode"] rustdoc-args = ["--cfg", "docsrs"] [features] @@ -24,8 +24,6 @@ document-features = ["dep:document-features"] #! ### General Features ## Find injections during fuzzing injections = ["serde_yaml", "toml"] -## Python bindings support -python = ["pyo3", "pyo3-build-config", "libafl_qemu_sys/python"] ## Fork support fork = ["libafl/fork"] ## Build libqasan for address sanitization @@ -87,12 +85,10 @@ paste = "1" enum-map = "2.7" serde_yaml = { version = "0.8", optional = true } # For parsing the injections yaml file toml = { version = "0.4.2", optional = true } # For parsing the injections toml file -pyo3 = { version = "0.18", optional = true } # Document all features of this crate (for `cargo doc`) document-features = { version = "0.2", optional = true } [build-dependencies] -pyo3-build-config = { version = "0.18", optional = true } rustversion = "1.0" bindgen = "0.69" diff --git a/libafl_qemu/libafl_qemu_sys/Cargo.toml b/libafl_qemu/libafl_qemu_sys/Cargo.toml index 1d1dd57bfb..c754688d20 100644 --- a/libafl_qemu/libafl_qemu_sys/Cargo.toml +++ b/libafl_qemu/libafl_qemu_sys/Cargo.toml @@ -30,8 +30,6 @@ be = [] usermode = [] systemmode = [] -python = ["pyo3", "pyo3-build-config"] - slirp = [ "systemmode", "libafl_qemu_build/slirp" ] # build qemu with host libslirp (for user networking) shared = [ "libafl_qemu_build/shared" ] @@ -43,8 +41,6 @@ num_enum = "0.7" libc = "0.2" strum = "0.25" strum_macros = "0.25" -pyo3 = { version = "0.18", optional = true } [build-dependencies] libafl_qemu_build = { path = "../libafl_qemu_build", version = "0.11.2" } -pyo3-build-config = { version = "0.18", optional = true } diff --git a/libafl_qemu/libafl_qemu_sys/src/lib.rs b/libafl_qemu/libafl_qemu_sys/src/lib.rs index 9007c629fa..a2d63dba4f 100644 --- a/libafl_qemu/libafl_qemu_sys/src/lib.rs +++ b/libafl_qemu/libafl_qemu_sys/src/lib.rs @@ -98,8 +98,6 @@ macro_rules! extern_c_checked { use core::ops::BitAnd; use std::{ffi::c_void, slice::from_raw_parts, str::from_utf8_unchecked}; -#[cfg(feature = "python")] -use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python}; #[cfg(all(feature = "clippy", target_os = "linux"))] pub use x86_64_stub_bindings::*; @@ -117,7 +115,6 @@ pub type GuestVirtAddr = crate::vaddr; pub type GuestHwAddrInfo = crate::qemu_plugin_hwaddr; #[repr(C)] -#[cfg_attr(feature = "python", pyclass(unsendable))] pub struct MapInfo { start: GuestAddr, end: GuestAddr, @@ -204,7 +201,6 @@ extern_c_checked! { pub fn libafl_qemu_gdb_reply(buf: *const u8, len: usize); } -#[cfg_attr(feature = "python", pymethods)] impl MapInfo { #[must_use] pub fn start(&self) -> GuestAddr { @@ -280,11 +276,3 @@ impl MmapPerms { ) } } - -#[cfg(feature = "python")] -impl IntoPy for MmapPerms { - fn into_py(self, py: Python) -> PyObject { - let n: i32 = self.into(); - n.into_py(py) - } -} diff --git a/libafl_qemu/src/aarch64.rs b/libafl_qemu/src/aarch64.rs index 3793146d4a..d204303981 100644 --- a/libafl_qemu/src/aarch64.rs +++ b/libafl_qemu/src/aarch64.rs @@ -3,8 +3,6 @@ use std::sync::OnceLock; use capstone::arch::BuildsCapstone; use enum_map::{enum_map, EnumMap}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -#[cfg(feature = "python")] -use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::aarch64::*; @@ -73,14 +71,6 @@ impl Regs { pub const Lr: Regs = Regs::X30; } -#[cfg(feature = "python")] -impl IntoPy for Regs { - fn into_py(self, py: Python) -> PyObject { - let n: i32 = self.into(); - n.into_py(py) - } -} - /// Return an ARM64 ArchCapstoneBuilder pub fn capstone() -> capstone::arch::arm64::ArchCapstoneBuilder { capstone::Capstone::new() diff --git a/libafl_qemu/src/arm.rs b/libafl_qemu/src/arm.rs index fcdf9b1a06..4237af854f 100644 --- a/libafl_qemu/src/arm.rs +++ b/libafl_qemu/src/arm.rs @@ -3,8 +3,6 @@ use std::sync::OnceLock; use capstone::arch::BuildsCapstone; use enum_map::{enum_map, EnumMap}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -#[cfg(feature = "python")] -use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::arm::*; @@ -63,14 +61,6 @@ impl Regs { pub const Cpsr: Regs = Regs::R25; } -#[cfg(feature = "python")] -impl IntoPy for Regs { - fn into_py(self, py: Python) -> PyObject { - let n: i32 = self.into(); - n.into_py(py) - } -} - /// Return an ARM ArchCapstoneBuilder pub fn capstone() -> capstone::arch::arm::ArchCapstoneBuilder { capstone::Capstone::new() diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index 582a22440e..1356d4f339 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -352,9 +352,6 @@ impl From for MemAccessInfo { } } -#[cfg(feature = "python")] -use pyo3::prelude::*; - pub const SKIP_EXEC_HOOK: u64 = u64::MAX; pub use libafl_qemu_sys::{CPUArchState, CPUState}; @@ -363,33 +360,11 @@ use crate::sync_backdoor::{SyncBackdoor, SyncBackdoorError}; // syshook_ret #[repr(C)] -#[cfg_attr(feature = "python", pyclass)] -#[cfg_attr(feature = "python", derive(FromPyObject))] pub struct SyscallHookResult { pub retval: GuestAddr, pub skip_syscall: bool, } -#[cfg(feature = "python")] -#[pymethods] -impl SyscallHookResult { - #[new] - #[must_use] - pub fn new(value: Option) -> Self { - value.map_or( - Self { - retval: 0, - skip_syscall: false, - }, - |v| Self { - retval: v, - skip_syscall: true, - }, - ) - } -} - -#[cfg(not(feature = "python"))] impl SyscallHookResult { #[must_use] pub fn new(value: Option) -> Self { @@ -1738,190 +1713,3 @@ where // self.qemu.write_function_argument(conv, idx, val) // } // } - -#[cfg(feature = "python")] -pub mod pybind { - use pyo3::{exceptions::PyValueError, prelude::*, types::PyInt}; - - use super::{GuestAddr, GuestUsize, MmapPerms, SyscallHookResult}; - - static mut PY_SYSCALL_HOOK: Option = None; - static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![]; - - extern "C" fn py_syscall_hook_wrapper( - _data: u64, - sys_num: i32, - a0: u64, - a1: u64, - a2: u64, - a3: u64, - a4: u64, - a5: u64, - a6: u64, - a7: u64, - ) -> SyscallHookResult { - unsafe { PY_SYSCALL_HOOK.as_ref() }.map_or_else( - || SyscallHookResult::new(None), - |obj| { - let args = (sys_num, a0, a1, a2, a3, a4, a5, a6, a7); - Python::with_gil(|py| { - let ret = obj.call1(py, args).expect("Error in the syscall hook"); - let any = ret.as_ref(py); - if any.is_none() { - SyscallHookResult::new(None) - } else { - let a: Result<&PyInt, _> = any.downcast(); - if let Ok(i) = a { - SyscallHookResult::new(Some( - i.extract().expect("Invalid syscall hook return value"), - )) - } else { - SyscallHookResult::extract(any) - .expect("The syscall hook must return a SyscallHookResult") - } - } - }) - }, - ) - } - - extern "C" fn py_generic_hook_wrapper(idx: u64, _pc: GuestAddr) { - let obj = unsafe { &PY_GENERIC_HOOKS[idx as usize].1 }; - Python::with_gil(|py| { - obj.call0(py).expect("Error in the hook"); - }); - } - - #[pyclass(unsendable)] - pub struct Qemu { - pub qemu: super::Qemu, - } - - #[pymethods] - impl Qemu { - #[allow(clippy::needless_pass_by_value)] - #[new] - fn new(args: Vec, env: Vec<(String, String)>) -> PyResult { - let qemu = super::Qemu::init(&args, &env) - .map_err(|e| PyValueError::new_err(format!("{e}")))?; - - Ok(Qemu { qemu }) - } - - fn write_mem(&self, addr: GuestAddr, buf: &[u8]) { - unsafe { - self.qemu.write_mem(addr, buf); - } - } - - fn read_mem(&self, addr: GuestAddr, size: usize) -> Vec { - let mut buf = vec![0; size]; - unsafe { - self.qemu.read_mem(addr, &mut buf); - } - buf - } - - fn num_regs(&self) -> i32 { - self.qemu.num_regs() - } - - fn write_reg(&self, reg: i32, val: GuestUsize) -> PyResult<()> { - self.qemu.write_reg(reg, val).map_err(PyValueError::new_err) - } - - fn read_reg(&self, reg: i32) -> PyResult { - self.qemu.read_reg(reg).map_err(PyValueError::new_err) - } - - fn set_breakpoint(&self, addr: GuestAddr) { - self.qemu.set_breakpoint(addr); - } - - fn entry_break(&self, addr: GuestAddr) { - self.qemu.entry_break(addr); - } - - fn remove_breakpoint(&self, addr: GuestAddr) { - self.qemu.remove_breakpoint(addr); - } - - fn g2h(&self, addr: GuestAddr) -> u64 { - self.qemu.g2h::<*const u8>(addr) as u64 - } - - fn h2g(&self, addr: u64) -> GuestAddr { - self.qemu.h2g(addr as *const u8) - } - - fn binary_path(&self) -> String { - self.qemu.binary_path().to_owned() - } - - fn load_addr(&self) -> GuestAddr { - self.qemu.load_addr() - } - - fn flush_jit(&self) { - self.qemu.flush_jit(); - } - - fn map_private(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult { - if let Ok(p) = MmapPerms::try_from(perms) { - self.qemu - .map_private(addr, size, p) - .map_err(PyValueError::new_err) - } else { - Err(PyValueError::new_err("Invalid perms")) - } - } - - fn map_fixed(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult { - if let Ok(p) = MmapPerms::try_from(perms) { - self.qemu - .map_fixed(addr, size, p) - .map_err(PyValueError::new_err) - } else { - Err(PyValueError::new_err("Invalid perms")) - } - } - - fn mprotect(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<()> { - if let Ok(p) = MmapPerms::try_from(perms) { - self.qemu - .mprotect(addr, size, p) - .map_err(PyValueError::new_err) - } else { - Err(PyValueError::new_err("Invalid perms")) - } - } - - fn unmap(&self, addr: GuestAddr, size: usize) -> PyResult<()> { - self.qemu.unmap(addr, size).map_err(PyValueError::new_err) - } - - fn set_syscall_hook(&self, hook: PyObject) { - unsafe { - PY_SYSCALL_HOOK = Some(hook); - } - self.qemu - .add_pre_syscall_hook(0u64, py_syscall_hook_wrapper); - } - - fn set_hook(&self, addr: GuestAddr, hook: PyObject) { - unsafe { - let idx = PY_GENERIC_HOOKS.len(); - PY_GENERIC_HOOKS.push((addr, hook)); - self.qemu - .set_hook(idx as u64, addr, py_generic_hook_wrapper, true); - } - } - - fn remove_hooks_at(&self, addr: GuestAddr) -> usize { - unsafe { - PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr); - } - self.qemu.remove_hooks_at(addr, true) - } - } -} diff --git a/libafl_qemu/src/emu/usermode.rs b/libafl_qemu/src/emu/usermode.rs index 1dbfffe55e..9c2abf359f 100644 --- a/libafl_qemu/src/emu/usermode.rs +++ b/libafl_qemu/src/emu/usermode.rs @@ -7,8 +7,6 @@ use libafl_qemu_sys::{ read_self_maps, strlen, GuestAddr, GuestUsize, MapInfo, MmapPerms, VerifyAccess, }; use libc::c_int; -#[cfg(feature = "python")] -use pyo3::prelude::*; use crate::{ emu::{HasExecutions, State}, @@ -24,7 +22,6 @@ pub enum HandlerError { MultipleInputDefinition, } -#[cfg_attr(feature = "python", pyclass(unsendable))] pub struct GuestMaps { orig_c_iter: *const c_void, c_iter: *const c_void, @@ -64,17 +61,6 @@ impl Iterator for GuestMaps { } } -#[cfg(feature = "python")] -#[pymethods] -impl GuestMaps { - fn __iter__(slf: PyRef) -> PyRef { - slf - } - fn __next__(mut slf: PyRefMut) -> Option { - Python::with_gil(|py| slf.next().map(|x| x.into_py(py))) - } -} - impl Drop for GuestMaps { fn drop(&mut self) { unsafe { diff --git a/libafl_qemu/src/hexagon.rs b/libafl_qemu/src/hexagon.rs index d931876034..f083295ce3 100644 --- a/libafl_qemu/src/hexagon.rs +++ b/libafl_qemu/src/hexagon.rs @@ -2,8 +2,6 @@ use std::sync::OnceLock; use enum_map::{enum_map, EnumMap}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -#[cfg(feature = "python")] -use pyo3::prelude::*; pub use strum_macros::EnumIter; use crate::{sync_backdoor::BackdoorArgs, CallingConvention}; diff --git a/libafl_qemu/src/i386.rs b/libafl_qemu/src/i386.rs index d70578987a..a4144f74ed 100644 --- a/libafl_qemu/src/i386.rs +++ b/libafl_qemu/src/i386.rs @@ -3,8 +3,6 @@ use std::{mem::size_of, sync::OnceLock}; use capstone::arch::BuildsCapstone; use enum_map::{enum_map, EnumMap}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -#[cfg(feature = "python")] -use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::x86::*; @@ -49,14 +47,6 @@ impl Regs { pub const Pc: Regs = Regs::Eip; } -#[cfg(feature = "python")] -impl IntoPy for Regs { - fn into_py(self, py: Python) -> PyObject { - let n: i32 = self.into(); - n.into_py(py) - } -} - /// Return an X86 ArchCapstoneBuilder pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder { capstone::Capstone::new() diff --git a/libafl_qemu/src/lib.rs b/libafl_qemu/src/lib.rs index 3c21f3ae08..b42b35a954 100644 --- a/libafl_qemu/src/lib.rs +++ b/libafl_qemu/src/lib.rs @@ -131,33 +131,3 @@ pub fn filter_qemu_args() -> Vec { } args } - -#[cfg(feature = "python")] -use pyo3::prelude::*; - -#[cfg(feature = "python")] -#[pymodule] -#[pyo3(name = "libafl_qemu")] -#[allow(clippy::items_after_statements, clippy::too_many_lines)] -pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { - let regsm = PyModule::new(py, "regs")?; - for r in Regs::iter() { - let v: i32 = r.into(); - regsm.add(&format!("{r:?}"), v)?; - } - m.add_submodule(regsm)?; - - let mmapm = PyModule::new(py, "mmap")?; - for r in emu::MmapPerms::iter() { - let v: i32 = r.into(); - mmapm.add(&format!("{r:?}"), v)?; - } - m.add_submodule(mmapm)?; - - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - Ok(()) -} diff --git a/libafl_qemu/src/mips.rs b/libafl_qemu/src/mips.rs index 96b464d9fd..8619529fa4 100644 --- a/libafl_qemu/src/mips.rs +++ b/libafl_qemu/src/mips.rs @@ -2,8 +2,6 @@ use std::sync::OnceLock; use enum_map::{enum_map, EnumMap}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -#[cfg(feature = "python")] -use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::mips::*; @@ -72,14 +70,6 @@ impl Regs { pub const Zero: Regs = Regs::R0; } -#[cfg(feature = "python")] -impl IntoPy for Regs { - fn into_py(self, py: Python) -> PyObject { - let n: i32 = self.into(); - n.into_py(py) - } -} - /// Return an MIPS ArchCapstoneBuilder pub fn capstone() -> capstone::arch::mips::ArchCapstoneBuilder { capstone::Capstone::new().mips() diff --git a/libafl_qemu/src/ppc.rs b/libafl_qemu/src/ppc.rs index 9fdd4def74..5427bce59f 100644 --- a/libafl_qemu/src/ppc.rs +++ b/libafl_qemu/src/ppc.rs @@ -2,8 +2,6 @@ use std::sync::OnceLock; use enum_map::{enum_map, EnumMap}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -#[cfg(feature = "python")] -use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::powerpc::*; @@ -112,14 +110,6 @@ impl Regs { pub const Sp: Regs = Regs::R1; } -#[cfg(feature = "python")] -impl IntoPy for Regs { - fn into_py(self, py: Python) -> PyObject { - let n: i32 = self.into(); - n.into_py(py) - } -} - /// Return an MIPS ArchCapstoneBuilder pub fn capstone() -> capstone::arch::ppc::ArchCapstoneBuilder { capstone::Capstone::new().ppc() diff --git a/libafl_qemu/src/x86_64.rs b/libafl_qemu/src/x86_64.rs index d6ac5aac0d..bef59a1dd2 100644 --- a/libafl_qemu/src/x86_64.rs +++ b/libafl_qemu/src/x86_64.rs @@ -3,8 +3,6 @@ use std::{mem::size_of, sync::OnceLock}; use capstone::arch::BuildsCapstone; use enum_map::{enum_map, EnumMap}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -#[cfg(feature = "python")] -use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::x86_64::*; @@ -57,14 +55,6 @@ impl Regs { pub const Pc: Regs = Regs::Rip; } -#[cfg(feature = "python")] -impl IntoPy for Regs { - fn into_py(self, py: Python) -> PyObject { - let n: i32 = self.into(); - n.into_py(py) - } -} - /// Return an X86 `ArchCapstoneBuilder` #[must_use] pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder { diff --git a/libafl_sugar/Cargo.toml b/libafl_sugar/Cargo.toml index 521af3ab22..f4ac7d89ac 100644 --- a/libafl_sugar/Cargo.toml +++ b/libafl_sugar/Cargo.toml @@ -9,14 +9,12 @@ readme = "../README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing"] edition = "2021" -build = "build.rs" categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"] [package.metadata.docs.rs] all-features = true [features] -python = ["pyo3", "libafl_qemu/python", "pyo3-build-config"] default = [] # for libafl_qemu @@ -29,16 +27,12 @@ mips = ["libafl_qemu/mips"] # build qemu for mips (el, use with the 'be' feature ppc = ["libafl_qemu/ppc"] # build qemu for powerpc hexagon = ["libafl_qemu/hexagon"] # build qemu for hexagon -[build-dependencies] -pyo3-build-config = { version = "0.18", optional = true } - [dependencies] libafl = { path = "../libafl", version = "0.11.2" } libafl_bolts = { path = "../libafl_bolts", version = "0.11.2" } libafl_targets = { path = "../libafl_targets", version = "0.11.2" } typed-builder = "0.16" # Implement the builder pattern at compiletime -pyo3 = { version = "0.18", optional = true } log = "0.4.20" [target.'cfg(target_os = "linux")'.dependencies] diff --git a/libafl_sugar/build.rs b/libafl_sugar/build.rs deleted file mode 100644 index 294fe34040..0000000000 --- a/libafl_sugar/build.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - #[cfg(feature = "python")] - pyo3_build_config::add_extension_module_link_args(); -} diff --git a/libafl_sugar/src/forkserver.rs b/libafl_sugar/src/forkserver.rs index c7fa34c451..e99b613ba3 100644 --- a/libafl_sugar/src/forkserver.rs +++ b/libafl_sugar/src/forkserver.rs @@ -299,80 +299,3 @@ impl<'a> ForkserverBytesCoverageSugar<'a> { } } } - -/// The python bindings for this sugar -#[cfg(feature = "python")] -pub mod pybind { - use std::path::PathBuf; - - use libafl_bolts::core_affinity::Cores; - use pyo3::prelude::*; - - use crate::forkserver; - - /// Python bindings for the `LibAFL` forkserver sugar - #[pyclass(unsendable)] - #[derive(Debug)] - struct ForkserverBytesCoverageSugar { - input_dirs: Vec, - output_dir: PathBuf, - broker_port: u16, - cores: Cores, - use_cmplog: Option, - iterations: Option, - tokens_file: Option, - timeout: Option, - } - - #[pymethods] - impl ForkserverBytesCoverageSugar { - /// Create a new [`ForkserverBytesCoverageSugar`] - #[new] - #[allow(clippy::too_many_arguments)] - fn new( - input_dirs: Vec, - output_dir: PathBuf, - broker_port: u16, - cores: Vec, - use_cmplog: Option, - iterations: Option, - tokens_file: Option, - timeout: Option, - ) -> Self { - Self { - input_dirs, - output_dir, - broker_port, - cores: cores.into(), - use_cmplog, - iterations, - tokens_file, - timeout, - } - } - - /// Run the fuzzer - #[allow(clippy::needless_pass_by_value)] - pub fn run(&self, program: String, arguments: Vec) { - forkserver::ForkserverBytesCoverageSugar::builder() - .input_dirs(&self.input_dirs) - .output_dir(self.output_dir.clone()) - .broker_port(self.broker_port) - .cores(&self.cores) - .program(program) - .arguments(&arguments) - .use_cmplog(self.use_cmplog) - .timeout(self.timeout) - .tokens_file(self.tokens_file.clone()) - .iterations(self.iterations) - .build() - .run(); - } - } - - /// Register the module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl_sugar/src/inmemory.rs b/libafl_sugar/src/inmemory.rs index fc00a0e84a..39ad9d50b2 100644 --- a/libafl_sugar/src/inmemory.rs +++ b/libafl_sugar/src/inmemory.rs @@ -348,87 +348,3 @@ where } } } - -/// Python bindings for this sugar -#[cfg(feature = "python")] -pub mod pybind { - use std::path::PathBuf; - - use libafl_bolts::core_affinity::Cores; - use pyo3::{prelude::*, types::PyBytes}; - - use crate::inmemory; - - /// In-Memory fuzzing made easy. - /// Use this sugar for scaling `libfuzzer`-style fuzzers. - #[pyclass(unsendable)] - #[derive(Debug)] - struct InMemoryBytesCoverageSugar { - input_dirs: Vec, - output_dir: PathBuf, - broker_port: u16, - cores: Cores, - use_cmplog: Option, - iterations: Option, - tokens_file: Option, - timeout: Option, - } - - #[pymethods] - impl InMemoryBytesCoverageSugar { - /// Create a new [`InMemoryBytesCoverageSugar`] - #[new] - #[allow(clippy::too_many_arguments)] - fn new( - input_dirs: Vec, - output_dir: PathBuf, - broker_port: u16, - cores: Vec, - use_cmplog: Option, - iterations: Option, - tokens_file: Option, - timeout: Option, - ) -> Self { - Self { - input_dirs, - output_dir, - broker_port, - cores: cores.into(), - use_cmplog, - iterations, - tokens_file, - timeout, - } - } - - /// Run the fuzzer - #[allow(clippy::needless_pass_by_value)] - pub fn run(&self, harness: PyObject) { - inmemory::InMemoryBytesCoverageSugar::builder() - .input_dirs(&self.input_dirs) - .output_dir(self.output_dir.clone()) - .broker_port(self.broker_port) - .cores(&self.cores) - .harness(|buf| { - Python::with_gil(|py| -> PyResult<()> { - let args = (PyBytes::new(py, buf),); // TODO avoid copy - harness.call1(py, args)?; - Ok(()) - }) - .unwrap(); - }) - .use_cmplog(self.use_cmplog) - .timeout(self.timeout) - .tokens_file(self.tokens_file.clone()) - .iterations(self.iterations) - .build() - .run(); - } - } - - /// Register the module - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -} diff --git a/libafl_sugar/src/lib.rs b/libafl_sugar/src/lib.rs index fb41e4a5aa..115ba85071 100644 --- a/libafl_sugar/src/lib.rs +++ b/libafl_sugar/src/lib.rs @@ -78,23 +78,3 @@ pub const DEFAULT_TIMEOUT_SECS: u64 = 1200; /// Default cache size for the corpus in memory. /// Anything else will be on disk. pub const CORPUS_CACHE_SIZE: usize = 4096; - -#[cfg(feature = "python")] -use pyo3::prelude::*; - -/// The sugar python module -#[cfg(feature = "python")] -#[pymodule] -#[pyo3(name = "libafl_sugar")] -pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { - inmemory::pybind::register(py, m)?; - #[cfg(target_os = "linux")] - { - qemu::pybind::register(py, m)?; - } - #[cfg(unix)] - { - forkserver::pybind::register(py, m)?; - } - Ok(()) -} diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index 30c00f911a..ff3ae19599 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -436,86 +436,3 @@ where launcher.build().launch().expect("Launcher failed"); } } - -/// python bindings for this sugar -#[cfg(feature = "python")] -pub mod pybind { - use std::path::PathBuf; - - use libafl_bolts::core_affinity::Cores; - use libafl_qemu::emu::pybind::Qemu; - use pyo3::{prelude::*, types::PyBytes}; - - use crate::qemu; - - #[pyclass(unsendable)] - #[derive(Debug)] - struct QemuBytesCoverageSugar { - input_dirs: Vec, - output_dir: PathBuf, - broker_port: u16, - cores: Cores, - use_cmplog: Option, - iterations: Option, - tokens_file: Option, - timeout: Option, - } - - #[pymethods] - impl QemuBytesCoverageSugar { - /// Create a new [`QemuBytesCoverageSugar`] - #[new] - #[allow(clippy::too_many_arguments)] - fn new( - input_dirs: Vec, - output_dir: PathBuf, - broker_port: u16, - cores: Vec, - use_cmplog: Option, - iterations: Option, - tokens_file: Option, - timeout: Option, - ) -> Self { - Self { - input_dirs, - output_dir, - broker_port, - cores: cores.into(), - use_cmplog, - iterations, - tokens_file, - timeout, - } - } - - /// Run the fuzzer - #[allow(clippy::needless_pass_by_value)] - pub fn run(&self, qemu: &Qemu, harness: PyObject) { - qemu::QemuBytesCoverageSugar::builder() - .input_dirs(&self.input_dirs) - .output_dir(self.output_dir.clone()) - .broker_port(self.broker_port) - .cores(&self.cores) - .harness(|buf| { - Python::with_gil(|py| -> PyResult<()> { - let args = (PyBytes::new(py, buf),); // TODO avoid copy - harness.call1(py, args)?; - Ok(()) - }) - .unwrap(); - }) - .use_cmplog(self.use_cmplog) - .timeout(self.timeout) - .tokens_file(self.tokens_file.clone()) - .iterations(self.iterations) - .build() - .run(&qemu.qemu); - } - } - - /// Register this class - pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - Ok(()) - } -}