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>
|
/// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user