#![allow(incomplete_features)]
#![no_std]
#![cfg_attr(unstable_feature, feature(specialization))]
#![cfg_attr(unstable_feature, feature(intrinsics))]
#![cfg_attr(unstable_feature, feature(portable_simd))]
#![warn(clippy::cargo)]
#![deny(clippy::cargo_common_metadata)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::all)]
#![deny(clippy::pedantic)]
#![allow(
clippy::unreadable_literal,
clippy::type_repetition_in_bounds,
clippy::missing_errors_doc,
clippy::cast_possible_truncation,
clippy::used_underscore_binding,
clippy::ptr_as_ptr,
clippy::missing_panics_doc,
clippy::missing_docs_in_private_items,
clippy::module_name_repetitions,
clippy::unreadable_literal
)]
#![cfg_attr(not(test), warn(
missing_debug_implementations,
missing_docs,
//trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
//unused_results
))]
#![cfg_attr(test, deny(
missing_debug_implementations,
missing_docs,
//trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_must_use,
missing_docs,
//unused_results
))]
#![cfg_attr(
test,
deny(
bad_style,
dead_code,
improper_ctypes,
non_shorthand_field_patterns,
no_mangle_generic_items,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
private_in_public,
unconditional_recursion,
unused,
unused_allocation,
unused_comparisons,
unused_parens,
while_true
)
)]
#![allow(clippy::borrow_as_ptr)]
#![allow(clippy::borrow_deref_ref)]
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
#[macro_use]
pub extern crate alloc;
#[macro_use]
extern crate static_assertions;
#[cfg(feature = "ctor")]
pub use ctor::ctor;
#[cfg(feature = "libafl_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate libafl_derive;
#[cfg(feature = "libafl_derive")]
#[doc(hidden)]
pub use libafl_derive::*;
pub mod bolts;
pub mod corpus;
pub mod events;
pub mod executors;
pub mod feedbacks;
pub mod generators;
pub mod inputs;
pub mod monitors;
pub mod mutators;
pub mod observers;
pub mod schedulers;
pub mod stages;
pub mod state;
pub mod fuzzer;
use alloc::string::{FromUtf8Error, String};
use core::{
array::TryFromSliceError,
fmt,
num::{ParseIntError, TryFromIntError},
};
#[cfg(feature = "std")]
use std::{env::VarError, io};
pub use fuzzer::*;
#[cfg(feature = "errors_backtrace")]
pub type ErrorBacktrace = backtrace::Backtrace;
#[cfg(not(feature = "errors_backtrace"))]
#[derive(Debug, Default)]
pub struct ErrorBacktrace {}
#[cfg(not(feature = "errors_backtrace"))]
impl ErrorBacktrace {
#[must_use]
pub fn new() -> Self {
Self {}
}
}
#[cfg(feature = "errors_backtrace")]
fn display_error_backtrace(f: &mut fmt::Formatter, err: &ErrorBacktrace) -> fmt::Result {
write!(f, "\nBacktrace: {err:?}")
}
#[cfg(not(feature = "errors_backtrace"))]
#[allow(clippy::unnecessary_wraps)]
fn display_error_backtrace(_f: &mut fmt::Formatter, _err: &ErrorBacktrace) -> fmt::Result {
fmt::Result::Ok(())
}
#[derive(Debug)]
pub enum Error {
Serialize(String, ErrorBacktrace),
#[cfg(feature = "llmp_compression")]
Compression(ErrorBacktrace),
#[cfg(feature = "std")]
File(io::Error, ErrorBacktrace),
EmptyOptional(String, ErrorBacktrace),
KeyNotFound(String, ErrorBacktrace),
Empty(String, ErrorBacktrace),
IteratorEnd(String, ErrorBacktrace),
NotImplemented(String, ErrorBacktrace),
IllegalState(String, ErrorBacktrace),
IllegalArgument(String, ErrorBacktrace),
Unsupported(String, ErrorBacktrace),
ShuttingDown,
Unknown(String, ErrorBacktrace),
}
impl Error {
#[must_use]
pub fn serialize<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::Serialize(arg.into(), ErrorBacktrace::new())
}
#[cfg(feature = "llmp_compression")]
#[must_use]
pub fn compression() -> Self {
Error::Compression(ErrorBacktrace::new())
}
#[cfg(feature = "std")]
#[must_use]
pub fn file(arg: io::Error) -> Self {
Error::File(arg, ErrorBacktrace::new())
}
#[must_use]
pub fn empty_optional<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::EmptyOptional(arg.into(), ErrorBacktrace::new())
}
#[must_use]
pub fn key_not_found<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::KeyNotFound(arg.into(), ErrorBacktrace::new())
}
#[must_use]
pub fn empty<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::Empty(arg.into(), ErrorBacktrace::new())
}
#[must_use]
pub fn iterator_end<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::IteratorEnd(arg.into(), ErrorBacktrace::new())
}
#[must_use]
pub fn not_implemented<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::NotImplemented(arg.into(), ErrorBacktrace::new())
}
#[must_use]
pub fn illegal_state<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::IllegalState(arg.into(), ErrorBacktrace::new())
}
#[must_use]
pub fn illegal_argument<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::IllegalArgument(arg.into(), ErrorBacktrace::new())
}
#[must_use]
pub fn shutting_down() -> Self {
Error::ShuttingDown
}
#[must_use]
pub fn unsupported<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::Unsupported(arg.into(), ErrorBacktrace::new())
}
#[must_use]
pub fn unknown<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::Unknown(arg.into(), ErrorBacktrace::new())
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Serialize(s, b) => {
write!(f, "Error in Serialization: `{0}`", &s)?;
display_error_backtrace(f, b)
}
#[cfg(feature = "llmp_compression")]
Self::Compression(b) => {
write!(f, "Error in decompression")?;
display_error_backtrace(f, b)
}
#[cfg(feature = "std")]
Self::File(err, b) => {
write!(f, "File IO failed: {:?}", &err)?;
display_error_backtrace(f, b)
}
Self::EmptyOptional(s, b) => {
write!(f, "Optional value `{0}` was not set", &s)?;
display_error_backtrace(f, b)
}
Self::KeyNotFound(s, b) => {
write!(f, "Key `{0}` not in Corpus", &s)?;
display_error_backtrace(f, b)
}
Self::Empty(s, b) => {
write!(f, "No items in {0}", &s)?;
display_error_backtrace(f, b)
}
Self::IteratorEnd(s, b) => {
write!(f, "All elements have been processed in {0} iterator", &s)?;
display_error_backtrace(f, b)
}
Self::NotImplemented(s, b) => {
write!(f, "Not implemented: {0}", &s)?;
display_error_backtrace(f, b)
}
Self::IllegalState(s, b) => {
write!(f, "Illegal state: {0}", &s)?;
display_error_backtrace(f, b)
}
Self::IllegalArgument(s, b) => {
write!(f, "Illegal argument: {0}", &s)?;
display_error_backtrace(f, b)
}
Self::Unsupported(s, b) => {
write!(
f,
"The operation is not supported on the current platform: {0}",
&s
)?;
display_error_backtrace(f, b)
}
Self::ShuttingDown => write!(f, "Shutting down!"),
Self::Unknown(s, b) => {
write!(f, "Unknown error: {0}", &s)?;
display_error_backtrace(f, b)
}
}
}
}
impl From<postcard::Error> for Error {
fn from(err: postcard::Error) -> Self {
Self::serialize(format!("{err:?}"))
}
}
#[cfg(feature = "std")]
impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Self {
Self::serialize(format!("{err:?}"))
}
}
#[cfg(all(unix, feature = "std"))]
impl From<nix::Error> for Error {
fn from(err: nix::Error) -> Self {
Self::unknown(format!("Unix error: {err:?}"))
}
}
#[cfg(feature = "std")]
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::file(err)
}
}
impl From<FromUtf8Error> for Error {
fn from(err: FromUtf8Error) -> Self {
Self::unknown(format!("Could not convert byte / utf-8: {err:?}"))
}
}
#[cfg(feature = "std")]
impl From<VarError> for Error {
fn from(err: VarError) -> Self {
Self::empty(format!("Could not get env var: {err:?}"))
}
}
impl From<ParseIntError> for Error {
fn from(err: ParseIntError) -> Self {
Self::unknown(format!("Failed to parse Int: {err:?}"))
}
}
impl From<TryFromIntError> for Error {
fn from(err: TryFromIntError) -> Self {
Self::illegal_state(format!("Expected conversion failed: {err:?}"))
}
}
impl From<TryFromSliceError> for Error {
fn from(err: TryFromSliceError) -> Self {
Self::illegal_argument(format!("Could not convert slice: {err:?}"))
}
}
#[cfg(windows)]
impl From<windows::core::Error> for Error {
fn from(err: windows::core::Error) -> Self {
Self::unknown(format!("Windows API error: {err:?}"))
}
}
#[cfg(feature = "python")]
impl From<pyo3::PyErr> for Error {
fn from(err: pyo3::PyErr) -> Self {
pyo3::Python::with_gil(|py| {
if err.matches(
py,
pyo3::types::PyType::new::<pyo3::exceptions::PyKeyboardInterrupt>(py),
) {
Self::shutting_down()
} else {
Self::illegal_state(format!("Python exception: {err:?}"))
}
})
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
#[cfg(feature = "prelude")]
pub mod prelude {
pub use super::{
bolts::{bolts_prelude::*, *},
corpus::*,
events::*,
executors::*,
feedbacks::*,
fuzzer::*,
generators::*,
inputs::*,
monitors::*,
mutators::*,
observers::*,
schedulers::*,
stages::*,
state::*,
*,
};
}
#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use crate::{
bolts::{rands::StdRand, tuples::tuple_list},
corpus::{Corpus, InMemoryCorpus, Testcase},
events::NopEventManager,
executors::{ExitKind, InProcessExecutor},
feedbacks::ConstFeedback,
fuzzer::Fuzzer,
inputs::BytesInput,
monitors::SimpleMonitor,
mutators::{mutations::BitFlipMutator, StdScheduledMutator},
schedulers::RandScheduler,
stages::StdMutationalStage,
state::{HasCorpus, StdState},
StdFuzzer,
};
#[test]
#[allow(clippy::similar_names)]
fn test_fuzzer() {
let rand = StdRand::with_seed(0);
let mut corpus = InMemoryCorpus::<BytesInput>::new();
let testcase = Testcase::new(vec![0; 4].into());
corpus.add(testcase).unwrap();
let mut feedback = ConstFeedback::new(false);
let mut objective = ConstFeedback::new(false);
let mut state = StdState::new(
rand,
corpus,
InMemoryCorpus::<BytesInput>::new(),
&mut feedback,
&mut objective,
)
.unwrap();
let _monitor = SimpleMonitor::new(|s| {
println!("{s}");
});
let mut event_manager = NopEventManager::new();
let feedback = ConstFeedback::new(false);
let objective = ConstFeedback::new(false);
let scheduler = RandScheduler::new();
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let mut harness = |_buf: &BytesInput| ExitKind::Ok;
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(),
&mut fuzzer,
&mut state,
&mut event_manager,
)
.unwrap();
let mutator = StdScheduledMutator::new(tuple_list!(BitFlipMutator::new()));
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
for i in 0..1000 {
fuzzer
.fuzz_one(&mut stages, &mut executor, &mut state, &mut event_manager)
.unwrap_or_else(|_| panic!("Error in iter {i}"));
}
let state_serialized = postcard::to_allocvec(&state).unwrap();
let state_deserialized: StdState<
_,
InMemoryCorpus<BytesInput>,
StdRand,
InMemoryCorpus<BytesInput>,
> = postcard::from_bytes(state_serialized.as_slice()).unwrap();
assert_eq!(state.corpus().count(), state_deserialized.corpus().count());
let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap();
let corpus_deserialized: InMemoryCorpus<BytesInput> =
postcard::from_bytes(corpus_serialized.as_slice()).unwrap();
assert_eq!(state.corpus().count(), corpus_deserialized.count());
}
}
#[cfg(all(any(doctest, test), not(feature = "std")))]
#[no_mangle]
pub extern "C" fn external_current_millis() -> u64 {
1000
}
#[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind {
use pyo3::prelude::*;
use super::{
bolts, corpus, events, executors, feedbacks, fuzzer, generators, monitors, mutators,
observers, stages, state,
};
#[derive(Debug, Clone)]
pub struct PythonMetadata {
pub map: PyObject,
}
crate::impl_serde_pyobjectwrapper!(PythonMetadata, map);
crate::impl_serdeany!(PythonMetadata);
impl PythonMetadata {
#[must_use]
pub fn new(map: PyObject) -> Self {
Self { map }
}
}
#[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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let buf = Python::with_gil(|py| -> PyResult<Vec<u8>> {
let pickle = PyModule::import(py, "pickle")?;
let buf: Vec<u8> =
pickle.getattr("dumps")?.call1((&self.$inner,))?.extract()?;
Ok(buf)
})
.unwrap();
serializer.serialize_bytes(&buf)
}
}
struct PyObjectVisitor;
impl<'de> serde::de::Visitor<'de> for PyObjectVisitor {
type Value = $struct_name;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter
.write_str("Expecting some bytes to deserialize from the Python side")
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let obj = Python::with_gil(|py| -> PyResult<PyObject> {
let pickle = PyModule::import(py, "pickle")?;
let obj = pickle.getattr("loads")?.call1((v,))?.to_object(py);
Ok(obj)
})
.unwrap();
Ok($struct_name::new(obj))
}
}
impl<'de> Deserialize<'de> for $struct_name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_byte_buf(PyObjectVisitor)
}
}
};
};
}
#[pymodule]
#[pyo3(name = "libafl")]
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
observers::map::pybind::register(py, m)?;
observers::pybind::register(py, m)?;
feedbacks::map::pybind::register(py, m)?;
feedbacks::pybind::register(py, m)?;
state::pybind::register(py, m)?;
monitors::pybind::register(py, m)?;
events::pybind::register(py, m)?;
events::simple::pybind::register(py, m)?;
fuzzer::pybind::register(py, m)?;
executors::pybind::register(py, m)?;
executors::inprocess::pybind::register(py, m)?;
generators::pybind::register(py, m)?;
mutators::pybind::register(py, m)?;
mutators::scheduled::pybind::register(py, m)?;
corpus::pybind::register(py, m)?;
corpus::testcase::pybind::register(py, m)?;
corpus::ondisk::pybind::register(py, m)?;
corpus::inmemory::pybind::register(py, m)?;
corpus::cached::pybind::register(py, m)?;
bolts::rands::pybind::register(py, m)?;
stages::pybind::register(py, m)?;
stages::mutational::pybind::register(py, m)?;
Ok(())
}
}