From 4d06f28d282526b7618319a91bdead87f8991f96 Mon Sep 17 00:00:00 2001 From: plotchy <98172525+plotchy@users.noreply.github.com> Date: Sat, 18 May 2024 12:47:47 -0400 Subject: [PATCH] feat: add incrementing and decrementing mutator (#476) * feat: add incdec mutator * fix: remove trace! log --- src/mutation_utils.rs | 69 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/mutation_utils.rs b/src/mutation_utils.rs index 35d12d4d..7bdeeab0 100644 --- a/src/mutation_utils.rs +++ b/src/mutation_utils.rs @@ -60,6 +60,73 @@ impl ConstantPoolMetadata { impl_serdeany!(ConstantPoolMetadata); +/// [`IncDecValue`] is a mutator that mutates the input by overflowing_add 1 or +/// overflowing_sub 1 +/// +/// When paired with [`ConstantHintedMutator`], it allows us to increase test +/// coverage by passing ` gt` and ` lt` in +/// the contract +#[derive(Default)] +pub struct IncDecValue; + +impl Named for IncDecValue { + fn name(&self) -> &str { + "IncDecValue" + } +} + +impl IncDecValue { + pub fn new() -> Self { + Self + } +} + +impl Mutator for IncDecValue +where + S: State + HasRand + HasMetadata, + I: Input + HasBytesVec, +{ + /// Mutate the input by adding 1 to the last byte, with carry propagation + fn mutate(&mut self, state: &mut S, input: &mut I, _stage_idx: i32) -> Result { + let input_bytes = input.bytes_mut(); + match state.rand_mut().below(2) { + 0 => { + // increment input by 1 + let mut carry = true; + for byte in input_bytes.iter_mut().rev() { + if carry { + let (new_byte, new_carry) = byte.overflowing_add(1); + *byte = new_byte; + carry = new_carry; + } else { + break; + } + } + Ok(MutationResult::Mutated) + } + 1 => { + // decrement input by 1 + let mut borrow = true; + for byte in input_bytes.iter_mut().rev() { + if borrow { + let (new_byte, new_borrow) = byte.overflowing_sub(1); + *byte = new_byte; + borrow = new_borrow; + } else { + break; + } + } + Ok(MutationResult::Mutated) + } + _ => { + // Should be unreachable. If here, rand.below didn't work as expected. + // unreachable!() + Ok(MutationResult::Skipped) + } + } + } +} + /// [`ConstantHintedMutator`] is a mutator that mutates the input to a constant /// in the contract /// @@ -178,6 +245,7 @@ where WordInterestingMutator::new(), DwordInterestingMutator::new(), ConstantHintedMutator::new(), + IncDecValue::new(), ); if let Some(vm_slots) = vm_slots { @@ -210,6 +278,7 @@ where BytesInsertMutator::new(), BytesRandInsertMutator::new(), ConstantHintedMutator::new(), + IncDecValue::new(), ); if let Some(vm_slots) = vm_slots {