Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make bolts work without alloc #1401

Merged
merged 5 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ jobs:
run: cargo test
- name: Test libafl no_std
run: cd libafl && cargo test --no-default-features
- name: Test libafl_bolts no_std no_alloc
run: cd libafl_bolts && cargo test --no-default-features
- name: Test libafl_targets no_std
run: cd libafl_targets && cargo test --no-default-features

Expand Down Expand Up @@ -285,6 +287,8 @@ jobs:
run: cd ./libafl && cargo test --no-default-features
- name: libafl armv6m-none-eabi (32 bit no_std) clippy
run: cd ./libafl && cargo clippy --target thumbv6m-none-eabi --no-default-features
- name: Build no_std no_alloc bolts
run: cd ./libafl_bolts && cargo +nightly build -Zbuild-std=core --target aarch64-unknown-none --no-default-features -v --release && cd ../

build-docker:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion libafl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
bytecount = "0.6.3"

[dependencies]
libafl_bolts = { version = "0.10.1", path = "../libafl_bolts", default-features = false }
libafl_bolts = { version = "0.10.1", path = "../libafl_bolts", default-features = false, features = ["alloc"] }
libafl_derive = { version = "0.10.1", path = "../libafl_derive", optional = true }

rustversion = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion libafl/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[rustversion::nightly]
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rustc-cfg=unstable_feature");
println!("cargo:rustc-cfg=nightly");
}

#[rustversion::not(nightly)]
Expand Down
6 changes: 3 additions & 3 deletions libafl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ Welcome to `LibAFL`
#![allow(incomplete_features)]
#![no_std]
// For `type_eq`
#![cfg_attr(unstable_feature, feature(specialization))]
#![cfg_attr(nightly, feature(specialization))]
// For `type_id` and owned things
#![cfg_attr(unstable_feature, feature(intrinsics))]
#![cfg_attr(nightly, feature(intrinsics))]
// For `std::simd`
#![cfg_attr(unstable_feature, feature(portable_simd))]
#![cfg_attr(nightly, feature(portable_simd))]
#![warn(clippy::cargo)]
#![allow(ambiguous_glob_reexports)]
#![deny(clippy::cargo_common_metadata)]
Expand Down
4 changes: 2 additions & 2 deletions libafl/src/observers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ pub mod concolic;
pub mod value;

// Rust is breaking this with 'error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `type_id`' and so we disable this component for the moment
//#[cfg(unstable_feature)]
//#[cfg(nightly)]
//pub mod owned;
//#[cfg(unstable_feature)]
//#[cfg(nightly)]
//pub use owned::*;
use alloc::{
string::{String, ToString},
Expand Down
27 changes: 14 additions & 13 deletions libafl_bolts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ edition = "2021"
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]

[features]
default = ["std", "derive", "llmp_compression", "llmp_small_maps", "rand_trait", "prelude", "gzip", "serdeany_autoreg"]
std = ["serde_json", "serde_json/std", "hostname", "nix", "serde/std", "once_cell", "uuid", "byteorder", "backtrace", "uds", "serial_test"] # print, env, launcher ... support
default = ["std", "derive", "llmp_compression", "llmp_small_maps", "rand_trait", "prelude", "gzip", "serdeany_autoreg", "alloc"]
std = ["serde_json", "serde_json/std", "hostname", "nix", "serde/std", "once_cell", "uuid", "byteorder", "backtrace", "uds", "serial_test", "alloc"] # print, env, ... support
alloc = ["serde/alloc", "hashbrown", "postcard", "erased-serde/alloc", "ahash"] # Enables all features that allocate in no_std
derive = ["libafl_derive"] # provide derive(SerdeAny) macro.
rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng`
python = ["pyo3"]
python = ["pyo3", "std"]
prelude = [] # Expose libafl::prelude for access without additional using directives
cli = ["clap"] # expose libafl_bolts::cli for easy commandline parsing
qemu_cli = ["cli"] # Commandline flags for qemu-based fuzzers
qemu_cli = ["cli"] # Commandline flagr for qemu-based fuzzers
frida_cli = ["cli"] # Commandline flags for frida-based fuzzers
errors_backtrace = ["backtrace"]
gzip = ["miniz_oxide"] # Enables gzip compression in certain parts of the lib
Expand All @@ -28,10 +29,10 @@ gzip = ["miniz_oxide"] # Enables gzip compression in certain parts of the lib
serdeany_autoreg = ["ctor"] # Automatically register all `#[derive(SerdeAny)]` types at startup.

