new Rand method: choose. fixes #117 (#118)

The choose method takes an ExactSizeIterator and returns a randomly
chosen item from it. Using this method prevents chosing items with an
incorrect upper_bound on the index.

Various macros help with defining and implementing repetitive mutation
strategies.
This commit is contained in:
Evan Richter 2021-05-22 04:51:24 -05:00 committed by GitHub
parent cbec59bea8
commit e65a2f9550
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 183 additions and 506 deletions

View File

@ -49,6 +49,29 @@ pub trait Rand: Debug + Serialize + DeserializeOwned {
debug_assert!(lower_bound_incl <= upper_bound_incl); debug_assert!(lower_bound_incl <= upper_bound_incl);
lower_bound_incl + self.below(upper_bound_incl - lower_bound_incl + 1) lower_bound_incl + self.below(upper_bound_incl - lower_bound_incl + 1)
} }
/// Choose an item at random from the given iterator, sampling uniformly.
///
/// Note: the runtime cost is bound by the iterator's [`nth`][`Iterator::nth`] implementation
/// * For `Vec`, slice, array, this is O(1)
/// * For `HashMap`, `HashSet`, this is O(n)
fn choose<I, E, T>(&mut self, from: I) -> T
where
I: IntoIterator<Item = T, IntoIter = E>,
E: ExactSizeIterator + Iterator<Item = T>,
{
// create iterator
let mut iter = from.into_iter();
// make sure there is something to choose from
debug_assert!(iter.len() > 0, "choosing from an empty iterator");
// pick a random, valid index
let index = self.below(iter.len() as u64) as usize;
// return the item chosen
iter.nth(index).unwrap()
}
} }
/// Has a Rand field, that can be used to get random values /// Has a Rand field, that can be used to get random values

View File

@ -86,9 +86,7 @@ where
size = 1; size = 1;
} }
let printables = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \t\n!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".as_bytes(); let printables = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \t\n!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".as_bytes();
let random_bytes: Vec<u8> = (0..size) let random_bytes: Vec<u8> = (0..size).map(|_| *rand.choose(printables)).collect();
.map(|_| printables[rand.below(printables.len() as u64) as usize])
.collect();
Ok(BytesInput::new(random_bytes)) Ok(BytesInput::new(random_bytes))
} }

View File

