Fix grimoire when used with on_replace/on_remove (#1075)

This commit is contained in:
Addison Crump 2023-02-16 00:14:26 +01:00 committed by GitHub
parent e42cd9c12f
commit 26aace6073
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 136 deletions

View File

@ -5,7 +5,7 @@ use alloc::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::{Corpus, CorpusId, Testcase}, corpus::{CorpusId, Testcase},
impl_serdeany, impl_serdeany,
inputs::BytesInput, inputs::BytesInput,
stages::mutational::{MutatedTransform, MutatedTransformPost}, stages::mutational::{MutatedTransform, MutatedTransformPost},
@ -23,7 +23,7 @@ pub enum GeneralizedItem {
} }
/// Metadata regarding the generalised content of an input /// Metadata regarding the generalised content of an input
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
pub struct GeneralizedInputMetadata { pub struct GeneralizedInputMetadata {
generalized: Vec<GeneralizedItem>, generalized: Vec<GeneralizedItem>,
} }
@ -112,14 +112,16 @@ where
_state: &S, _state: &S,
corpus_idx: CorpusId, corpus_idx: CorpusId,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
base.metadata() let meta = base
.metadata()
.get::<GeneralizedInputMetadata>() .get::<GeneralizedInputMetadata>()
.ok_or_else(|| { .ok_or_else(|| {
Error::key_not_found(format!( Error::key_not_found(format!(
"Couldn't find the GeneralizedInputMetadata for corpus entry {corpus_idx}", "Couldn't find the GeneralizedInputMetadata for corpus entry {corpus_idx}",
)) ))
}) })
.cloned() .cloned()?;
Ok(meta)
} }
fn try_transform_into(self, _state: &S) -> Result<(BytesInput, Self::Post), Error> { fn try_transform_into(self, _state: &S) -> Result<(BytesInput, Self::Post), Error> {
@ -127,20 +129,4 @@ where
} }
} }
impl<S> MutatedTransformPost<S> for GeneralizedInputMetadata impl<S> MutatedTransformPost<S> for GeneralizedInputMetadata where S: HasCorpus {}
where
S: HasCorpus,
{
fn post_exec(
self,
state: &mut S,
_stage_idx: i32,
corpus_idx: Option<CorpusId>,
) -> Result<(), Error> {
if let Some(corpus_idx) = corpus_idx {
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
testcase.metadata_mut().insert(self);
}
Ok(())
}
}

View File