# LLMP features
llmp_bind_public = [] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default.
llmp_compression = ["gzip"] # llmp compression using GZip
llmp_debug = [] # Enables debug output for LLMP
llmp_small_maps = [] # reduces initial map size for llmp
llmp_bind_public = ["alloc"] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default.
llmp_compression = ["alloc", "gzip"] # llmp compression using GZip
llmp_debug = ["alloc"] # Enables debug output for LLMP
llmp_small_maps = ["alloc"] # reduces initial map size for llmp

[build-dependencies]
rustversion = "1.0"
Expand All @@ -45,13 +46,13 @@ libafl_derive = { version = "0.10.1", optional = true, path = "../libafl_derive"

rustversion = "1.0"
tuple_list = { version = "0.1.3" }
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features=false } # A faster hashmap, nostd compatible
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features=false, optional = true } # A faster hashmap, nostd compatible
xxhash-rust = { version = "0.8.5", features = ["xxh3"] } # xxh3 hashing for rust
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # serialization lib
erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde
postcard = { version = "1.0", features = ["alloc"] } # no_std compatible serde serialization format
serde = { version = "1.0", default-features = false, features = ["derive"] } # serialization lib
erased-serde = { version = "0.3.21", default-features = false, optional = true } # erased serde
postcard = { version = "1.0", features = ["alloc"], optional = true } # no_std compatible serde serialization format
num_enum = { version = "0.5.7", default-features = false }
ahash = { version = "0.8", default-features=false } # The hash function already used in hashbrown
ahash = { version = "0.8", default-features=false, optional = true } # The hash function already used in hashbrown
backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver

ctor = { optional = true, version = "0.2" }
Expand Down
2 changes: 1 addition & 1 deletion libafl_bolts/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[rustversion::nightly]
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rustc-cfg=unstable_feature");
println!("cargo:rustc-cfg=nightly");
}

#[rustversion::not(nightly)]
Expand Down
56 changes: 47 additions & 9 deletions libafl_bolts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ Welcome to `LibAFL`
#![allow(incomplete_features)]
#![no_std]
// For `type_eq`
#![cfg_attr(unstable_feature, feature(specialization))]
#![cfg_attr(nightly, feature(specialization))]
// For `type_id` and owned things
#![cfg_attr(unstable_feature, feature(intrinsics))]
#![cfg_attr(nightly, feature(intrinsics))]
// For `std::simd`
#![cfg_attr(unstable_feature, feature(portable_simd))]
#![cfg_attr(nightly, feature(portable_simd))]
// For `core::error`
#![cfg_attr(nightly, feature(error_in_core))]
#![warn(clippy::cargo)]
#![allow(ambiguous_glob_reexports)]
#![deny(clippy::cargo_common_metadata)]
Expand Down Expand Up @@ -78,6 +80,7 @@ Welcome to `LibAFL`
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
#[cfg(feature = "alloc")]
#[macro_use]
#[doc(hidden)]
pub extern crate alloc;
Expand All @@ -98,10 +101,11 @@ pub mod launcher {}
#[allow(unused_imports)]
#[macro_use]
extern crate libafl_derive;
#[cfg(feature = "alloc")]
use alloc::string::{FromUtf8Error, String};
use core::{
array::TryFromSliceError,
fmt,
fmt::{self, Display},
num::{ParseIntError, TryFromIntError},
};
#[cfg(feature = "std")]
Expand All @@ -110,6 +114,21 @@ use std::{env::VarError, io};
#[cfg(feature = "libafl_derive")]
pub use libafl_derive::SerdeAny;

/// We need some sort of "[`String`]" for errors in `no_alloc`...
/// We can only support `'static` without allocator, so let's do that.
#[cfg(not(feature = "alloc"))]
type String = &'static str;

/// We also need a non-allocating format...
/// This one simply returns the `fmt` string.
/// Good enough for simple errors, for anything else, use the `alloc` feature.
#[cfg(not(feature = "alloc"))]
macro_rules! format {
($fmt:literal) => {{
$fmt
}};
}

/// We need fixed names for many parts of this lib.
pub trait Named {
/// Provide the name of this element.
Expand Down Expand Up @@ -276,7 +295,7 @@ impl Error {
}
}

