* Auto-implement Rand for (normal, rusty rng) CoreRng types, fixes #3060 * clippy * cleanup * clip * doc * more doc
This commit is contained in:
parent
bf3c391ffa
commit
115672904e
@ -76,7 +76,7 @@ trait State:
|
|||||||
impl<C, I, R, SC> State for StdState<C, I, R, SC>
|
impl<C, I, R, SC> State for StdState<C, I, R, SC>
|
||||||
where
|
where
|
||||||
C: Serialize + DeserializeOwned,
|
C: Serialize + DeserializeOwned,
|
||||||
R: Rand,
|
R: Rand + Serialize + for<'de> Deserialize<'de>,
|
||||||
SC: Serialize + DeserializeOwned,
|
SC: Serialize + DeserializeOwned,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,8 @@ alloc = ["serde/alloc", "hashbrown", "postcard", "erased-serde/alloc", "ahash"]
|
|||||||
## Provide the `#[derive(SerdeAny)]` macro.
|
## Provide the `#[derive(SerdeAny)]` macro.
|
||||||
derive = ["libafl_derive"]
|
derive = ["libafl_derive"]
|
||||||
|
|
||||||
## If set, libafl_bolt's `rand` implementations will implement `rand::Rng`
|
## If set, libafl_bolt's `rand` implementations will implement `rand_core::CoreRng`
|
||||||
|
## and, inversely, all seedable `rand_core::RngCore` types can be used as Rng for LibAFL.
|
||||||
rand_trait = ["rand_core"]
|
rand_trait = ["rand_core"]
|
||||||
|
|
||||||
## Will build the `pyo3` bindings
|
## Will build the `pyo3` bindings
|
||||||
|
@ -8,7 +8,9 @@ use core::{
|
|||||||
num::{NonZero, NonZeroUsize},
|
num::{NonZero, NonZeroUsize},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
#[cfg(feature = "rand_trait")]
|
||||||
|
use rand_core::{RngCore, SeedableRng};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub mod loaded_dice;
|
pub mod loaded_dice;
|
||||||
@ -103,7 +105,7 @@ fn fast_bound_usize(rand: u64, n: usize) -> usize {
|
|||||||
/// Ways to get random around here.
|
/// Ways to get random around here.
|
||||||
/// Please note that these are not cryptographically secure.
|
/// Please note that these are not cryptographically secure.
|
||||||
/// Or, even if some might be by accident, at least they are not seeded in a cryptographically secure fashion.
|
/// Or, even if some might be by accident, at least they are not seeded in a cryptographically secure fashion.
|
||||||
pub trait Rand: Debug + Serialize + DeserializeOwned {
|
pub trait Rand {
|
||||||
/// Sets the seed of this Rand
|
/// Sets the seed of this Rand
|
||||||
fn set_seed(&mut self, seed: u64);
|
fn set_seed(&mut self, seed: u64);
|
||||||
|
|
||||||
@ -220,6 +222,20 @@ pub trait Rand: Debug + Serialize + DeserializeOwned {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rand_trait")]
|
||||||
|
impl<T> Rand for T
|
||||||
|
where
|
||||||
|
T: RngCore + SeedableRng + Serialize + for<'de> Deserialize<'de> + Debug,
|
||||||
|
{
|
||||||
|
fn set_seed(&mut self, seed: u64) {
|
||||||
|
*self = Self::seed_from_u64(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&mut self) -> u64 {
|
||||||
|
self.next_u64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_default_new {
|
macro_rules! impl_default_new {
|
||||||
($rand:ty) => {
|
($rand:ty) => {
|
||||||
impl Default for $rand {
|
impl Default for $rand {
|
||||||
@ -540,6 +556,92 @@ impl XkcdRand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
/// `Rand` Python bindings
|
||||||
|
pub mod pybind {
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::{Rand, StdRand, random_seed};
|
||||||
|
|
||||||
|
#[pyclass(unsendable, name = "StdRand")]
|
||||||
|
#[expect(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_random_seed() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: StdRand::with_seed(random_seed()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[staticmethod]
|
||||||
|
fn with_seed(seed: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: StdRand::with_seed(seed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_rand(slf: Py<Self>) -> PythonRand {
|
||||||
|
PythonRand::new_std(slf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
enum PythonRandWrapper {
|
||||||
|
Std(Py<PythonStdRand>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rand Trait binding
|
||||||
|
#[pyclass(unsendable, name = "Rand")]
|
||||||
|
#[expect(clippy::unsafe_derive_deserialize)]
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
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<PythonStdRand>) -> 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(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
|
m.add_class::<PythonStdRand>()?;
|
||||||
|
m.add_class::<PythonRand>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -664,90 +766,40 @@ mod tests {
|
|||||||
assert_eq!(v, u);
|
assert_eq!(v, u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "python")]
|
#[test]
|
||||||
/// `Rand` Python bindings
|
#[cfg(feature = "rand_trait")]
|
||||||
pub mod pybind {
|
fn test_rand_trait() {
|
||||||
use pyo3::prelude::*;
|
use rand_core::{RngCore, SeedableRng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{Rand, StdRand, random_seed};
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct CountingRng(u64);
|
||||||
|
|
||||||
#[pyclass(unsendable, name = "StdRand")]
|
impl RngCore for CountingRng {
|
||||||
#[expect(clippy::unsafe_derive_deserialize)]
|
fn next_u32(&mut self) -> u32 {
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
self.next_u64() as u32
|
||||||
/// Python class for StdRand
|
}
|
||||||
pub struct PythonStdRand {
|
|
||||||
/// Rust wrapped StdRand object
|
|
||||||
pub inner: StdRand,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pymethods]
|
fn next_u64(&mut self) -> u64 {
|
||||||
impl PythonStdRand {
|
self.0 += 1;
|
||||||
#[staticmethod]
|
self.0
|
||||||
fn with_random_seed() -> Self {
|
}
|
||||||
Self {
|
|
||||||
inner: StdRand::with_seed(random_seed()),
|
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||||
|
rand_core::impls::fill_bytes_via_next(self, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[staticmethod]
|
impl SeedableRng for CountingRng {
|
||||||
fn with_seed(seed: u64) -> Self {
|
type Seed = [u8; 8];
|
||||||
Self {
|
|
||||||
inner: StdRand::with_seed(seed),
|
fn from_seed(seed: Self::Seed) -> Self {
|
||||||
|
Self(u64::from_le_bytes(seed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_rand(slf: Py<Self>) -> PythonRand {
|
// LibAFL's Rand trait is auto-implemented for all SeedableRng + RngCore types.
|
||||||
PythonRand::new_std(slf)
|
assert!(CountingRng(0).coinflip(0.1));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
enum PythonRandWrapper {
|
|
||||||
Std(Py<PythonStdRand>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Rand Trait binding
|
|
||||||
#[pyclass(unsendable, name = "Rand")]
|
|
||||||
#[expect(clippy::unsafe_derive_deserialize)]
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
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<PythonStdRand>) -> 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(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
||||||
m.add_class::<PythonStdRand>()?;
|
|
||||||
m.add_class::<PythonRand>()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,6 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
libfuzzer.compile("libfuzzer");
|
libfuzzer.compile("libfuzzer");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "coverage")]
|
#[cfg(feature = "coverage")]
|
||||||
@ -222,7 +221,8 @@ fn main() {
|
|||||||
cmplog.link_lib_modifier("+whole-archive");
|
cmplog.link_lib_modifier("+whole-archive");
|
||||||
}
|
}
|
||||||
|
|
||||||
cmplog.flag("-Wno-pointer-sign") // UNIX ONLY FLAGS
|
cmplog
|
||||||
|
.flag("-Wno-pointer-sign") // UNIX ONLY FLAGS
|
||||||
.flag("-Wno-sign-compare")
|
.flag("-Wno-sign-compare")
|
||||||
.define("CMP_MAP_SIZE", Some(&*format!("{cmp_map_size}")))
|
.define("CMP_MAP_SIZE", Some(&*format!("{cmp_map_size}")))
|
||||||
.define("CMPLOG_MAP_W", Some(&*format!("{cmplog_map_w}")))
|
.define("CMPLOG_MAP_W", Some(&*format!("{cmplog_map_w}")))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user