@ -9,7 +9,7 @@ use crate::{
corpus::Corpus, corpus::Corpus,
inputs::{GeneralizedInputMetadata, GeneralizedItem}, inputs::{GeneralizedInputMetadata, GeneralizedItem},
mutators::{token_mutations::Tokens, MutationResult, Mutator}, mutators::{token_mutations::Tokens, MutationResult, Mutator},
stages::generalization::GeneralizedIndexesMetadata, random_corpus_id,
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand},
Error, Error,
}; };
@ -22,35 +22,19 @@ fn extend_with_random_generalized<S>(
state: &mut S, state: &mut S,
items: &mut Vec<GeneralizedItem>, items: &mut Vec<GeneralizedItem>,
gap_indices: &mut Vec<usize>, gap_indices: &mut Vec<usize>,
) -> Result<(), Error> ) -> Result<MutationResult, Error>
where where
S: HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus,
{ {
let rand_idx = state.rand_mut().next() as usize; let idx = random_corpus_id!(state.corpus(), state.rand_mut());
let idx = {
let meta = state.metadata_mut().get_mut::<GeneralizedIndexesMetadata>().ok_or_else(|| {
Error::key_not_found("GeneralizedIndexesMetadata needed by extend_with_random_generalized() not found, make sure that you have GeneralizationStage in")
})?;
*meta
.indexes
.iter()
.nth(rand_idx % meta.indexes.len())
.unwrap()
};
if state.rand_mut().below(100) > CHOOSE_SUBINPUT_PROB { if state.rand_mut().below(100) > CHOOSE_SUBINPUT_PROB {
if state.rand_mut().below(100) < 50 { if state.rand_mut().below(100) < 50 {
let rand1 = state.rand_mut().next() as usize; let rand1 = state.rand_mut().next() as usize;
let rand2 = state.rand_mut().next() as usize; let rand2 = state.rand_mut().next() as usize;
let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let other_testcase = state.corpus().get(idx)?.borrow();
if let Some(other) = other_testcase if let Some(other) = other_testcase.metadata().get::<GeneralizedInputMetadata>() {
.metadata_mut()
.get::<GeneralizedInputMetadata>()
{
if other.generalized_len() > 0 {
let gen = other.generalized(); let gen = other.generalized();
for (i, _) in gen for (i, _) in gen
@ -74,8 +58,7 @@ where
debug_assert!(items.first() == Some(&GeneralizedItem::Gap)); debug_assert!(items.first() == Some(&GeneralizedItem::Gap));
debug_assert!(items.last() == Some(&GeneralizedItem::Gap)); debug_assert!(items.last() == Some(&GeneralizedItem::Gap));
return Ok(()); return Ok(MutationResult::Mutated);
}
} }
} }
@ -93,19 +76,17 @@ where
debug_assert!(items.first() == Some(&GeneralizedItem::Gap)); debug_assert!(items.first() == Some(&GeneralizedItem::Gap));
debug_assert!(items.last() == Some(&GeneralizedItem::Gap)); debug_assert!(items.last() == Some(&GeneralizedItem::Gap));
return Ok(()); return Ok(MutationResult::Mutated);
} }
} }
} }
let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let other_testcase = state.corpus().get(idx)?.borrow();
let other = other_testcase if let Some(other) = other_testcase.metadata().get::<GeneralizedInputMetadata>() {
.metadata_mut()
.get::<GeneralizedInputMetadata>()
.unwrap();
let gen = other.generalized(); let gen = other.generalized();
if items.last() == Some(&GeneralizedItem::Gap) && gen.first() == Some(&GeneralizedItem::Gap) { if items.last() == Some(&GeneralizedItem::Gap) && gen.first() == Some(&GeneralizedItem::Gap)
{
items.extend_from_slice(&gen[1..]); items.extend_from_slice(&gen[1..]);
} else { } else {
items.extend_from_slice(gen); items.extend_from_slice(gen);
@ -114,7 +95,10 @@ where
debug_assert!(items.first() == Some(&GeneralizedItem::Gap)); debug_assert!(items.first() == Some(&GeneralizedItem::Gap));
debug_assert!(items.last() == Some(&GeneralizedItem::Gap)); debug_assert!(items.last() == Some(&GeneralizedItem::Gap));
Ok(()) Ok(MutationResult::Mutated)
} else {
Ok(MutationResult::Skipped)
}
} }
/// Extend the generalized input with another random one from the corpus /// Extend the generalized input with another random one from the corpus
@ -137,9 +121,7 @@ where
state, state,
generalised_meta.generalized_mut(), generalised_meta.generalized_mut(),
&mut self.gap_indices, &mut self.gap_indices,
)?; )
Ok(MutationResult::Mutated)
} }
} }
@ -202,7 +184,11 @@ where
self.scratch.extend_from_slice(&gen[selected + 1..]); self.scratch.extend_from_slice(&gen[selected + 1..]);
gen.truncate(selected); gen.truncate(selected);
extend_with_random_generalized(state, gen, &mut self.gap_indices)?; if extend_with_random_generalized(state, gen, &mut self.gap_indices)?
== MutationResult::Skipped
{
gen.push(GeneralizedItem::Gap);
}
gen.extend_from_slice(&self.scratch); gen.extend_from_slice(&self.scratch);
self.scratch.clear(); self.scratch.clear();
@ -358,10 +344,10 @@ where
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let gen = generalised_meta.generalized_mut(); let gen = generalised_meta.generalized_mut();
for (i, _) in gen for i in gen
.iter() .iter()
.enumerate() .enumerate()
.filter(|&(_, x)| *x == GeneralizedItem::Gap) .filter_map(|(i, x)| (*x == GeneralizedItem::Gap).then_some(i))
{ {
self.gap_indices.push(i); self.gap_indices.push(i);
} }
@ -369,6 +355,7 @@ where
self.gap_indices[state.rand_mut().below(self.gap_indices.len() as u64) as usize]; self.gap_indices[state.rand_mut().below(self.gap_indices.len() as u64) as usize];
let max_idx = let max_idx =
self.gap_indices[state.rand_mut().below(self.gap_indices.len() as u64) as usize]; self.gap_indices[state.rand_mut().below(self.gap_indices.len() as u64) as usize];
let (min_idx, max_idx) = (min(min_idx, max_idx), max(min_idx, max_idx)); let (min_idx, max_idx) = (min(min_idx, max_idx), max(min_idx, max_idx));
self.gap_indices.clear(); self.gap_indices.clear();

