Skip to content

Commit 1be6e5d

Browse files
authored
chore: validate address and word mutations (#11306)
* chore: validate address and word mutations * Changes after review
1 parent 8d92436 commit 1be6e5d

File tree

1 file changed

+83
-214
lines changed

1 file changed

+83
-214
lines changed

crates/evm/fuzz/src/strategies/mutators.rs

Lines changed: 83 additions & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -157,39 +157,31 @@ impl AbiMutator for I256 {
157157

158158
impl AbiMutator for Address {
159159
#[instrument(name = "Address::flip_random_bit", skip(_size, test_runner), ret)]
160-
fn flip_random_bit(mut self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {
161-
flip_random_bit_in_slice(self.as_mut_slice(), test_runner)?;
162-
Some(self)
160+
fn flip_random_bit(self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {
161+
let mut mutated = self;
162+
flip_random_bit_in_slice(mutated.as_mut_slice(), test_runner)?;
163+
(self != mutated).then_some(mutated)
163164
}
164165

165166
#[instrument(name = "Address::mutate_interesting_byte", skip(_size, test_runner), ret)]
166-
fn mutate_interesting_byte(
167-
mut self,
168-
_size: usize,
169-
test_runner: &mut TestRunner,
170-
) -> Option<Self> {
171-
mutate_interesting_byte_slice(self.as_mut_slice(), test_runner)?;
172-
Some(self)
167+
fn mutate_interesting_byte(self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {
168+
let mut mutated = self;
169+
mutate_interesting_byte_slice(mutated.as_mut_slice(), test_runner)?;
170+
(self != mutated).then_some(mutated)
173171
}
174172

175173
#[instrument(name = "Address::mutate_interesting_word", skip(_size, test_runner), ret)]
176-
fn mutate_interesting_word(
177-
mut self,
178-
_size: usize,
179-
test_runner: &mut TestRunner,
180-
) -> Option<Self> {
181-
mutate_interesting_word_slice(self.as_mut_slice(), test_runner)?;
182-
Some(self)
174+
fn mutate_interesting_word(self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {
175+
let mut mutated = self;
176+
mutate_interesting_word_slice(mutated.as_mut_slice(), test_runner)?;
177+
(self != mutated).then_some(mutated)
183178
}
184179

185180
#[instrument(name = "Address::mutate_interesting_dword", skip(_size, test_runner), ret)]
186-
fn mutate_interesting_dword(
187-
mut self,
188-
_size: usize,
189-
test_runner: &mut TestRunner,
190-
) -> Option<Self> {
191-
mutate_interesting_dword_slice(self.as_mut_slice(), test_runner)?;
192-
Some(self)
181+
fn mutate_interesting_dword(self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {
182+
let mut mutated = self;
183+
mutate_interesting_dword_slice(mutated.as_mut_slice(), test_runner)?;
184+
(self != mutated).then_some(mutated)
193185
}
194186
}
195187

@@ -199,31 +191,31 @@ impl AbiMutator for Word {
199191
let mut bytes = self;
200192
let slice = &mut bytes[..size];
201193
flip_random_bit_in_slice(slice, test_runner)?;
202-
Some(bytes)
194+
(self != bytes).then_some(bytes)
203195
}
204196

205197
#[instrument(name = "Word::mutate_interesting_byte", skip(size, test_runner), ret)]
206198
fn mutate_interesting_byte(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {
207199
let mut bytes = self;
208200
let slice = &mut bytes[..size];
209201
mutate_interesting_byte_slice(slice, test_runner)?;
210-
Some(bytes)
202+
(self != bytes).then_some(bytes)
211203
}
212204

213205
#[instrument(name = "Word::mutate_interesting_word", skip(size, test_runner), ret)]
214206
fn mutate_interesting_word(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {
215207
let mut bytes = self;
216208
let slice = &mut bytes[..size];
217209
mutate_interesting_word_slice(slice, test_runner)?;
218-
Some(bytes)
210+
(self != bytes).then_some(bytes)
219211
}
220212

221213
#[instrument(name = "Word::mutate_interesting_dword", skip(size, test_runner), ret)]
222214
fn mutate_interesting_dword(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {
223215
let mut bytes = self;
224216
let slice = &mut bytes[..size];
225217
mutate_interesting_dword_slice(slice, test_runner)?;
226-
Some(bytes)
218+
(self != bytes).then_some(bytes)
227219
}
228220
}
229221

@@ -306,228 +298,105 @@ mod tests {
306298
use proptest::test_runner::Config;
307299

308300
#[test]
309-
fn test_increment_decrement_u256() {
301+
fn test_mutate_uint() {
310302
let mut runner = TestRunner::new(Config::default());
303+
let size = 32;
311304

312-
let mut increment_decrement = |value: U256, expected: Vec<U256>| {
313-
for _ in 0..100 {
314-
let mutated = value.increment_decrement(8, &mut runner);
315-
assert!(
316-
mutated.is_none() || mutated.is_some_and(|mutated| expected.contains(&mutated))
317-
);
318-
}
319-
};
320-
321-
increment_decrement(U256::ZERO, vec![U256::ONE]);
322-
increment_decrement(U256::from(255), vec![U256::from(254)]);
323-
increment_decrement(U256::from(64), vec![U256::from(63), U256::from(65)]);
324-
}
325-
326-
#[test]
327-
fn test_increment_decrement_i256() {
328-
let mut runner = TestRunner::new(Config::default());
329-
330-
let mut increment_decrement = |value: I256, expected: Vec<I256>| {
331-
for _ in 0..100 {
332-
let mutated = value.increment_decrement(8, &mut runner);
333-
assert!(
334-
mutated.is_none() || mutated.is_some_and(|mutated| expected.contains(&mutated))
335-
);
336-
}
337-
};
338-
339-
increment_decrement(
340-
I256::from_dec_str("-128").unwrap(),
341-
vec![I256::from_dec_str("-127").unwrap()],
342-
);
343-
increment_decrement(
344-
I256::from_dec_str("127").unwrap(),
345-
vec![I256::from_dec_str("126").unwrap()],
346-
);
347-
increment_decrement(
348-
I256::from_dec_str("-47").unwrap(),
349-
vec![I256::from_dec_str("-48").unwrap(), I256::from_dec_str("-46").unwrap()],
350-
);
351-
increment_decrement(
352-
I256::from_dec_str("47").unwrap(),
353-
vec![I256::from_dec_str("48").unwrap(), I256::from_dec_str("46").unwrap()],
354-
);
355-
}
356-
357-
#[test]
358-
fn test_bit_flip_u256() {
359-
let mut runner = TestRunner::new(Config::default());
360-
let size = 8;
361-
362-
let mut test_bit_flip = |value: U256| {
363-
for _ in 0..100 {
364-
let flipped = U256::flip_random_bit(value, size, &mut runner);
365-
assert!(
366-
flipped.is_none()
367-
|| flipped.is_some_and(
368-
|flipped| flipped != value && flipped < (U256::from(1) << size)
369-
)
370-
);
371-
}
372-
};
373-
374-
test_bit_flip(U256::ZERO);
375-
test_bit_flip(U256::ONE);
376-
test_bit_flip(U256::MAX);
377-
test_bit_flip(U256::from(255));
378-
}
379-
380-
#[test]
381-
fn test_bit_flip_i256() {
382-
let mut runner = TestRunner::new(Config::default());
383-
let size = 8;
384-
385-
let mut test_bit_flip = |value: I256| {
386-
for _ in 0..100 {
387-
let flipped = I256::flip_random_bit(value, size, &mut runner);
388-
assert!(
389-
flipped.is_none()
390-
|| flipped.is_some_and(|flipped| {
391-
flipped != value
392-
&& flipped.abs().unsigned_abs() < (U256::from(1) << (size - 1))
393-
})
394-
);
395-
}
396-
};
397-
398-
test_bit_flip(I256::from_dec_str("-128").unwrap());
399-
test_bit_flip(I256::from_dec_str("127").unwrap());
400-
test_bit_flip(I256::MAX);
401-
test_bit_flip(I256::MIN);
402-
test_bit_flip(I256::MINUS_ONE);
403-
}
404-
405-
#[test]
406-
fn test_mutate_interesting_byte_u256() {
407-
let mut runner = TestRunner::new(Config::default());
408-
let value = U256::from(0);
409-
let size = 8;
305+
let test_values =
306+
vec![U256::ZERO, U256::ONE, U256::from(12345u64), U256::from(255), U256::MAX];
410307

411-
for _ in 0..100 {
412-
let mutated = U256::mutate_interesting_byte(value, size, &mut runner);
308+
#[track_caller]
309+
fn validate_mutation(value: U256, mutated: Option<U256>) {
413310
assert!(
414-
mutated.is_none()
415-
|| mutated.is_some_and(
416-
|mutated| mutated != value && mutated < (U256::from(1) << size)
417-
)
311+
mutated.is_none() || mutated.is_some_and(|m| m != value),
312+
"Mutation failed: value = {value:?}, mutated = {mutated:?}"
418313
);
419314
}
420-
}
421315

422-
#[test]
423-
fn test_mutate_interesting_word_u256() {
424-
let mut runner = TestRunner::new(Config::default());
425-
let value = U256::from(0);
426-
let size = 16;
427-
428-
for _ in 0..100 {
429-
let mutated = U256::mutate_interesting_word(value, size, &mut runner);
430-
assert!(
431-
mutated.is_none()
432-
|| mutated.is_some_and(
433-
|mutated| mutated != value && mutated < (U256::from(1) << size)
434-
)
435-
);
316+
for value in test_values {
317+
for _ in 0..100 {
318+
validate_mutation(value, U256::increment_decrement(value, size, &mut runner));
319+
validate_mutation(value, U256::flip_random_bit(value, size, &mut runner));
320+
validate_mutation(value, U256::mutate_interesting_byte(value, size, &mut runner));
321+
validate_mutation(value, U256::mutate_interesting_word(value, size, &mut runner));
322+
validate_mutation(value, U256::mutate_interesting_dword(value, size, &mut runner));
323+
}
436324
}
437325
}
438326

439327
#[test]
440-
fn test_mutate_interesting_dword_u256() {
328+
fn test_mutate_int() {
441329
let mut runner = TestRunner::new(Config::default());
442-
let value = U256::from(0);
443330
let size = 32;
444331

445-
for _ in 0..100 {
446-
let mutated = U256::mutate_interesting_dword(value, size, &mut runner);
332+
let test_values = vec![
333+
I256::ZERO,
334+
I256::ONE,
335+
I256::MINUS_ONE,
336+
I256::from_dec_str("12345").unwrap(),
337+
I256::from_dec_str("-54321").unwrap(),
338+
I256::from_dec_str("340282366920938463463374607431768211455").unwrap(),
339+
I256::from_dec_str("-340282366920938463463374607431768211455").unwrap(),
340+
];
341+
342+
#[track_caller]
343+
fn validate_mutation(value: I256, mutated: Option<I256>) {
447344
assert!(
448-
mutated.is_none()
449-
|| mutated.is_some_and(
450-
|mutated| mutated != value && mutated < (U256::from(1) << size)
451-
)
345+
mutated.is_none() || mutated.is_some_and(|m| m != value),
346+
"Mutation failed: value = {value:?}, mutated = {mutated:?}"
452347
);
453348
}
454-
}
455349

456-
#[test]
457-
fn test_mutate_interesting_byte_i256() {
458-
let mut runner = TestRunner::new(Config::default());
459-
let value = I256::ZERO;
460-
let size = 8;
461-
462-
for _ in 0..100 {
463-
let mutated = I256::mutate_interesting_byte(value, size, &mut runner);
464-
assert!(
465-
mutated.is_none()
466-
|| mutated.is_some_and(|mutated| mutated != value
467-
&& mutated.abs().unsigned_abs() < (U256::from(1) << (size - 1)))
468-
)
350+
for value in test_values {
351+
for _ in 0..100 {
352+
validate_mutation(value, I256::increment_decrement(value, size, &mut runner));
353+
validate_mutation(value, I256::flip_random_bit(value, size, &mut runner));
354+
validate_mutation(value, I256::mutate_interesting_byte(value, size, &mut runner));
355+
validate_mutation(value, I256::mutate_interesting_word(value, size, &mut runner));
356+
validate_mutation(value, I256::mutate_interesting_dword(value, size, &mut runner));
357+
}
469358
}
470359
}
471360

472361
#[test]
473-
fn test_mutate_interesting_word_i256() {
362+
fn test_mutate_address() {
474363
let mut runner = TestRunner::new(Config::default());
475-
let value = I256::ZERO;
476-
let size = 16;
364+
let value = Address::random();
477365

478-
for _ in 0..100 {
479-
let mutated = I256::mutate_interesting_word(value, size, &mut runner);
366+
#[track_caller]
367+
fn validate_mutation(value: Address, mutated: Option<Address>) {
480368
assert!(
481-
mutated.is_none()
482-
|| mutated.is_some_and(|mutated| mutated != value
483-
&& mutated.abs().unsigned_abs() < (U256::from(1) << (size - 1)))
484-
)
369+
mutated.is_none() || mutated.is_some_and(|mutated| mutated != value),
370+
"Mutation failed for value: {value:?}, result: {mutated:?}"
371+
);
485372
}
486-
}
487-
488-
#[test]
489-
fn test_mutate_interesting_dword_i256() {
490-
let mut runner = TestRunner::new(Config::default());
491-
let value = I256::ZERO;
492-
let size = 32;
493373

494374
for _ in 0..100 {
495-
let mutated = I256::mutate_interesting_dword(value, size, &mut runner);
496-
assert!(
497-
mutated.is_none()
498-
|| mutated.is_some_and(|mutated| mutated != value
499-
&& mutated.abs().unsigned_abs() < (U256::from(1) << (size - 1)))
500-
)
375+
validate_mutation(value, Address::flip_random_bit(value, 20, &mut runner));
376+
validate_mutation(value, Address::mutate_interesting_byte(value, 20, &mut runner));
377+
validate_mutation(value, Address::mutate_interesting_word(value, 20, &mut runner));
378+
validate_mutation(value, Address::mutate_interesting_dword(value, 20, &mut runner));
501379
}
502380
}
503381

504382
#[test]
505-
fn test_mutate_address() {
383+
fn test_mutate_word() {
506384
let mut runner = TestRunner::new(Config::default());
507-
for _ in 0..100 {
508-
let value = Address::random();
509-
assert_ne!(value, Address::flip_random_bit(value, 20, &mut runner).unwrap());
510-
let value1 = Address::random();
511-
assert_ne!(value1, Address::mutate_interesting_byte(value1, 20, &mut runner).unwrap());
512-
let value2 = Address::random();
513-
assert_ne!(value2, Address::mutate_interesting_word(value2, 20, &mut runner).unwrap());
514-
let value3 = Address::random();
515-
assert_ne!(value3, Address::mutate_interesting_dword(value3, 20, &mut runner).unwrap());
385+
let value = Word::random();
386+
387+
#[track_caller]
388+
fn validate_mutation(value: Word, mutated: Option<Word>) {
389+
assert!(
390+
mutated.is_none() || mutated.is_some_and(|mutated| mutated != value),
391+
"Mutation failed for value: {value:?}, result: {mutated:?}"
392+
);
516393
}
517-
}
518394

519-
#[test]
520-
fn test_mutate_word() {
521-
let mut runner = TestRunner::new(Config::default());
522395
for _ in 0..100 {
523-
let value = Word::random();
524-
assert_ne!(value, Word::flip_random_bit(value, 32, &mut runner).unwrap());
525-
let value1 = Word::random();
526-
assert_ne!(value1, Word::mutate_interesting_byte(value1, 32, &mut runner).unwrap());
527-
let value2 = Word::random();
528-
assert_ne!(value2, Word::mutate_interesting_word(value2, 32, &mut runner).unwrap());
529-
let value3 = Word::random();
530-
assert_ne!(value3, Word::mutate_interesting_dword(value3, 32, &mut runner).unwrap());
396+
validate_mutation(value, Word::flip_random_bit(value, 32, &mut runner));
397+
validate_mutation(value, Word::mutate_interesting_byte(value, 32, &mut runner));
398+
validate_mutation(value, Word::mutate_interesting_word(value, 32, &mut runner));
399+
validate_mutation(value, Word::mutate_interesting_dword(value, 32, &mut runner));
531400
}
532401
}
533402

0 commit comments

Comments
 (0)