byte_mutator/
lib.rs

1//! # Byte Mutator
2//!
3//! `byte-mutator` is a crate for defining a set of rules by which to mutate byte arrays. It
4//! contains two main primitives: `Stage`, and `Mutator`. A `Stage` allows multiple mutations per
5//! step, and a Mutator is a small stateful object that
6//!
7//! ```
8//! ```
9use serde_derive::Deserialize;
10
11pub use crate::fuzz_config::FuzzConfig;
12pub use crate::mutators::{Mutation, MutationType};
13pub use crate::undo_buffer::UndoBuffer;
14
15pub mod fuzz_config;
16pub mod mutators;
17pub mod undo_buffer;
18
19/// Used to limit the number of iterations in a `Stage`.
20/// todo: Unused, fix
21#[derive(Clone, Debug, Deserialize)]
22pub enum Iterations {
23    /// One iteration per bit in slice
24    Bits,
25    /// One iteration per byte in slice
26    Bytes,
27    /// Goes forever
28    Unlimited,
29    /// Fixed number of iterations
30    Limited(usize),
31}
32
33/// Used to define groups of mutations, and how many mutations should be performed.
34#[derive(Clone, Debug, Deserialize)]
35pub struct Stage {
36    /// Current number of iterations.
37    /// This can start at > 0 if you want to reproduce something from an earlier run.
38    pub count: usize,
39    /// Optional max number of iterations
40    pub max: Option<usize>,
41    /// Group of mutations, all of which are performed every time.
42    pub mutations: Vec<Mutation>,
43}
44
45impl Stage {
46    pub fn new(count: usize, mutations: Vec<Mutation>, max: Option<usize>) -> Self {
47        Self {
48            count,
49            mutations,
50            max,
51        }
52    }
53
54    /// Returns whether the stage is complete
55    pub fn is_done(&self) -> bool {
56        match self.max {
57            None => false,
58            Some(n) => self.count >= n,
59        }
60    }
61
62    /// Advances the internal state of the `Stage`
63    pub fn next(&mut self) {
64        self.count += 1;
65    }
66
67    /// Add a mutation
68    pub fn add_mutation(&mut self, mutation: Mutation) {
69        self.mutations.push(mutation);
70    }
71}
72
73impl Default for Stage {
74    /// Default `Stage` with no mutations and unlimited iterations
75    fn default() -> Self {
76        Stage::new(0, vec![], None)
77    }
78}
79
80/// A defined set of stages of mutations
81#[derive(Debug, Clone)]
82pub struct ByteMutator {
83    /// Queue of outstanding stages, ordered from first to last. Drains from the front.
84    stages: Vec<Stage>,
85    /// The in-progress stage.
86    cur_stage: usize,
87}
88
89impl ByteMutator {
90    /// Create a new `ByteMutator`.
91    pub fn new() -> Self {
92        Self {
93            stages: vec![],
94            cur_stage: 0,
95        }
96    }
97
98    pub fn with_stages(mut self, stages: Vec<Stage>) -> Self {
99        self.stages = stages;
100        self
101    }
102
103    /// Creates a new `ByteMutator` and consumes the `stages` configured in `config`
104    pub fn new_from_config(config: FuzzConfig) -> Self {
105        Self {
106            stages: config.stages,
107            cur_stage: 0,
108        }
109    }
110
111    /// Number of outstanding stages
112    pub fn remaining_stages(&self) -> usize {
113        self.stages.len()
114    }
115
116    /// Add a stage
117    pub fn add_stage(&mut self, stage: Stage) {
118        self.stages.push(stage);
119    }
120
121    /// Advance the mutation one step. Resets outstanding changes, advances the stage state,
122    /// and mutates using all mutators defined in the stage.
123    /// todo: Make this an actual iterator
124    pub fn next(&mut self) {
125        let stage = match self.stages.get_mut(0) {
126            None => return, // nothing to do
127            Some(s) => s,
128        };
129
130        stage.next();
131
132        if stage.is_done() {
133            self.stages.drain(..1);
134        }
135    }
136
137    pub fn mutate(&self, bytes: &mut [u8]) {
138        let stage = match self.stages.get(0) {
139            None => return, // nothing to do
140            Some(s) => s,
141        };
142
143        for mutation in &stage.mutations {
144            match mutation.range {
145                Some((start, end)) => mutation.mutate(&mut bytes[start..end], stage.count),
146                None => mutation.mutate(bytes, stage.count),
147            };
148        }
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155    use crate::mutators::MutationType;
156
157    #[test]
158    fn mutator_stage() {
159        let mut byte_mutator = ByteMutator::new();
160
161        byte_mutator.add_stage(Stage::new(
162            0,
163            vec![Mutation {
164                range: None,
165                mutation: MutationType::BitFlipper { width: 1 },
166            }],
167            Some(10),
168        ));
169
170        assert_eq!(byte_mutator.remaining_stages(), 1);
171
172        for _ in 0..10 {
173            byte_mutator.next();
174        }
175
176        assert_eq!(byte_mutator.remaining_stages(), 0);
177    }
178}