View File

@ -106,8 +106,16 @@ where
mgr: &mut EM, mgr: &mut EM,
corpus_idx: CorpusId, corpus_idx: CorpusId,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Run this stage only once for each corpus entry // Run this stage only once for each corpus entry and only if we haven't already inspected it
if state.corpus().get(corpus_idx)?.borrow_mut().fuzz_level() > 0 { if state.corpus().get(corpus_idx)?.borrow().fuzz_level() > 0
|| state
.corpus()
.get(corpus_idx)?
.borrow()
.metadata()
.get::<SchedulerTestcaseMetaData>()
.map_or(false, |meta| meta.bitmap_size() != 0)
{
return Ok(()); return Ok(());
} }

View File

@ -6,9 +6,6 @@ use alloc::{
}; };
use core::{fmt::Debug, marker::PhantomData}; use core::{fmt::Debug, marker::PhantomData};
use hashbrown::HashSet;
use serde::{Deserialize, Serialize};
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use crate::monitors::PerfFeature; use crate::monitors::PerfFeature;
use crate::{ use crate::{
@ -27,23 +24,6 @@ use crate::{
const MAX_GENERALIZED_LEN: usize = 8192; const MAX_GENERALIZED_LEN: usize = 8192;
/// A state metadata holding the set of indexes related to the generalized corpus entries
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct GeneralizedIndexesMetadata {
/// The set of indexes
pub indexes: HashSet<CorpusId>,
}
crate::impl_serdeany!(GeneralizedIndexesMetadata);
impl GeneralizedIndexesMetadata {
/// Create the metadata
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
fn increment_by_offset(_list: &[Option<u8>], idx: usize, off: u8) -> usize { fn increment_by_offset(_list: &[Option<u8>], idx: usize, off: u8) -> usize {
idx + 1 + off as usize idx + 1 + off as usize
} }
@ -97,31 +77,12 @@ where
manager: &mut EM, manager: &mut EM,
corpus_idx: CorpusId, corpus_idx: CorpusId,
) -> Result<(), Error> { ) -> Result<(), Error> {
if state
.metadata()
.get::<GeneralizedIndexesMetadata>()
.is_none()
{
state.add_metadata(GeneralizedIndexesMetadata::new());
}
let (mut payload, original, novelties) = { let (mut payload, original, novelties) = {
start_timer!(state); start_timer!(state);
state.corpus().get(corpus_idx)?.borrow_mut().load_input()?; state.corpus().get(corpus_idx)?.borrow_mut().load_input()?;
mark_feature_time!(state, PerfFeature::GetInputFromCorpus); mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
let mut entry = state.corpus().get(corpus_idx)?.borrow_mut(); let mut entry = state.corpus().get(corpus_idx)?.borrow_mut();
if entry.metadata().contains::<GeneralizedInputMetadata>() {
drop(entry);
state
.metadata_mut()
.get_mut::<GeneralizedIndexesMetadata>()
.unwrap()
.indexes
.insert(corpus_idx);
return Ok(());
}
let input = entry.input_mut().as_mut().unwrap(); let input = entry.input_mut().as_mut().unwrap();
let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect(); let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect();
@ -327,19 +288,12 @@ where
{ {
let meta = GeneralizedInputMetadata::generalized_from_options(&payload); let meta = GeneralizedInputMetadata::generalized_from_options(&payload);
debug_assert!(meta.generalized().first() == Some(&GeneralizedItem::Gap)); assert!(meta.generalized().first() == Some(&GeneralizedItem::Gap));
debug_assert!(meta.generalized().last() == Some(&GeneralizedItem::Gap)); assert!(meta.generalized().last() == Some(&GeneralizedItem::Gap));
let mut entry = state.corpus().get(corpus_idx)?.borrow_mut(); let mut entry = state.corpus().get(corpus_idx)?.borrow_mut();
entry.metadata_mut().insert(meta); entry.metadata_mut().insert(meta);
} }
state
.metadata_mut()
.get_mut::<GeneralizedIndexesMetadata>()
.unwrap()
.indexes
.insert(corpus_idx);
} }
Ok(()) Ok(())