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:
parent
3c331e5a9b
commit
08fe6ab791
@ -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>
|
||||
#[inline]
|
||||
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 offset2 = state.rand_mut().next() as usize % (upper + len);
|
||||
let len = 1 + state.rand_mut().below(max_len as u64) as usize;
|
||||
// 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 offset2 = offset2.clamp(0, upper);
|
||||
if offset2 > upper {
|
||||
offset2 = upper;
|
||||
}
|
||||
|
||||
offset1..offset2
|
||||
}
|
||||
@ -490,9 +493,6 @@ where
|
||||
}
|
||||
|
||||
let range = rand_range(state, size, size);
|
||||
if range.is_empty() {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
input.bytes_mut().drain(range);
|
||||
|
||||
@ -535,17 +535,15 @@ where
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
let mut range = rand_range(state, size, min(max_size - size, 16));
|
||||
if range.is_empty() {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
let new_size = range.len() + size;
|
||||
let range = rand_range(state, size, min(16, max_size - size));
|
||||
|
||||
let mut target = size;
|
||||
core::mem::swap(&mut target, &mut range.end);
|
||||
|
||||
input.bytes_mut().resize(new_size, 0);
|
||||
input.bytes_mut().copy_within(range, target);
|
||||
input.bytes_mut().resize(size + range.len(), 0);
|
||||
buffer_self_copy(
|
||||
input.bytes_mut(),
|
||||
range.start,
|
||||
range.start + range.len(),
|
||||
size - range.start,
|
||||
);
|
||||
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
@ -586,14 +584,22 @@ where
|
||||
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;
|
||||
|
||||
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];
|
||||
|
||||
input
|
||||
.bytes_mut()
|
||||
.splice(offset..offset, core::iter::repeat(val).take(amount));
|
||||
input.bytes_mut().resize(size + amount, 0);
|
||||
buffer_self_copy(input.bytes_mut(), offset, offset + amount, size - offset);
|
||||
buffer_set(input.bytes_mut(), offset, amount, val);
|
||||
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
@ -634,14 +640,22 @@ where
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
input
|
||||
.bytes_mut()
|
||||
.splice(offset..offset, core::iter::repeat(val).take(amount));
|
||||
input.bytes_mut().resize(size + amount, 0);
|
||||
buffer_self_copy(input.bytes_mut(), offset, offset + amount, size - offset);
|
||||
buffer_set(input.bytes_mut(), offset, amount, val);
|
||||
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
@ -681,15 +695,10 @@ where
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
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 quantity = range.len();
|
||||
input
|
||||
.bytes_mut()
|
||||
.splice(range, core::iter::repeat(val).take(quantity));
|
||||
buffer_set(input.bytes_mut(), range.start, quantity, val);
|
||||
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
@ -729,15 +738,10 @@ where
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
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 quantity = range.len();
|
||||
input
|
||||
.bytes_mut()
|
||||
.splice(range, core::iter::repeat(val).take(quantity));
|
||||
buffer_set(input.bytes_mut(), range.start, quantity, val);
|
||||
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
@ -780,7 +784,7 @@ where
|
||||
let target = state.rand_mut().below(size as u64) as usize;
|
||||
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)
|
||||
}
|
||||
@ -818,22 +822,32 @@ where
|
||||
_stage_idx: i32,
|
||||
) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
if size <= 1 || size == state.max_size() {
|
||||
if size <= 1 || size >= state.max_size() {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
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
|
||||
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();
|
||||
self.tmp_buf.extend(input.bytes()[range].iter().copied());
|
||||
|
||||
input
|
||||
.bytes_mut()
|
||||
.splice(target..target, self.tmp_buf.drain(..));
|
||||
input.bytes_mut().resize(size + range.len(), 0);
|
||||
self.tmp_buf.resize(range.len(), 0);
|
||||
buffer_copy(
|
||||
&mut self.tmp_buf,
|
||||
input.bytes(),
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -858,6 +872,7 @@ pub struct BytesSwapMutator {
|
||||
tmp_buf: Vec<u8>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
impl<I, S> Mutator<I, S> for BytesSwapMutator
|
||||
where
|
||||
S: HasRand,
|
||||
@ -874,31 +889,166 @@ where
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
self.tmp_buf.clear();
|
||||
|
||||
let first = rand_range(state, size, size);
|
||||
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);
|
||||
self.tmp_buf.extend(input.bytes_mut().drain(first.clone()));
|
||||
self.tmp_buf
|
||||
.extend(input.bytes()[second.clone()].iter().copied());
|
||||
input
|
||||
.bytes_mut()
|
||||
.splice(first.start..first.start, self.tmp_buf.drain(first.len()..));
|
||||
input.bytes_mut().splice(second, self.tmp_buf.drain(..));
|
||||
self.tmp_buf.resize(first.len(), 0);
|
||||
// If range first is larger
|
||||
if first.len() >= second.len() {
|
||||
let diff_in_size = first.len() - second.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 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)
|
||||
} 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);
|
||||
second.start += first.end;
|
||||
second.end += first.end;
|
||||
self.tmp_buf.extend(input.bytes_mut().drain(second.clone()));
|
||||
self.tmp_buf
|
||||
.extend(input.bytes()[first.clone()].iter().copied());
|
||||
input.bytes_mut().splice(
|
||||
second.start..second.start,
|
||||
self.tmp_buf.drain(second.len()..),
|
||||
);
|
||||
input.bytes_mut().splice(first, self.tmp_buf.drain(..));
|
||||
|
||||
self.tmp_buf.resize(second.len(), 0);
|
||||
if second.len() >= first.len() {
|
||||
let diff_in_size = second.len() - first.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 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)
|
||||
} else {
|
||||
Ok(MutationResult::Skipped)
|
||||
@ -967,10 +1117,20 @@ where
|
||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||
let other = other_testcase.load_input()?;
|
||||
|
||||
input
|
||||
.bytes_mut()
|
||||
.splice(target..target, other.bytes()[range].iter().copied());
|
||||
|
||||
input.bytes_mut().resize(size + range.len(), 0);
|
||||
buffer_self_copy(
|
||||
input.bytes_mut(),
|
||||
target,
|
||||
target + range.len(),
|
||||
size - target,
|
||||
);
|
||||
buffer_copy(
|
||||
input.bytes_mut(),
|
||||
other.bytes(),
|
||||
range.start,
|
||||
target,
|
||||
range.len(),
|
||||
);
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
}
|
||||
@ -1034,11 +1194,13 @@ where
|
||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||
let other = other_testcase.load_input()?;
|
||||
|
||||
input.bytes_mut().splice(
|
||||
target..(target + range.len()),
|
||||
other.bytes()[range].iter().copied(),
|
||||
buffer_copy(
|
||||
input.bytes_mut(),
|
||||
other.bytes(),
|
||||
range.start,
|
||||
target,
|
||||
range.len(),
|
||||
);
|
||||
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user