зеркало из https://github.com/microsoft/lain.git
Breaking change: remove mutator mode/corpus fuzzing state
This commit is contained in:
Родитель
3b3dbe6d4a
Коммит
88ef34d91b
|
@ -211,11 +211,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "lain"
|
||||
version = "0.2.5"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"field-offset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lain_derive 0.2.5",
|
||||
"lain_derive 0.3.0",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -228,7 +228,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lain_derive"
|
||||
version = "0.2.5"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -632,7 +632,7 @@ name = "testsuite"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lain 0.2.5",
|
||||
"lain 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -84,15 +84,8 @@ fn fuzzer_routine<R: Rng>(mutator: &mut Mutator<R>, thread_context: &mut FuzzerT
|
|||
|
||||
let packet = match thread_context.last_packet {
|
||||
Some(ref mut last_packet) => {
|
||||
if mutator.mode() == MutatorMode::Havoc {
|
||||
last_packet.mutate(mutator, None);
|
||||
last_packet
|
||||
} else {
|
||||
// We want to do fuzzing of every field separately
|
||||
thread_context.scratch_packet = last_packet.clone();
|
||||
thread_context.scratch_packet.mutate(mutator, None);
|
||||
&thread_context.scratch_packet
|
||||
}
|
||||
last_packet.mutate(mutator, None);
|
||||
last_packet
|
||||
}
|
||||
_ => {
|
||||
mutator.begin_new_corpus();
|
||||
|
|
|
@ -241,7 +241,7 @@ pub fn start_fuzzer<F: 'static, C: 'static, T: 'static + Send + Sync>(
|
|||
return;
|
||||
}
|
||||
|
||||
mutator.begin_new_iteration();
|
||||
mutator.random_flags();
|
||||
|
||||
if let Err(_) =
|
||||
(callback)(&mut mutator, &mut context, thread_driver.global_context())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::mutator::{Mutator, MutatorMode};
|
||||
use crate::mutator::{Mutator};
|
||||
use crate::rand::seq::index;
|
||||
use crate::rand::Rng;
|
||||
use crate::traits::*;
|
||||
|
@ -204,7 +204,7 @@ where
|
|||
const CHANCE_TO_RESIZE_VEC: f64 = 0.01;
|
||||
|
||||
// 1% chance to resize this vec
|
||||
if mutator.mode() == MutatorMode::Havoc && mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
|
||||
if mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
|
||||
shrink_vec(self, mutator);
|
||||
} else {
|
||||
// Recreate the constraints so that the min/max types match
|
||||
|
@ -244,7 +244,7 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
if mutator.mode() == MutatorMode::Havoc && mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
|
||||
if mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
|
||||
let resize_type = VecResizeType::new_fuzzed(mutator, None);
|
||||
if resize_type == VecResizeType::Grow {
|
||||
grow_vec(self, mutator, constraints.and_then(|c| c.max_size));
|
||||
|
@ -327,7 +327,7 @@ where
|
|||
|
||||
match *self {
|
||||
UnsafeEnum::Invalid(ref mut value) => {
|
||||
mutator.mutate_from_mutation_mode(value);
|
||||
mutator.mutate(value);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ macro_rules! impl_mutatable {
|
|||
|
||||
#[inline(always)]
|
||||
fn mutate<R: Rng>(&mut self, mutator: &mut Mutator<R>, _constraints: Option<&Constraints<Self::RangeType>>) {
|
||||
mutator.mutate_from_mutation_mode(self);
|
||||
mutator.mutate(self);
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
@ -397,7 +397,7 @@ impl Mutatable for i8 {
|
|||
_constraints: Option<&Constraints<Self::RangeType>>,
|
||||
) {
|
||||
let mut val = *self as u8;
|
||||
mutator.mutate_from_mutation_mode(&mut val);
|
||||
mutator.mutate(&mut val);
|
||||
*self = val as i8;
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +412,7 @@ impl Mutatable for i16 {
|
|||
_constraints: Option<&Constraints<Self::RangeType>>,
|
||||
) {
|
||||
let mut val = *self as u16;
|
||||
mutator.mutate_from_mutation_mode(&mut val);
|
||||
mutator.mutate(&mut val);
|
||||
*self = val as i16;
|
||||
}
|
||||
}
|
||||
|
@ -427,7 +427,7 @@ impl Mutatable for i32 {
|
|||
_constraints: Option<&Constraints<Self::RangeType>>,
|
||||
) {
|
||||
let mut val = *self as u32;
|
||||
mutator.mutate_from_mutation_mode(&mut val);
|
||||
mutator.mutate(&mut val);
|
||||
*self = val as i32;
|
||||
}
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ impl Mutatable for i64 {
|
|||
_constraints: Option<&Constraints<Self::RangeType>>,
|
||||
) {
|
||||
let mut val = *self as u64;
|
||||
mutator.mutate_from_mutation_mode(&mut val);
|
||||
mutator.mutate(&mut val);
|
||||
*self = val as i64;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,23 +30,11 @@ enum MutatorOperation {
|
|||
Arithmetic,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
enum MutatorFlags {
|
||||
FuzzUpToNFields(usize),
|
||||
ShouldAlwaysPerformPostMutation(bool),
|
||||
AllChancesSucceedOrFail(bool),
|
||||
}
|
||||
|
||||
/// Represents the mode of the mutator
|
||||
#[derive(PartialEq, Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||
pub enum MutatorMode {
|
||||
/// Performs a linear bit flip from index 0 up to the max bit index, flipping `current_idx` number of bits
|
||||
WalkingBitFlip { bits: u8, current_idx: u8 },
|
||||
/// Selects interesting values for the current data type
|
||||
InterestingValues { current_idx: u8 },
|
||||
/// All-out random mutation
|
||||
Havoc,
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct MutatorFlags {
|
||||
field_count: Option<usize>,
|
||||
always_fixup: bool,
|
||||
all_chances_succeed: bool,
|
||||
}
|
||||
|
||||
/// Represents the state of the current corpus item being fuzzed.
|
||||
|
@ -54,22 +42,12 @@ pub enum MutatorMode {
|
|||
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||
pub struct CorpusFuzzingState {
|
||||
fields_fuzzed: usize,
|
||||
mode: MutatorMode,
|
||||
targeted_field_idx: usize,
|
||||
pub target_total_fields: usize,
|
||||
target_total_passes: usize,
|
||||
finished_iteration: bool,
|
||||
}
|
||||
|
||||
impl Default for CorpusFuzzingState {
|
||||
fn default() -> Self {
|
||||
CorpusFuzzingState {
|
||||
fields_fuzzed: 0,
|
||||
mode: MutatorMode::Havoc,
|
||||
targeted_field_idx: 0,
|
||||
target_total_fields: 0,
|
||||
target_total_passes: 0,
|
||||
finished_iteration: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,11 +55,6 @@ impl Default for CorpusFuzzingState {
|
|||
impl CorpusFuzzingState {
|
||||
pub fn reset(&mut self) {
|
||||
self.fields_fuzzed = 0;
|
||||
self.target_total_passes = 0;
|
||||
self.targeted_field_idx = 0;
|
||||
self.target_total_fields = 0;
|
||||
self.mode = MutatorMode::Havoc;
|
||||
self.finished_iteration = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +62,7 @@ impl CorpusFuzzingState {
|
|||
#[derive(Debug)]
|
||||
pub struct Mutator<R: Rng> {
|
||||
pub rng: R,
|
||||
flags: Vec<MutatorFlags>,
|
||||
flags: MutatorFlags,
|
||||
corpus_state: CorpusFuzzingState,
|
||||
}
|
||||
|
||||
|
@ -97,19 +70,11 @@ impl<R: Rng> Mutator<R> {
|
|||
pub fn new(rng: R) -> Mutator<R> {
|
||||
Mutator {
|
||||
rng,
|
||||
flags: Vec::new(),
|
||||
flags: MutatorFlags::default(),
|
||||
corpus_state: CorpusFuzzingState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_mode(&mut self, mode: MutatorMode) {
|
||||
self.corpus_state.mode = mode;
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> MutatorMode {
|
||||
self.corpus_state.mode
|
||||
}
|
||||
|
||||
pub fn get_corpus_state(&self) -> CorpusFuzzingState {
|
||||
self.corpus_state.clone()
|
||||
}
|
||||
|
@ -126,110 +91,6 @@ impl<R: Rng> Mutator<R> {
|
|||
T::new_fuzzed(self, None)
|
||||
}
|
||||
|
||||
/// TODO: Change function name. Mutates `mn` while taking into consideration the current mutator mode.
|
||||
///
|
||||
pub fn mutate_from_mutation_mode<T>(&mut self, mn: &mut T)
|
||||
where
|
||||
T: BitXor<Output = T>
|
||||
+ Add<Output = T>
|
||||
+ Sub<Output = T>
|
||||
+ WrappingAdd<Output = T>
|
||||
+ WrappingSub<Output = T>
|
||||
+ NumCast
|
||||
+ Bounded
|
||||
+ Copy
|
||||
+ DangerousNumber<T>
|
||||
+ std::fmt::Display,
|
||||
{
|
||||
// info!("{:?}", self.mode());
|
||||
// info!("num is: {}", mn);
|
||||
// info!("{}, {}, {}, {}", self.corpus_state.fields_fuzzed, self.corpus_state.targeted_field_idx, self.corpus_state.target_total_fields, self.corpus_state.target_total_passes);
|
||||
self.corpus_state.fields_fuzzed += 1;
|
||||
|
||||
if self.mode() != MutatorMode::Havoc && self.corpus_state.finished_iteration
|
||||
|| self.corpus_state.targeted_field_idx != self.corpus_state.fields_fuzzed - 1
|
||||
{
|
||||
return;
|
||||
}
|
||||
//println!("should be changing mode");
|
||||
|
||||
match self.mode() {
|
||||
MutatorMode::WalkingBitFlip { bits, current_idx } => {
|
||||
for i in current_idx..current_idx + bits {
|
||||
*mn = *mn ^ num::cast(1u64 << i).unwrap();
|
||||
}
|
||||
}
|
||||
MutatorMode::InterestingValues { current_idx } => {
|
||||
*mn = T::dangerous_number_at_index(current_idx as usize);
|
||||
}
|
||||
// Do nothing for havoc mode -- we let the individual mutators handle that
|
||||
MutatorMode::Havoc => {
|
||||
self.mutate(mn);
|
||||
}
|
||||
}
|
||||
|
||||
self.corpus_state.finished_iteration = true;
|
||||
self.next_mode::<T>();
|
||||
}
|
||||
|
||||
/// Manages the mutator mode state machine.
|
||||
///
|
||||
/// This will basically:
|
||||
///
|
||||
/// - Swap between the different [MutatorMode]s. This will transition from walking bit flips to dangerous numbers, to havoc mode.
|
||||
/// - For each mode, determine if there are any any other substates to exhaust (e.g. more bits to flip, more dangerous numbers to select), and update
|
||||
/// the state accordingly for the next iteration. If no other substates exist, the hard [MutatorMode] state will move to the next enum variant. Before reaching
|
||||
/// the [MutatorMode::Havoc] state, each subsequent mode will check if the last field has been mutated yet. If not, the state will reset to [MutatorMode::WalkingBitFlip]
|
||||
/// and adjust the current member index being fuzzed.
|
||||
/// - Once all members have been fuzzed in all [MutatorMode]s, the mode is set to [MutatorMode::Havoc].
|
||||
pub fn next_mode<T: Bounded + NumCast + DangerousNumber<T>>(&mut self) {
|
||||
let num_bits = (std::mem::size_of::<T>() * 8) as u8;
|
||||
//println!("previous: {:?}", self.mode());
|
||||
//println!("num bits: {}", num_bits);
|
||||
match self.mode() {
|
||||
MutatorMode::WalkingBitFlip { bits, current_idx } => {
|
||||
// current_idx + bits + 1 == num_bits
|
||||
if bits == num_bits {
|
||||
// if we are at the max bits, move on to the next state
|
||||
self.corpus_state.mode = MutatorMode::InterestingValues { current_idx: 0 };
|
||||
} else if current_idx + bits == num_bits {
|
||||
self.corpus_state.mode = MutatorMode::WalkingBitFlip {
|
||||
bits: bits + 1,
|
||||
current_idx: 0,
|
||||
};
|
||||
} else {
|
||||
self.corpus_state.mode = MutatorMode::WalkingBitFlip {
|
||||
bits,
|
||||
current_idx: current_idx + 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
MutatorMode::InterestingValues { current_idx } => {
|
||||
if (current_idx as usize) + 1 < T::dangerous_numbers_len() {
|
||||
self.corpus_state.mode = MutatorMode::InterestingValues {
|
||||
current_idx: current_idx + 1,
|
||||
};
|
||||
} else {
|
||||
self.corpus_state.targeted_field_idx += 1;
|
||||
if self.corpus_state.targeted_field_idx == self.corpus_state.target_total_fields
|
||||
{
|
||||
self.corpus_state.mode = MutatorMode::Havoc;
|
||||
} else {
|
||||
self.corpus_state.mode = MutatorMode::WalkingBitFlip {
|
||||
bits: 1,
|
||||
current_idx: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
MutatorMode::Havoc => {
|
||||
// stay in havoc mode since we've exhausted all other states
|
||||
}
|
||||
}
|
||||
|
||||
//println!("new: {:?}", self.mode());
|
||||
}
|
||||
|
||||
/// Mutates a number after randomly selecting a mutation strategy (see [MutatorOperation] for a list of strategies)
|
||||
/// If a min/max is specified then a new number in this range is chosen instead of performing
|
||||
/// a bit/arithmetic mutation
|
||||
|
@ -244,22 +105,14 @@ impl<R: Rng> Mutator<R> {
|
|||
+ WrappingAdd<Output = T>
|
||||
+ WrappingSub<Output = T>,
|
||||
{
|
||||
if self.mode() != MutatorMode::Havoc {
|
||||
panic!("Mutate called in non-havoc mode");
|
||||
}
|
||||
|
||||
// dirty but needs to be done so we can call self.gen_chance_ignore_flags
|
||||
let flags = self.flags.clone();
|
||||
for flag in flags {
|
||||
if let MutatorFlags::FuzzUpToNFields(num_fields) = flag {
|
||||
if self.corpus_state.fields_fuzzed == num_fields
|
||||
|| !self.gen_chance_ignore_flags(50.0)
|
||||
{
|
||||
return;
|
||||
} else {
|
||||
self.corpus_state.fields_fuzzed += 1;
|
||||
}
|
||||
if let Some(count) = self.flags.field_count.clone() {
|
||||
// 75% chance to ignore this field
|
||||
if self.corpus_state.fields_fuzzed == count || self.gen_chance_ignore_flags(0.75) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.corpus_state.fields_fuzzed += 1;
|
||||
}
|
||||
|
||||
let operation = MutatorOperation::new_fuzzed(self, None);
|
||||
|
@ -334,9 +187,8 @@ impl<R: Rng> Mutator<R> {
|
|||
|
||||
/// Generates a number in the range from [min, max) (**note**: non-inclusive). Panics if min >= max.
|
||||
pub fn gen_range<T, B1>(&mut self, min: B1, max: B1) -> T
|
||||
where
|
||||
T: SampleUniform + std::fmt::Display,
|
||||
B1: SampleBorrow<T>
|
||||
where T: SampleUniform + std::fmt::Display,
|
||||
B1: SampleBorrow<T>
|
||||
+ std::fmt::Display
|
||||
+ Add
|
||||
+ Mul
|
||||
|
@ -440,18 +292,10 @@ impl<R: Rng> Mutator<R> {
|
|||
num
|
||||
}
|
||||
|
||||
/// Generates the chance to mutate a field. This will always return `true` if the current mode is
|
||||
/// [MutatorMode::Havoc].
|
||||
pub fn gen_chance_to_mutate_field(&mut self, chance_percentage: f64) -> bool {
|
||||
self.mode() != MutatorMode::Havoc || !self.gen_chance(chance_percentage)
|
||||
}
|
||||
|
||||
/// Helper function for quitting the recursive mutation early if the target field has already
|
||||
/// been mutated.
|
||||
pub fn should_early_bail_mutation(&self) -> bool {
|
||||
self.mode() != MutatorMode::Havoc
|
||||
&& self.corpus_state.finished_iteration
|
||||
&& self.corpus_state.target_total_passes > 0
|
||||
self.flags.field_count.clone().map(|count| count == self.corpus_state.fields_fuzzed).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Returns a boolean value indicating whether or not the chance event occurred
|
||||
|
@ -460,14 +304,12 @@ impl<R: Rng> Mutator<R> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if chance_percentage >= 100.0 {
|
||||
if chance_percentage >= 1.0 {
|
||||
return true;
|
||||
}
|
||||
|
||||
for flag in self.flags.iter() {
|
||||
if let MutatorFlags::AllChancesSucceedOrFail(should_succeed) = flag {
|
||||
return *should_succeed;
|
||||
}
|
||||
if self.flags.all_chances_succeed {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.gen_chance_ignore_flags(chance_percentage)
|
||||
|
@ -480,65 +322,20 @@ impl<R: Rng> Mutator<R> {
|
|||
|
||||
/// Returns a boolean indicating whether or not post mutation steps should be taken
|
||||
pub fn should_fixup(&mut self) -> bool {
|
||||
self.mode() == MutatorMode::Havoc && !self.gen_chance(CHANCE_TO_IGNORE_POST_MUTATION)
|
||||
// for flag in self.flags.iter() {
|
||||
// if let MutatorFlags::ShouldAlwaysPerformPostMutation(should_perform) = flag {
|
||||
// return *should_perform;
|
||||
// }
|
||||
// }
|
||||
|
||||
// !self.gen_chance(CHANCE_TO_IGNORE_POST_MUTATION)
|
||||
self.flags.always_fixup || !self.gen_chance(CHANCE_TO_IGNORE_POST_MUTATION)
|
||||
}
|
||||
|
||||
/// Client code should call this to signal to the mutator that a new fuzzer iteration is beginning
|
||||
/// and that the mutator should reset internal state.
|
||||
pub fn begin_new_iteration(&mut self) {
|
||||
let mut set_flags = [false, false, false];
|
||||
self.flags.clear();
|
||||
let temp_fields_fuzzed = self.corpus_state.fields_fuzzed;
|
||||
self.corpus_state.fields_fuzzed = 0;
|
||||
pub fn random_flags(&mut self) {
|
||||
self.flags = MutatorFlags::default();
|
||||
|
||||
if self.corpus_state.target_total_fields == 0 {
|
||||
self.corpus_state.target_total_fields = temp_fields_fuzzed;
|
||||
|
||||
if self.corpus_state.targeted_field_idx > self.corpus_state.target_total_fields {
|
||||
panic!(
|
||||
"somehow got targeted field index {} with {} total fields",
|
||||
self.corpus_state.targeted_field_idx, self.corpus_state.target_total_fields
|
||||
);
|
||||
}
|
||||
// each flag has a 10% chance of being active
|
||||
if self.gen_chance_ignore_flags(0.10) {
|
||||
self.flags.field_count = Some(self.gen_range(1, 10));
|
||||
}
|
||||
|
||||
self.corpus_state.target_total_passes += 1;
|
||||
self.corpus_state.finished_iteration = false;
|
||||
|
||||
if self.mode() == MutatorMode::Havoc && self.corpus_state.target_total_fields > 0 {
|
||||
// only 2 flags can be concurrently set
|
||||
for _i in 0..self.gen_range(0, 2) {
|
||||
let flag_num = self.gen_range(0, 3);
|
||||
let flag = match flag_num {
|
||||
0 => MutatorFlags::FuzzUpToNFields(
|
||||
self.gen_range(1, self.corpus_state.target_total_fields + 1),
|
||||
),
|
||||
1 => MutatorFlags::ShouldAlwaysPerformPostMutation(self.gen_range(0, 2) != 0),
|
||||
2 => MutatorFlags::AllChancesSucceedOrFail(self.gen_range(0, 2) != 0),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if !set_flags[flag_num] {
|
||||
set_flags[flag_num] = true;
|
||||
self.flags.push(flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets the corpus state and current mutation mode.
|
||||
pub fn begin_new_corpus(&mut self) {
|
||||
self.corpus_state.reset();
|
||||
self.set_mode(MutatorMode::WalkingBitFlip {
|
||||
bits: 1,
|
||||
current_idx: 0,
|
||||
});
|
||||
self.flags.all_chances_succeed = self.rng.gen();
|
||||
self.flags.always_fixup = self.rng.gen();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ pub use crate::byteorder::{BigEndian, LittleEndian};
|
|||
#[doc(no_inline)]
|
||||
pub use crate::log::*;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::mutator::{Mutator, MutatorMode};
|
||||
pub use crate::mutator::{Mutator};
|
||||
#[doc(no_inline)]
|
||||
pub use crate::traits::*;
|
||||
#[doc(no_inline)]
|
||||
|
|
|
@ -103,7 +103,8 @@ fn mutatable_enum(variants: &[Variant], cont_ident: &syn::Ident) -> TokenStream
|
|||
}
|
||||
|
||||
quote! {
|
||||
if mutator.mode() == _lain::mutator::MutatorMode::Havoc {
|
||||
// 10% chance to re-generate this field
|
||||
if mutator.gen_chance(0.10) {
|
||||
*self = Self::new_fuzzed(mutator, parent_constraints);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -577,60 +577,6 @@ mod test {
|
|||
assert!(instance.post_mutation_called);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutator_switches_modes_properly() {
|
||||
let mut mutator = get_mutator();
|
||||
#[derive(Default, NewFuzzed, Mutatable, BinarySerialize, Clone)]
|
||||
struct S {
|
||||
first: u64,
|
||||
second: u8,
|
||||
}
|
||||
|
||||
let mut instance = S::new_fuzzed(&mut mutator, None);
|
||||
mutator.begin_new_corpus();
|
||||
|
||||
let mut counter = 0usize;
|
||||
loop {
|
||||
println!("{:?}", mutator.mode());
|
||||
instance.mutate(&mut mutator, None);
|
||||
mutator.begin_new_iteration();
|
||||
counter += 1;
|
||||
|
||||
match counter {
|
||||
2078 => assert_eq!(
|
||||
mutator.mode(),
|
||||
MutatorMode::WalkingBitFlip {
|
||||
bits: 63,
|
||||
current_idx: 1
|
||||
}
|
||||
),
|
||||
2079 => assert_eq!(
|
||||
mutator.mode(),
|
||||
MutatorMode::WalkingBitFlip {
|
||||
bits: 64,
|
||||
current_idx: 0
|
||||
}
|
||||
),
|
||||
2085 => assert_eq!(
|
||||
mutator.mode(),
|
||||
MutatorMode::InterestingValues { current_idx: 5 }
|
||||
),
|
||||
2100 => assert_eq!(
|
||||
mutator.mode(),
|
||||
MutatorMode::WalkingBitFlip {
|
||||
bits: 2,
|
||||
current_idx: 6
|
||||
}
|
||||
),
|
||||
2134 => {
|
||||
assert_eq!(mutator.mode(), MutatorMode::Havoc);
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_mutation() {
|
||||
// this test mostly ensures that the string generation does not panic
|
||||
|
|
Загрузка…
Ссылка в новой задаче