Coverage Report

Created: 2025-12-14 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/data-encoding/lib/fuzz/src/cmd.rs
Line
Count
Source
1
#[cfg(not(fuzzing))]
2
use std::collections::HashMap;
3
#[cfg(not(fuzzing))]
4
use std::path::{Path, PathBuf};
5
#[cfg(not(fuzzing))]
6
use std::sync::OnceLock;
7
8
use data_encoding::{BitOrder, Encoding, Specification};
9
10
use crate::{gen, spec};
11
12
macro_rules! debug {
13
    ($($arg:tt)*) => {
14
        #[cfg(not(fuzzing))]
15
        if *DEBUG.get().unwrap() {
16
            println!($($arg)*);
17
        }
18
    };
19
}
20
21
#[cfg(not(fuzzing))]
22
pub fn path(debug: bool) -> PathBuf {
23
    DEBUG.set(debug).unwrap();
24
    PathBuf::from(std::env::args_os().nth(1).unwrap())
25
}
26
27
#[cfg(not(fuzzing))]
28
pub fn target(path: &Path) -> String {
29
    path.components().nth(2).unwrap().as_os_str().to_str().unwrap().to_owned()
30
}
31
32
42.7k
pub fn execute(target: &str, mut input: &[u8]) -> Output {
33
42.7k
    let mut output = BothOutput::default();
34
42.7k
    match target {
35
42.7k
        "fuzz_any_spec" => {
36
727
            let Some(spec) = gen::any_spec(&mut input) else { return output.reject() };
37
659
            let Ok(base) = spec.encoding() else { return output.reject() };
38
405
            let spec = base.specification();
39
405
            stat_spec(&mut output, &spec, &base);
40
405
            let input = gen::rev_spec(&spec);
41
405
            assert_eq!(gen::spec(&mut input.as_slice()).encoding().unwrap(), base);
42
        }
43
42.0k
        "impl_encode_len" => {
44
481
            let (_, base) = gen_spec_base(&mut input, &mut output);
45
481
            let _ = base.encode_len(usize::MAX / 512);
46
481
        }
47
41.5k
        "impl_decode_len" => {
48
464
            let (_, base) = gen_spec_base(&mut input, &mut output);
49
464
            let _ = base.decode_len(usize::MAX / 8);
50
464
        }
51
41.1k
        "impl_encode" => {
52
4.11k
            let (spec, base) = gen_spec_base(&mut input, &mut output);
53
4.11k
            assert_eq!(base.encode(input), spec::encode(&spec, input));
54
        }
55
36.9k
        "impl_decode" => {
56
8.06k
            let (spec, base) = gen_spec_base(&mut input, &mut output);
57
8.06k
            let actual = base.decode(input);
58
8.06k
            output.insert("decode_ok", actual.is_ok() as usize);
59
8.06k
            assert_eq!(actual.ok(), spec::decode(&spec, input));
60
        }
61
28.9k
        "impl_encode_mut_str" => {
62
4.17k
            let (spec, base) = gen_spec_base(&mut input, &mut output);
63
4.17k
            let mut output = vec![0; base.encode_len(input.len())];
64
4.17k
            assert_eq!(base.encode_mut_str(input, &mut output), spec::encode(&spec, input));
65
        }
66
24.7k
        "impl_encode_append" => {
67
4.23k
            let (spec, base) = gen_spec_base(&mut input, &mut output);
68
4.23k
            let mut output = String::new();
69
4.23k
            base.encode_append(input, &mut output);
70
4.23k
            assert_eq!(output, spec::encode(&spec, input));
71
        }
72
20.5k
        "impl_encode_write_buffer" => {
73
5.44k
            let (_, base) = gen_spec_base(&mut input, &mut output);
74
5.44k
            let mut buffer = vec![0; gen::nat(&mut input, 510, 2050)];
75
5.44k
            output.insert("buffer_len", buffer.len());
76
5.44k
            let mut actual = String::new();
77
5.44k
            base.encode_write_buffer(input, &mut actual, &mut buffer).unwrap();
78
5.44k
            assert_eq!(actual, base.encode(input));
79
        }
80
15.0k
        "impl_new_encoder" => {
81
5.47k
            let (_, base) = gen_spec_base(&mut input, &mut output);
82
5.47k
            let mut actual = String::new();
83
5.47k
            let mut full = Vec::new();
84
5.47k
            let mut encoder = base.new_encoder(&mut actual);
85
5.47k
            let mut num_chunks = 0;
86
6.61M
            while !input.is_empty() {
87
6.60M
                let len = gen::nat(&mut input, 0, 3 * 256 - 1);
88
6.60M
                let chunk = gen::bytes(&mut input, len);
89
6.60M
                full.extend_from_slice(chunk);
90
6.60M
                encoder.append(chunk);
91
6.60M
                num_chunks += 1;
92
6.60M
            }
93
5.47k
            encoder.finalize();
94
5.47k
            output.insert("full_len", full.len());
95
5.47k
            output.insert("num_chunks", num_chunks);
96
5.47k
            assert_eq!(actual, base.encode(&full));
97
        }
98
9.59k
        "spec_decode_encode" => {
99
2.12k
            let (_, base) = gen_spec_base(&mut input, &mut output);
100
2.12k
            let true = base.is_canonical() else { return output.reject() };
101
1.89k
            let Ok(tmp) = base.decode(input) else { return output.reject() };
102
1.55k
            assert_eq!(base.encode(&tmp).as_bytes(), input);
103
        }
104
7.47k
        "spec_encode_decode" => {
105
7.02k
            let (_, base) = gen_spec_base(&mut input, &mut output);
106
7.02k
            assert_eq!(base.decode(base.encode(input).as_bytes()).unwrap(), input);
107
        }
108
452
        "spec_spec_base" => {
109
452
            let (_, base) = gen_spec_base(&mut input, &mut output);
110
452
            assert_eq!(base.specification().encoding().unwrap(), base);
111
        }
112
0
        x => unimplemented!("{x:?}"),
113
    }
114
41.8k
    output.0
115
42.7k
}
116
117
42.0k
fn gen_spec_base(input: &mut &[u8], output: &mut BothOutput) -> (Specification, Encoding) {
118
42.0k
    let base = gen::base(input);
119
42.0k
    let spec = base.specification();
120
    debug!("{spec:#?}");
121
    debug!("{input:?}");
122
42.0k
    stat_spec(output, &spec, &base);
123
42.0k
    output.insert("input_len", input.len());
124
42.0k
    (spec, base)
125
42.0k
}
126
127
42.4k
fn stat_spec(output: &mut BothOutput, spec: &Specification, base: &Encoding) {
128
42.4k
    output.insert("bit", spec.symbols.len().trailing_zeros() as usize);
129
42.4k
    output.insert("msb", (spec.bit_order == BitOrder::MostSignificantFirst) as usize);
130
42.4k
    output.insert("ctb", spec.check_trailing_bits as usize);
131
42.4k
    output.insert("pad", spec.padding.is_some() as usize);
132
42.4k
    output.insert("ignore_len", spec.ignore.len());
133
42.4k
    output.insert("wrap_col", spec.wrap.width);
134
42.4k
    output.insert("wrap_len", spec.wrap.separator.len());
135
42.4k
    output.insert("translate_len", spec.translate.from.len());
136
42.4k
    output.insert("is_canonical", base.is_canonical() as usize);
137
42.4k
}
138
139
#[cfg(fuzzing)]
140
type Output = libfuzzer_sys::Corpus;
141
#[cfg(not(fuzzing))]
142
type Output = HashMap<&'static str, usize>;
143
144
struct BothOutput(Output);
145
146
impl Default for BothOutput {
147
42.7k
    fn default() -> Self {
148
        #[cfg(fuzzing)]
149
42.7k
        let output = libfuzzer_sys::Corpus::Keep;
150
        #[cfg(not(fuzzing))]
151
        let output = HashMap::default();
152
42.7k
        BothOutput(output)
153
42.7k
    }
154
}
155
156
impl BothOutput {
157
    #[cfg(fuzzing)]
158
448k
    fn insert(&mut self, _: &'static str, _: usize) {}
159
    #[cfg(not(fuzzing))]
160
    fn insert(&mut self, key: &'static str, value: usize) {
161
        assert!(self.0.insert(key, value).is_none());
162
    }
163
164
    #[cfg(fuzzing)]
165
896
    fn reject(self) -> Output {
166
896
        libfuzzer_sys::Corpus::Reject
167
896
    }
168
    #[cfg(not(fuzzing))]
169
    fn reject(self) -> Output {
170
        self.0
171
    }
172
}
173
174
#[cfg(not(fuzzing))]
175
static DEBUG: OnceLock<bool> = OnceLock::new();