Assign weights that control often each stream is mutated based on on the colorization rate. This avoids spending effort on mutating streams that have little to zero impact on the path of the input.
(
fuzzer: &mut Fuzzer,
id: usize,
streams: &[(StreamKey, usize)],
)
| 172 | /// This avoids spending effort on mutating streams that have little to zero impact on the path of |
| 173 | /// the input. |
| 174 | pub(crate) fn get_stream_weights( |
| 175 | fuzzer: &mut Fuzzer, |
| 176 | id: usize, |
| 177 | streams: &[(StreamKey, usize)], |
| 178 | ) -> rand_distr::WeightedAliasIndex<f64> { |
| 179 | // Currently even streams that are impactful often have a very high colorization rate, this can |
| 180 | // occur when a 32-bit read performed but only the low 8 are used. Currently we only adjust |
| 181 | // the mutation probability of fully colorized streams. |
| 182 | const COLORIZATION_THRESHOLD: f64 = 0.99; |
| 183 | |
| 184 | let color = |
| 185 | fuzzer.corpus[id].stage_data::<hashbrown::HashMap<StreamKey, usize>>(Stage::Colorization); |
| 186 | let colorization_rates: Vec<_> = streams |
| 187 | .iter() |
| 188 | .map(|(key, len)| { |
| 189 | color |
| 190 | .get(key) |
| 191 | .map_or(1.0, |x| *x as f64 / *len.min(&fuzzer.features.max_i2s_bytes) as f64) |
| 192 | }) |
| 193 | .collect(); |
| 194 | let weights = colorization_rates |
| 195 | .into_iter() |
| 196 | .map(|x| if x > COLORIZATION_THRESHOLD { 0.01 } else { 1.0 }) |
| 197 | .collect(); |
| 198 | |
| 199 | // We could adjust the weights such that streams with higher colorization rates are |
| 200 | // mutated more often, however because of oversized reads, interesting data often has a higher |
| 201 | // than expected colorization rate. |
| 202 | // |
| 203 | // let min_rate = *colorization_rates.iter().min_by(|a, b| a.total_cmp(b)).unwrap_or(&0.0); |
| 204 | // let weights = colorization_rates |
| 205 | // .into_iter() |
| 206 | // .map(|x| (1.0 - (x - min_rate) / (1.0 - min_rate)).max(0.01)) |
| 207 | // .collect(); |
| 208 | |
| 209 | rand_distr::WeightedAliasIndex::new(weights).unwrap() |
| 210 | } |
| 211 | |
| 212 | pub fn rand_pow2<R: Rng>(mut rng: R, log2_max: u32) -> u64 { |
| 213 | 2_f32.powf(1.0 + (rng.gen::<f32>() * (log2_max as f32 - 1.0))).floor() as u64 |