@ -117,11 +117,9 @@ where
if input.bytes().is_empty() { if input.bytes().is_empty() {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
} else { } else {
let bit = state.rand_mut().below((input.bytes().len() << 3) as u64) as usize; let bit = 1 << state.rand_mut().choose(0..8);
unsafe { let byte = state.rand_mut().choose(input.bytes_mut());
// Moar speed, no bound check *byte ^= bit;
*input.bytes_mut().get_unchecked_mut(bit >> 3) ^= (128u8 >> (bit & 7)) as u8;
}
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -179,11 +177,7 @@ where
if input.bytes().is_empty() { if input.bytes().is_empty() {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
} else { } else {
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; *state.rand_mut().choose(input.bytes_mut()) ^= 0xff;
unsafe {
// Moar speed, no bound check
*input.bytes_mut().get_unchecked_mut(idx) ^= 0xff;
}
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -241,12 +235,8 @@ where
if input.bytes().is_empty() { if input.bytes().is_empty() {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
} else { } else {
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; let byte = state.rand_mut().choose(input.bytes_mut());
unsafe { *byte = byte.wrapping_add(1);
// Moar speed, no bound check
let ptr = input.bytes_mut().get_unchecked_mut(idx);
*ptr = (*ptr).wrapping_add(1);
}
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -304,12 +294,8 @@ where
if input.bytes().is_empty() { if input.bytes().is_empty() {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
} else { } else {
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; let byte = state.rand_mut().choose(input.bytes_mut());
unsafe { *byte = byte.wrapping_sub(1);
// Moar speed, no bound check
let ptr = input.bytes_mut().get_unchecked_mut(idx);
*ptr = (*ptr).wrapping_sub(1);
}
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -367,11 +353,8 @@ where
if input.bytes().is_empty() { if input.bytes().is_empty() {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
} else { } else {
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; let byte = state.rand_mut().choose(input.bytes_mut());
unsafe { *byte = !*byte;
// Moar speed, no bound check
*input.bytes_mut().get_unchecked_mut(idx) = !(*input.bytes().get_unchecked(idx));
}
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -429,11 +412,8 @@ where
if input.bytes().is_empty() { if input.bytes().is_empty() {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
} else { } else {
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; let byte = state.rand_mut().choose(input.bytes_mut());
unsafe { *byte = state.rand_mut().next() as u8;
// Moar speed, no bound check
*input.bytes_mut().get_unchecked_mut(idx) = state.rand_mut().below(256) as u8;
}
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -465,488 +445,168 @@ where
} }
} }
/// Byte add mutation for inputs with a bytes vector // Helper macro that defines the arithmetic addition/subtraction mutations where random slices
#[derive(Default)] // within the input are treated as u8, u16, u32, or u64, then mutated in place.
pub struct ByteAddMutator<I, R, S> macro_rules! add_mutator_impl {
where ($name: ident, $size: ty) => {
I: Input + HasBytesVec, /// Adds or subtracts a random value up to `ARITH_MAX` to a [`<$size>`] at a random place in the [`Vec`], in random byte order.
S: HasRand<R>, #[derive(Default)]
R: Rand, pub struct $name<I, R, S>
{ where
phantom: PhantomData<(I, R, S)>, I: Input + HasBytesVec,
} S: HasRand<R>,
R: Rand,
{
phantom: PhantomData<(I, R, S)>,
}
impl<I, R, S> Mutator<I, S> for ByteAddMutator<I, R, S> impl<I, R, S> Mutator<I, S> for $name<I, R, S>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().len() < size_of::<$size>() {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
} else { } else {
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; // choose a random window of bytes (windows overlap) and convert to $size
unsafe { let (index, bytes) = state
// Moar speed, no bound check .rand_mut()
let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut u8; .choose(input.bytes().windows(size_of::<$size>()).enumerate());
let num = 1 + state.rand_mut().below(ARITH_MAX) as u8; let val = <$size>::from_ne_bytes(bytes.try_into().unwrap());
match state.rand_mut().below(2) {
0 => *ptr = (*ptr).wrapping_add(num), // mutate
_ => *ptr = (*ptr).wrapping_sub(num), let num = 1 + state.rand_mut().below(ARITH_MAX) as $size;
}; let new_val = match state.rand_mut().below(4) {
0 => val.wrapping_add(num),
1 => val.wrapping_sub(num),
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
};
// set bytes to mutated value
let new_bytes = &mut input.bytes_mut()[index..index + size_of::<$size>()];
new_bytes.copy_from_slice(&new_val.to_ne_bytes());
Ok(MutationResult::Mutated)
}
} }
Ok(MutationResult::Mutated)
} }
}
}
impl<I, R, S> Named for ByteAddMutator<I, R, S> impl<I, R, S> Named for $name<I, R, S>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
fn name(&self) -> &str { fn name(&self) -> &str {
"ByteAddMutator" stringify!($name)
}
}
impl<I, R, S> ByteAddMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
/// Creates a new [`ByteAddMutator`].
#[must_use]
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/// Word add mutation for inputs with a bytes vector
/// adds or subtracts a random value up to [`ARITH_MAX`] to a [`u16`] at a random place in the [`Vec`].
#[derive(Default)]
pub struct WordAddMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
phantom: PhantomData<(I, R, S)>,
}
impl<I, R, S> Mutator<I, S> for WordAddMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().len() < size_of::<u16>() {
Ok(MutationResult::Skipped)
} else {
let bytes = input.bytes_mut();
let idx = state
.rand_mut()
.below((bytes.len() - size_of::<u16>() + 1) as u64) as usize;
let val = u16::from_ne_bytes(bytes[idx..idx + size_of::<u16>()].try_into().unwrap());
let num = 1 + state.rand_mut().below(ARITH_MAX) as u16;
let new_bytes = match state.rand_mut().below(4) {
0 => val.wrapping_add(num),
1 => val.wrapping_sub(num),
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
} }
.to_ne_bytes();
bytes[idx..idx + size_of::<u16>()].copy_from_slice(&new_bytes);
Ok(MutationResult::Mutated)
} }
}
}
impl<I, R, S> Named for WordAddMutator<I, R, S> impl<I, R, S> $name<I, R, S>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
fn name(&self) -> &str { /// Creates a new [`$name`].
"WordAddMutator" #[must_use]
} pub fn new() -> Self {
} Self {
phantom: PhantomData,
impl<I, R, S> WordAddMutator<I, R, S> }
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
/// Creates a new [`WordAddMutator`].
#[must_use]
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/// Dword add mutation for inputs with a bytes vector.
/// Adds a random value up to `ARITH_MAX` to a [`u32`] at a random place in the [`Vec`], in random byte order.
#[derive(Default)]
pub struct DwordAddMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
phantom: PhantomData<(I, R, S)>,
}
impl<I, R, S> Mutator<I, S> for DwordAddMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().len() < size_of::<u32>() {
Ok(MutationResult::Skipped)
} else {
let bytes = input.bytes_mut();
let idx = state
.rand_mut()
.below((bytes.len() - size_of::<u32>() + 1) as u64) as usize;
let val = u32::from_ne_bytes(bytes[idx..idx + size_of::<u32>()].try_into().unwrap());
let num = 1 + state.rand_mut().below(ARITH_MAX) as u32;
let new_bytes = match state.rand_mut().below(4) {
0 => val.wrapping_add(num),
1 => val.wrapping_sub(num),
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
} }
.to_ne_bytes();
bytes[idx..idx + size_of::<u32>()].copy_from_slice(&new_bytes);
Ok(MutationResult::Mutated)
} }
} };
} }
impl<I, R, S> Named for DwordAddMutator<I, R, S> add_mutator_impl!(ByteAddMutator, u8);
where add_mutator_impl!(WordAddMutator, u16);
I: Input + HasBytesVec, add_mutator_impl!(DwordAddMutator, u32);
S: HasRand<R>, add_mutator_impl!(QwordAddMutator, u64);
R: Rand,
{
fn name(&self) -> &str {
"DwordAddMutator"
}
}
impl<I, R, S> DwordAddMutator<I, R, S> ///////////////////////////
where
I: Input + HasBytesVec, macro_rules! interesting_mutator_impl {
S: HasRand<R>, ($name: ident, $size: ty, $interesting: ident) => {
R: Rand, /// Inserts an interesting value at a random place in the input vector
{ #[derive(Default)]
/// Creates a new [`DwordAddMutator`]. pub struct $name<I, R, S>
#[must_use] where
pub fn new() -> Self { I: Input + HasBytesVec,
Self { S: HasRand<R>,
phantom: PhantomData, R: Rand,
{
phantom: PhantomData<(I, R, S)>,
} }
}
}
/// Qword add mutation for inputs with a bytes vector impl<I, R, S> Mutator<I, S> for $name<I, R, S>
#[derive(Default)] where
pub struct QwordAddMutator<I, R, S> I: Input + HasBytesVec,
where S: HasRand<R>,
I: Input + HasBytesVec, R: Rand,
S: HasRand<R>, {
R: Rand, #[allow(clippy::cast_sign_loss)]
{ fn mutate(
phantom: PhantomData<(I, R, S)>, &mut self,
} state: &mut S,
input: &mut I,
impl<I, R, S> Mutator<I, S> for QwordAddMutator<I, R, S> _stage_idx: i32,
where ) -> Result<MutationResult, Error> {
I: Input + HasBytesVec, if input.bytes().len() < size_of::<$size>() {
S: HasRand<R>, Ok(MutationResult::Skipped)
R: Rand, } else {
{ let bytes = input.bytes_mut();
fn mutate( let upper_bound = (bytes.len() + 1 - size_of::<$size>()) as u64;
&mut self, let idx = state.rand_mut().below(upper_bound) as usize;
state: &mut S, let val = *state.rand_mut().choose(&$interesting) as $size;
input: &mut I, let new_bytes = match state.rand_mut().choose(&[0, 1]) {
_stage_idx: i32, 0 => val.to_be_bytes(),
) -> Result<MutationResult, Error> { _ => val.to_le_bytes(),
if input.bytes().len() < 8 { };
Ok(MutationResult::Skipped) bytes[idx..idx + size_of::<$size>()].copy_from_slice(&new_bytes);
} else { Ok(MutationResult::Mutated)
let bytes = input.bytes_mut(); }
let idx = state
.rand_mut()
.below((bytes.len() - size_of::<u64>() + 1) as u64) as usize;
let val = u64::from_ne_bytes(bytes[idx..idx + size_of::<u64>()].try_into().unwrap());
let num = 1 + state.rand_mut().below(ARITH_MAX) as u64;
let new_bytes = match state.rand_mut().below(4) {
0 => val.wrapping_add(num),
1 => val.wrapping_sub(num),
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
} }
.to_ne_bytes();
bytes[idx..idx + size_of::<u64>()].copy_from_slice(&new_bytes);
Ok(MutationResult::Mutated)
} }
}
}
impl<I, R, S> Named for QwordAddMutator<I, R, S> impl<I, R, S> Named for $name<I, R, S>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
fn name(&self) -> &str { fn name(&self) -> &str {
"QwordAddMutator" stringify!($name)
}
}
impl<I, R, S> QwordAddMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
/// Creates a new [`QwordAddMutator`].
#[must_use]
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/// Byte interesting mutation for inputs with a bytes vector
#[derive(Default)]
pub struct ByteInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
phantom: PhantomData<(I, R, S)>,
}
impl<I, R, S> Mutator<I, S> for ByteInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
#[allow(clippy::cast_sign_loss)]
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize;
let val =
INTERESTING_8[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u8;
unsafe {
// Moar speed, no bound check
*input.bytes_mut().get_unchecked_mut(idx) = val;
} }
Ok(MutationResult::Mutated)
} }
}
}
impl<I, R, S> Named for ByteInterestingMutator<I, R, S> impl<I, R, S> $name<I, R, S>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
fn name(&self) -> &str { /// Creates a new [`$name`].
"ByteInterestingMutator" #[must_use]
} pub fn new() -> Self {
} Self {
phantom: PhantomData,
impl<I, R, S> ByteInterestingMutator<I, R, S> }
where }
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
/// Creates a new [`ByteInterestingMutator`].
#[must_use]
pub fn new() -> Self {
Self {
phantom: PhantomData,
} }
} };
} }
/// Word interesting mutation for inputs with a bytes vector interesting_mutator_impl!(ByteInterestingMutator, u8, INTERESTING_8);
#[derive(Default)] interesting_mutator_impl!(WordInterestingMutator, u16, INTERESTING_16);
pub struct WordInterestingMutator<I, R, S> interesting_mutator_impl!(DwordInterestingMutator, u32, INTERESTING_32);
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
phantom: PhantomData<(I, R, S)>,
}
impl<I, R, S> Mutator<I, S> for WordInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
#[allow(clippy::cast_sign_loss)]
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().len() < 2 {
Ok(MutationResult::Skipped)
} else {
let bytes = input.bytes_mut();
let idx = state.rand_mut().below(bytes.len() as u64 - 1) as usize;
let val =
INTERESTING_16[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u16;
let new_bytes = if state.rand_mut().below(2) == 0 {
val.to_be_bytes()
} else {
val.to_le_bytes()
};
bytes[idx..idx + size_of::<u16>()].copy_from_slice(&new_bytes);
Ok(MutationResult::Mutated)
}
}
}
impl<I, R, S> Named for WordInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
fn name(&self) -> &str {
"WordInterestingMutator"
}
}
impl<I, R, S> WordInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
/// Creates a new [`WordInterestingMutator`].
#[must_use]
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/// Dword interesting mutation for inputs with a bytes vector
#[derive(Default)]
pub struct DwordInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
phantom: PhantomData<(I, R, S)>,
}
impl<I, R, S> Mutator<I, S> for DwordInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
#[allow(clippy::cast_sign_loss)]
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().len() < 4 {
Ok(MutationResult::Skipped)
} else {
let bytes = input.bytes_mut();
let idx = state.rand_mut().below(bytes.len() as u64 - 3) as usize;
let val =
INTERESTING_32[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u32;
let new_bytes = if state.rand_mut().below(2) == 0 {
val.to_be_bytes()
} else {
val.to_le_bytes()
};
bytes[idx..idx + new_bytes.len()].copy_from_slice(&new_bytes);
Ok(MutationResult::Mutated)
}
}
}
impl<I, R, S> Named for DwordInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
fn name(&self) -> &str {
"DwordInterestingMutator"
}
}
impl<I, R, S> DwordInterestingMutator<I, R, S>
where
I: Input + HasBytesVec,
S: HasRand<R>,
R: Rand,
{
/// Creates a new [`DwordInterestingMutator`].
#[must_use]
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/// Bytes delete mutation for inputs with a bytes vector /// Bytes delete mutation for inputs with a bytes vector
#[derive(Default)] #[derive(Default)]
@ -1190,7 +850,7 @@ where
} }
} }
let val = state.rand_mut().below(256) as u8; let val = state.rand_mut().next() as u8;
input.bytes_mut().resize(size + len, 0); input.bytes_mut().resize(size + len, 0);
buffer_self_copy(input.bytes_mut(), off, off + len, size - off); buffer_self_copy(input.bytes_mut(), off, off + len, size - off);
@ -1256,7 +916,7 @@ where
let off = state.rand_mut().below(size as u64) as usize; let off = state.rand_mut().below(size as u64) as usize;
let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize; let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize;
let val = input.bytes()[state.rand_mut().below(size as u64) as usize]; let val = *state.rand_mut().choose(input.bytes());
buffer_set(input.bytes_mut(), off, len, val); buffer_set(input.bytes_mut(), off, len, val);
@ -1320,7 +980,7 @@ where
let off = state.rand_mut().below(size as u64) as usize; let off = state.rand_mut().below(size as u64) as usize;
let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize; let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize;
let val = state.rand_mut().below(256) as u8; let val = state.rand_mut().next() as u8;
buffer_set(input.bytes_mut(), off, len, val); buffer_set(input.bytes_mut(), off, len, val);
@ -1782,16 +1442,12 @@ where
// Converts a hex u8 to its u8 value: 'A' -> 10 etc. // Converts a hex u8 to its u8 value: 'A' -> 10 etc.
fn from_hex(hex: u8) -> Result<u8, Error> { fn from_hex(hex: u8) -> Result<u8, Error> {
if (48..=57).contains(&hex) { match hex {
return Ok(hex - 48); 48..=57 => Ok(hex - 48),
65..=70 => Ok(hex - 55),
97..=102 => Ok(hex - 87),
_ => Err(Error::IllegalArgument("Invalid hex character".to_owned())),
} }
if (65..=70).contains(&hex) {
return Ok(hex - 55);
}
if (97..=102).contains(&hex) {
return Ok(hex - 87);
}
Err(Error::IllegalArgument("".to_owned()))
} }
/// Decodes a dictionary token: 'foo\x41\\and\"bar' -> 'fooA\and"bar' /// Decodes a dictionary token: 'foo\x41\\and\"bar' -> 'fooA\and"bar'