impl fmt::Display for Error {
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Serialize(s, b) => {
Expand Down Expand Up @@ -339,6 +358,7 @@ impl fmt::Display for Error {
}

/// Stringify the postcard serializer error
#[cfg(feature = "alloc")]
impl From<postcard::Error> for Error {
fn from(err: postcard::Error) -> Self {
Self::serialize(format!("{err:?}"))
Expand Down Expand Up @@ -368,39 +388,46 @@ impl From<io::Error> for Error {
}
}

#[cfg(feature = "alloc")]
impl From<FromUtf8Error> for Error {
#[allow(unused_variables)]
fn from(err: FromUtf8Error) -> Self {
Self::unknown(format!("Could not convert byte / utf-8: {err:?}"))
}
}

#[cfg(feature = "std")]
impl From<VarError> for Error {
#[allow(unused_variables)]
fn from(err: VarError) -> Self {
Self::empty(format!("Could not get env var: {err:?}"))
}
}

impl From<ParseIntError> for Error {
#[allow(unused_variables)]
fn from(err: ParseIntError) -> Self {
Self::unknown(format!("Failed to parse Int: {err:?}"))
}
}

impl From<TryFromIntError> for Error {
#[allow(unused_variables)]
fn from(err: TryFromIntError) -> Self {
Self::illegal_state(format!("Expected conversion failed: {err:?}"))
}
}

impl From<TryFromSliceError> for Error {
#[allow(unused_variables)]
fn from(err: TryFromSliceError) -> Self {
Self::illegal_argument(format!("Could not convert slice: {err:?}"))
}
}

#[cfg(windows)]
impl From<windows::core::Error> for Error {
#[allow(unused_variables)]
fn from(err: windows::core::Error) -> Self {
Self::unknown(format!("Windows API error: {err:?}"))
}
Expand All @@ -422,9 +449,12 @@ impl From<pyo3::PyErr> for Error {
}
}

#[cfg(feature = "std")]
#[cfg(all(not(nightly), feature = "std"))]
impl std::error::Error for Error {}

#[cfg(nightly)]
impl core::error::Error for Error {}

/// The purpose of this module is to alleviate imports of many components by adding a glob import.
#[cfg(feature = "prelude")]
pub mod prelude {
Expand All @@ -439,6 +469,7 @@ pub unsafe extern "C" fn external_current_millis() -> u64 {
1000
}

#[cfg(feature = "alloc")]
pub mod anymap;
#[cfg(feature = "std")]
pub mod build_id;
Expand All @@ -454,18 +485,22 @@ pub mod core_affinity;
pub mod cpu;
#[cfg(feature = "std")]
pub mod fs;
#[cfg(feature = "alloc")]
pub mod llmp;
#[cfg(all(feature = "std", unix))]
pub mod minibsod;
pub mod os;
#[cfg(feature = "alloc")]
pub mod ownedref;
pub mod rands;
#[cfg(feature = "alloc")]
pub mod serdeany;
pub mod shmem;
#[cfg(feature = "std")]
pub mod staterestore;
pub mod tuples;

#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::{iter::Iterator, ops::AddAssign, time};
#[cfg(feature = "std")]
Expand Down Expand Up @@ -499,6 +534,7 @@ pub trait AsMutSlice {
fn as_mut_slice(&mut self) -> &mut [Self::Entry];
}

#[cfg(feature = "alloc")]
impl<T> AsSlice for Vec<T> {
type Entry = T;

Expand All @@ -507,6 +543,7 @@ impl<T> AsSlice for Vec<T> {
}
}

#[cfg(feature = "alloc")]
impl<T> AsMutSlice for Vec<T> {
type Entry = T;

Expand Down Expand Up @@ -653,6 +690,7 @@ pub fn current_milliseconds() -> u64 {
}

/// Format a `Duration` into a HMS string
#[cfg(feature = "alloc")]
#[must_use]
pub fn format_duration_hms(duration: &time::Duration) -> String {
let secs = duration.as_secs();
Expand Down Expand Up @@ -802,9 +840,9 @@ pub mod bolts_prelude {
pub use super::minibsod::*;
#[cfg(feature = "std")]
pub use super::staterestore::*;
pub use super::{
anymap::*, cpu::*, llmp::*, os::*, ownedref::*, rands::*, serdeany::*, shmem::*, tuples::*,
};
#[cfg(feature = "alloc")]
pub use super::{anymap::*, llmp::*, ownedref::*, rands::*, serdeany::*, shmem::*, tuples::*};
pub use super::{cpu::*, os::*, rands::*};
}

#[cfg(feature = "python")]
Expand Down
Loading