Fix mutator slowdown (#1138)

* perf stat

* fix except swap

* swap

* fix

* reveral-based byte swap

* Revert "reveral-based byte swap"

This reverts commit 2bc9609ece47fd4e8f6d96862f8ad3fb77f11aec.

* no introspection

* clp fmt

* change rand_range to have at least 1 length

* don't use modulo

---------

Co-authored-by: Addison Crump <addison.crump@cispa.de>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
Dongjia "toka" Zhang 2023-03-16 23:58:03 +09:00 committed by GitHub
parent 3c331e5a9b
commit 08fe6ab791

View File

@ -63,10 +63,13 @@ pub fn buffer_set<T: Clone>(data: &mut [T], from: usize, len: usize, val: T) {
/// This problem corresponds to: <https://oeis.org/A059036> /// This problem corresponds to: <https://oeis.org/A059036>
#[inline] #[inline]
pub fn rand_range<S: HasRand>(state: &mut S, upper: usize, max_len: usize) -> Range<usize> { pub fn rand_range<S: HasRand>(state: &mut S, upper: usize, max_len: usize) -> Range<usize> {
let len = state.rand_mut().next() as usize % max_len + 1; let len = 1 + state.rand_mut().below(max_len as u64) as usize;
let offset2 = state.rand_mut().next() as usize % (upper + len); // sample from [1..upper + len]
let mut offset2 = 1 + state.rand_mut().below((upper + len - 1) as u64) as usize;
let offset1 = offset2.saturating_sub(len); let offset1 = offset2.saturating_sub(len);
let offset2 = offset2.clamp(0, upper); if offset2 > upper {
offset2 = upper;
}
offset1..offset2 offset1..offset2
} }
@ -490,9 +493,6 @@ where
} }
let range = rand_range(state, size, size); let range = rand_range(state, size, size);
if range.is_empty() {
return Ok(MutationResult::Skipped);
}
input.bytes_mut().drain(range); input.bytes_mut().drain(range);
@ -535,17 +535,15 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
let mut range = rand_range(state, size, min(max_size - size, 16)); let range = rand_range(state, size, min(16, max_size - size));
if range.is_empty() {
return Ok(MutationResult::Skipped);
}
let new_size = range.len() + size;
let mut target = size; input.bytes_mut().resize(size + range.len(), 0);
core::mem::swap(&mut target, &mut range.end); buffer_self_copy(
input.bytes_mut(),
input.bytes_mut().resize(new_size, 0); range.start,
input.bytes_mut().copy_within(range, target); range.start + range.len(),
size - range.start,
);
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
@ -586,14 +584,22 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
let amount = 1 + state.rand_mut().below(min(max_size - size, 16) as u64) as usize; let mut amount = 1 + state.rand_mut().below(16) as usize;
let offset = state.rand_mut().below(size as u64 + 1) as usize; let offset = state.rand_mut().below(size as u64 + 1) as usize;
if size + amount > max_size {
if max_size > size {
amount = max_size - size;
} else {
return Ok(MutationResult::Skipped);
}
}
let val = input.bytes()[state.rand_mut().below(size as u64) as usize]; let val = input.bytes()[state.rand_mut().below(size as u64) as usize];
input input.bytes_mut().resize(size + amount, 0);
.bytes_mut() buffer_self_copy(input.bytes_mut(), offset, offset + amount, size - offset);
.splice(offset..offset, core::iter::repeat(val).take(amount)); buffer_set(input.bytes_mut(), offset, amount, val);
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
@ -634,14 +640,22 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
let amount = 1 + state.rand_mut().below(min(max_size - size, 16) as u64) as usize; let mut amount = 1 + state.rand_mut().below(16) as usize;
let offset = state.rand_mut().below(size as u64 + 1) as usize; let offset = state.rand_mut().below(size as u64 + 1) as usize;
if size + amount > max_size {
if max_size > size {
amount = max_size - size;
} else {
return Ok(MutationResult::Skipped);
}
}
let val = state.rand_mut().next() as u8; let val = state.rand_mut().next() as u8;
input input.bytes_mut().resize(size + amount, 0);
.bytes_mut() buffer_self_copy(input.bytes_mut(), offset, offset + amount, size - offset);
.splice(offset..offset, core::iter::repeat(val).take(amount)); buffer_set(input.bytes_mut(), offset, amount, val);
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
@ -681,15 +695,10 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
let range = rand_range(state, size, min(size, 16)); let range = rand_range(state, size, min(size, 16));
if range.is_empty() {
return Ok(MutationResult::Skipped);
}
let val = *state.rand_mut().choose(input.bytes()); let val = *state.rand_mut().choose(input.bytes());
let quantity = range.len(); let quantity = range.len();
input buffer_set(input.bytes_mut(), range.start, quantity, val);
.bytes_mut()
.splice(range, core::iter::repeat(val).take(quantity));
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
@ -729,15 +738,10 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
let range = rand_range(state, size, min(size, 16)); let range = rand_range(state, size, min(size, 16));
if range.is_empty() {
return Ok(MutationResult::Skipped);
}
let val = state.rand_mut().next() as u8; let val = state.rand_mut().next() as u8;
let quantity = range.len(); let quantity = range.len();
input buffer_set(input.bytes_mut(), range.start, quantity, val);
.bytes_mut()
.splice(range, core::iter::repeat(val).take(quantity));
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
@ -780,7 +784,7 @@ where
let target = state.rand_mut().below(size as u64) as usize; let target = state.rand_mut().below(size as u64) as usize;
let range = rand_range(state, size, size - target); let range = rand_range(state, size, size - target);
input.bytes_mut().copy_within(range, target); buffer_self_copy(input.bytes_mut(), range.start, target, range.len());
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
@ -818,22 +822,32 @@ where
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
if size <= 1 || size == state.max_size() { if size <= 1 || size >= state.max_size() {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
let target = state.rand_mut().below(size as u64) as usize; let target = state.rand_mut().below(size as u64) as usize;
// make sure that the sampled range is both in bounds and of an acceptable size // make sure that the sampled range is both in bounds and of an acceptable size
let max_insert_len = min(size - target, state.max_size() - size); let max_insert_len = min(size - target, state.max_size() - size);
let range = rand_range(state, size, max_insert_len); let range = rand_range(state, size, min(16, max_insert_len));
self.tmp_buf.clear(); input.bytes_mut().resize(size + range.len(), 0);
self.tmp_buf.extend(input.bytes()[range].iter().copied()); self.tmp_buf.resize(range.len(), 0);
buffer_copy(
input &mut self.tmp_buf,
.bytes_mut() input.bytes(),
.splice(target..target, self.tmp_buf.drain(..)); range.start,
0,
range.len(),
);
buffer_self_copy(
input.bytes_mut(),
target,
target + range.len(),
size - target,
);
buffer_copy(input.bytes_mut(), &self.tmp_buf, 0, target, range.len());
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -858,6 +872,7 @@ pub struct BytesSwapMutator {
tmp_buf: Vec<u8>, tmp_buf: Vec<u8>,
} }
#[allow(clippy::too_many_lines)]
impl<I, S> Mutator<I, S> for BytesSwapMutator impl<I, S> Mutator<I, S> for BytesSwapMutator
where where
S: HasRand, S: HasRand,
@ -874,31 +889,166 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
self.tmp_buf.clear();
let first = rand_range(state, size, size); let first = rand_range(state, size, size);
if state.rand_mut().next() & 1 == 0 && first.start != 0 { if state.rand_mut().next() & 1 == 0 && first.start != 0 {
// The second range comes before first.
let second = rand_range(state, first.start, first.start); let second = rand_range(state, first.start, first.start);
self.tmp_buf.extend(input.bytes_mut().drain(first.clone())); self.tmp_buf.resize(first.len(), 0);
self.tmp_buf // If range first is larger
.extend(input.bytes()[second.clone()].iter().copied()); if first.len() >= second.len() {
input let diff_in_size = first.len() - second.len();
.bytes_mut()
.splice(first.start..first.start, self.tmp_buf.drain(first.len()..)); // copy first range to tmp
input.bytes_mut().splice(second, self.tmp_buf.drain(..)); buffer_copy(
&mut self.tmp_buf,
input.bytes(),
first.start,
0,
first.len(),
);
// adjust second.end..first.start, move them by diff_in_size to the right
buffer_self_copy(
input.bytes_mut(),
second.end,
second.end + diff_in_size,
first.start - second.end,
);
// copy second to where first was
buffer_self_copy(
input.bytes_mut(),
second.start,
first.start + diff_in_size,
second.len(),
);
// copy first back
buffer_copy(
input.bytes_mut(),
&self.tmp_buf,
0,
second.start,
first.len(),
);
} else {
let diff_in_size = second.len() - first.len();
// copy first range to tmp
buffer_copy(
&mut self.tmp_buf,
input.bytes(),
first.start,
0,
first.len(),
);
// adjust second.end..first.start, move them by diff_in_size to the left
buffer_self_copy(
input.bytes_mut(),
second.end,
second.end - diff_in_size,
first.start - second.end,
);
// copy second to where first was
buffer_self_copy(
input.bytes_mut(),
second.start,
first.start - diff_in_size,
second.len(),
);
// copy first back
buffer_copy(
input.bytes_mut(),
&self.tmp_buf,
0,
second.start,
first.len(),
);
}
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} else if first.end != size { } else if first.end != size {
// The first range comes before the second range
let mut second = rand_range(state, size - first.end, size - first.end); let mut second = rand_range(state, size - first.end, size - first.end);
second.start += first.end; second.start += first.end;
second.end += first.end; second.end += first.end;
self.tmp_buf.extend(input.bytes_mut().drain(second.clone()));
self.tmp_buf self.tmp_buf.resize(second.len(), 0);
.extend(input.bytes()[first.clone()].iter().copied()); if second.len() >= first.len() {
input.bytes_mut().splice( let diff_in_size = second.len() - first.len();
second.start..second.start, // copy second range to tmp
self.tmp_buf.drain(second.len()..), buffer_copy(
); &mut self.tmp_buf,
input.bytes_mut().splice(first, self.tmp_buf.drain(..)); input.bytes(),
second.start,
0,
second.len(),
);
// adjust first.end..second.start, move them by diff_in_size to the right
buffer_self_copy(
input.bytes_mut(),
first.end,
first.end + diff_in_size,
second.start - first.end,
);
// copy first to where second was
buffer_self_copy(
input.bytes_mut(),
first.start,
second.start + diff_in_size,
first.len(),
);
// copy second back
buffer_copy(
input.bytes_mut(),
&self.tmp_buf,
0,
first.start,
second.len(),
);
} else {
let diff_in_size = first.len() - second.len();
// copy second range to tmp
buffer_copy(
&mut self.tmp_buf,
input.bytes(),
second.start,
0,
second.len(),
);
// adjust first.end..second.start, move them by diff_in_size to the left
buffer_self_copy(
input.bytes_mut(),
first.end,
first.end - diff_in_size,
second.start - first.end,
);
// copy first to where second was
buffer_self_copy(
input.bytes_mut(),
first.start,
second.start - diff_in_size,
first.len(),
);
// copy second back
buffer_copy(
input.bytes_mut(),
&self.tmp_buf,
0,
first.start,
second.len(),
);
}
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} else { } else {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
@ -967,10 +1117,20 @@ where
let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
let other = other_testcase.load_input()?; let other = other_testcase.load_input()?;
input input.bytes_mut().resize(size + range.len(), 0);
.bytes_mut() buffer_self_copy(
.splice(target..target, other.bytes()[range].iter().copied()); input.bytes_mut(),
target,
target + range.len(),
size - target,
);
buffer_copy(
input.bytes_mut(),
other.bytes(),
range.start,
target,
range.len(),
);
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -1034,11 +1194,13 @@ where
let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
let other = other_testcase.load_input()?; let other = other_testcase.load_input()?;
input.bytes_mut().splice( buffer_copy(
target..(target + range.len()), input.bytes_mut(),
other.bytes()[range].iter().copied(), other.bytes(),
range.start,
target,
range.len(),
); );
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }