use alloc::{borrow::Cow, vec::Vec};
use core::{
cmp::{max, min},
num::NonZero,
};
use libafl_bolts::{
rands::Rand,
tuples::{tuple_list, tuple_list_type},
};
use crate::{
Error,
corpus::Corpus,
inputs::EncodedInput,
mutators::{
MutationResult, Mutator, Named,
mutations::{ARITH_MAX, buffer_copy, buffer_self_copy},
},
nonzero, random_corpus_id_with_disabled,
state::{HasCorpus, HasMaxSize, HasRand},
};
#[derive(Debug, Default)]
pub struct EncodedRandMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedRandMutator {
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
if input.codes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let val = state.rand_mut().choose(input.codes_mut()).unwrap();
*val = state.rand_mut().next() as u32;
Ok(MutationResult::Mutated)
}
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedRandMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedRandMutator");
&NAME
}
}
impl EncodedRandMutator {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[derive(Debug, Default)]
pub struct EncodedIncMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedIncMutator {
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
if input.codes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let val = state.rand_mut().choose(input.codes_mut()).unwrap();
*val = val.wrapping_add(1);
Ok(MutationResult::Mutated)
}
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedIncMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedIncMutator");
&NAME
}
}
impl EncodedIncMutator {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[derive(Debug, Default)]
pub struct EncodedDecMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedDecMutator {
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
if input.codes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let val = state.rand_mut().choose(input.codes_mut()).unwrap();
*val = val.wrapping_sub(1);
Ok(MutationResult::Mutated)
}
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedDecMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedDecMutator");
&NAME
}
}
impl EncodedDecMutator {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[derive(Debug, Default)]
pub struct EncodedAddMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedAddMutator {
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
if input.codes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let val = state.rand_mut().choose(input.codes_mut()).unwrap();
let num = 1 + state.rand_mut().below(nonzero!(ARITH_MAX)) as u32;
*val = match state.rand_mut().below(nonzero!(2)) {
0 => val.wrapping_add(num),
_ => val.wrapping_sub(num),
};
Ok(MutationResult::Mutated)
}
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedAddMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedAddMutator");
&NAME
}
}
impl EncodedAddMutator {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[derive(Debug, Default)]
pub struct EncodedDeleteMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedDeleteMutator {
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
let size = input.codes().len();
if size <= 2 {
return Ok(MutationResult::Skipped);
}
let off = state
.rand_mut()
.below(unsafe { NonZero::new(size).unwrap_unchecked() });
let len = state
.rand_mut()
.below(unsafe { NonZero::new(size - off).unwrap_unchecked() });
input.codes_mut().drain(off..off + len);
Ok(MutationResult::Mutated)
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedDeleteMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedDeleteMutator");
&NAME
}
}
impl EncodedDeleteMutator {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[derive(Debug, Default)]
pub struct EncodedInsertCopyMutator {
tmp_buf: Vec<u32>,
}
impl<S> Mutator<EncodedInput, S> for EncodedInsertCopyMutator
where
S: HasRand + HasMaxSize,
{
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
let max_size = state.max_size();
let size = input.codes().len();
let Some(nz) = NonZero::new(size) else {
return Ok(MutationResult::Skipped);
};
let off = state
.rand_mut()
.below(unsafe { NonZero::new(size + 1).unwrap_unchecked() });
let mut len = 1 + state.rand_mut().below(nz);
if size + len > max_size {
if max_size > size {
len = max_size - size;
} else {
return Ok(MutationResult::Skipped);
}
}
let from = if let Some(bound) = NonZero::new(size - len) {
state.rand_mut().below(bound)
} else {
0
};
input.codes_mut().resize(size + len, 0);
self.tmp_buf.resize(len, 0);
unsafe {
buffer_copy(&mut self.tmp_buf, input.codes(), from, 0, len);
buffer_self_copy(input.codes_mut(), off, off + len, size - off);
buffer_copy(input.codes_mut(), &self.tmp_buf, 0, off, len);
};
Ok(MutationResult::Mutated)
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedInsertCopyMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedInsertCopyMutator");
&NAME
}
}
impl EncodedInsertCopyMutator {
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
#[derive(Debug, Default)]
pub struct EncodedCopyMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedCopyMutator {
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
let size = input.codes().len();
if size <= 1 {
return Ok(MutationResult::Skipped);
}
let from = state
.rand_mut()
.below(unsafe { NonZero::new(size).unwrap_unchecked() });
let to = state
.rand_mut()
.below(unsafe { NonZero::new(size).unwrap_unchecked() });
let len = 1 + state
.rand_mut()
.below(unsafe { NonZero::new(size - max(from, to)).unwrap_unchecked() });
unsafe {
buffer_self_copy(input.codes_mut(), from, to, len);
}
Ok(MutationResult::Mutated)
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedCopyMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedCopyMutator");
&NAME
}
}
impl EncodedCopyMutator {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[derive(Debug, Default)]
pub struct EncodedCrossoverInsertMutator;
impl<S> Mutator<EncodedInput, S> for EncodedCrossoverInsertMutator
where
S: HasRand + HasCorpus<EncodedInput> + HasMaxSize,
{
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
let size = input.codes().len();
let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut());
if let Some(cur) = state.corpus().current() {
if id == *cur {
return Ok(MutationResult::Skipped);
}
}
let Some(nz) = NonZero::new(size) else {
return Ok(MutationResult::Skipped);
};
let other_size = {
let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
other_testcase.load_input(state.corpus())?.codes().len()
};
if other_size < 2 {
return Ok(MutationResult::Skipped);
}
let max_size = state.max_size();
let from = state
.rand_mut()
.below(unsafe { NonZero::new(other_size).unwrap_unchecked() });
let to = state.rand_mut().below(nz);
let mut len = 1 + state
.rand_mut()
.below(unsafe { NonZero::new(other_size - from).unwrap_unchecked() });
if size + len > max_size {
if max_size > size {
len = max_size - size;
} else {
return Ok(MutationResult::Skipped);
}
}
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
let other = other_testcase.input().as_ref().unwrap();
input.codes_mut().resize(size + len, 0);
unsafe {
buffer_self_copy(input.codes_mut(), to, to + len, size - to);
buffer_copy(input.codes_mut(), other.codes(), from, to, len);
}
Ok(MutationResult::Mutated)
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedCrossoverInsertMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedCrossoverInsertMutator");
&NAME
}
}
impl EncodedCrossoverInsertMutator {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[derive(Debug, Default)]
pub struct EncodedCrossoverReplaceMutator;
impl<S> Mutator<EncodedInput, S> for EncodedCrossoverReplaceMutator
where
S: HasRand + HasCorpus<EncodedInput>,
{
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
let size = input.codes().len();
let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut());
if let Some(cur) = state.corpus().current() {
if id == *cur {
return Ok(MutationResult::Skipped);
}
}
let other_size = {
let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
other_testcase.load_input(state.corpus())?.codes().len()
};
if other_size < 2 {
return Ok(MutationResult::Skipped);
}
let from = state
.rand_mut()
.below(unsafe { NonZero::new(other_size).unwrap_unchecked() });
let len = state
.rand_mut()
.below(unsafe { NonZero::new(min(other_size - from, size)).unwrap_unchecked() });
let to = state
.rand_mut()
.below(unsafe { NonZero::new(size - len).unwrap_unchecked() });
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
let other = other_testcase.input().as_ref().unwrap();
unsafe {
buffer_copy(input.codes_mut(), other.codes(), from, to, len);
}
Ok(MutationResult::Mutated)
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_new_corpus_id: Option<crate::corpus::CorpusId>,
) -> Result<(), Error> {
Ok(())
}
}
impl Named for EncodedCrossoverReplaceMutator {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("EncodedCrossoverReplaceMutator");
&NAME
}
}
impl EncodedCrossoverReplaceMutator {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[must_use]
pub fn encoded_mutations() -> tuple_list_type!(
EncodedRandMutator,
EncodedIncMutator,
EncodedDecMutator,
EncodedAddMutator,
EncodedDeleteMutator,
EncodedInsertCopyMutator,
EncodedCopyMutator,
EncodedCrossoverInsertMutator,
EncodedCrossoverReplaceMutator,
) {
tuple_list!(
EncodedRandMutator::new(),
EncodedIncMutator::new(),
EncodedDecMutator::new(),
EncodedAddMutator::new(),
EncodedDeleteMutator::new(),
EncodedInsertCopyMutator::new(),
EncodedCopyMutator::new(),
EncodedCrossoverInsertMutator::new(),
EncodedCrossoverReplaceMutator::new(),
)
}