1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use arbitrary::{Arbitrary, Unstructured};
use canonical::{ByteSink, Canon, Store};
const FUZZ_ITERATIONS: usize = 1024;
fn hash<T: Hash>(t: T) -> u64 {
let mut hasher = DefaultHasher::new();
t.hash(&mut hasher);
hasher.finish()
}
pub fn fuzz_canon<C, S>(store: S)
where
C: Canon<S> + Arbitrary + PartialEq + std::fmt::Debug,
S: Store,
{
fuzz_canon_iterations::<C, S>(FUZZ_ITERATIONS, store)
}
pub fn fuzz_canon_iterations<C, S>(iterations: usize, store: S)
where
C: Canon<S> + Arbitrary + PartialEq + std::fmt::Debug,
S: Store,
{
let mut entropy = 0;
for _ in 0..iterations {
let mut bytes = vec![];
let canon = {
loop {
match C::arbitrary(&mut Unstructured::new(&bytes)) {
Ok(t) => break t,
Err(_) => {
entropy += 1;
bytes.extend_from_slice(&hash(entropy).to_be_bytes());
}
}
}
};
let claimed_len = canon.encoded_len();
let mut buffer_a = vec![];
buffer_a.resize_with(claimed_len + 1, || 0xff);
let mut buffer_b = vec![];
buffer_b.resize_with(claimed_len + 1, || 0x00);
let mut sink_a = ByteSink::new(&mut buffer_a[..], store.clone());
let mut sink_b = ByteSink::new(&mut buffer_b[..], store.clone());
Canon::write(&canon, &mut sink_a).unwrap();
Canon::write(&canon, &mut sink_b).unwrap();
let mut valid = true;
if buffer_a[claimed_len] != 0xff
|| buffer_b[claimed_len] != 0x00
|| (claimed_len > 0
&& buffer_a[claimed_len - 1] != buffer_b[claimed_len - 1])
{
valid = false
}
if !valid {
for i in 0..claimed_len {
if buffer_a[i] != buffer_b[i] {
panic!("claimed {}, wrote {}", claimed_len, i - 1)
}
}
}
let id = store.put(&canon).unwrap();
let restored = store.get(&id).unwrap();
assert!(canon == restored);
}
}
pub fn canon_encoding<C, S>(canon: &C) -> usize
where
C: Canon<S> + Arbitrary + PartialEq + std::fmt::Debug,
S: Store,
{
let store = S::default();
let buffer_size = canon.encoded_len();
let mut buffer_a = vec![0xff; buffer_size];
let mut buffer_b = vec![0x00; buffer_size];
let mut sink_a = ByteSink::new(&mut buffer_a, store.clone());
let mut sink_b = ByteSink::new(&mut buffer_b, store.clone());
Canon::write(canon, &mut sink_a).unwrap();
Canon::write(canon, &mut sink_b).unwrap();
let mut len = 0;
for i in 0..buffer_size {
if buffer_a[i] != buffer_b[i] {
break;
} else {
len += 1;
}
}
len
}