Coverage Report

Created: 2026-04-20 06:16

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
51.0k
pub fn execute(target: &str, mut input: &[u8]) -> Output {
33
51.0k
    let mut output = BothOutput::default();
34
51.0k
    match target {
35
51.0k
        "fuzz_any_spec" => {
36
883
            let Some(spec) = gen::any_spec(&mut input) else { return output.reject() };
37
800
            let Ok(base) = spec.encoding() else { return output.reject() };
38
511
            let spec = base.specification();
39
511
            stat_spec(&mut output, &spec, &base);
40
511
            let input = gen::rev_spec(&spec);
41
511
            assert_eq!(gen::spec(&mut input.as_slice()).encoding().unwrap(), base);
42
        }
43
50.1k
        "impl_encode_len" => {
44
589
            let (_, base) = gen_spec_base(&mut input, &mut output);
45
589
            let _ = base.encode_len(usize::MAX / 512);
46
589
        }
47
49.5k
        "impl_decode_len" => {
48
548
            let (_, base) = gen_spec_base(&mut input, &mut output);
49
548
            let _ = base.decode_len(usize::MAX / 8);
50
548
        }
51
49.0k
        "impl_encode" => {
52
5.07k
            let (spec, base) = gen_spec_base(&mut input, &mut output);
53
5.07k
            assert_eq!(base.encode(input), spec::encode(&spec, input));
54
        }
55
43.9k
        "impl_decode" => {
56
9.24k
            let (spec, base) = gen_spec_base(&mut input, &mut output);
57
9.24k
            let actual = base.decode(input);
58
9.24k
            output.insert("decode_ok", actual.is_ok() as usize);
59
9.24k
            assert_eq!(actual.ok(), spec::decode(&spec, input));
60
        }
61
34.7k
        "impl_encode_mut_str" => {
62
4.59k
            let (spec, base) = gen_spec_base(&mut input, &mut output);
63
4.59k
            let mut output = vec![0; base.encode_len(input.len())];
64
4.59k
            assert_eq!(base.encode_mut_str(input, &mut output), spec::encode(&spec, input));
65
        }
66
30.1k
        "impl_encode_append" => {
67
5.02k
            let (spec, base) = gen_spec_base(&mut input, &mut output);
68
5.02k
            let mut output = String::new();
69
5.02k
            base.encode_append(input, &mut output);
70
5.02k
            assert_eq!(output, spec::encode(&spec, input));
71
        }
72
25.0k
        "impl_encode_write_buffer" => {
73
6.63k
            let (_, base) = gen_spec_base(&mut input, &mut output);
74
6.63k
            let mut buffer = vec![0; gen::nat(&mut input, 510, 2050)];
75
6.63k
            output.insert("buffer_len", buffer.len());
76
6.63k
            let mut actual = String::new();
77
6.63k
            base.encode_write_buffer(input, &mut actual, &mut buffer).unwrap();
78
6.63k
            assert_eq!(actual, base.encode(input));
79
        }
80
18.4k
        "impl_new_encoder" => {
81
6.51k
            let (_, base) = gen_spec_base(&mut input, &mut output);
82
6.51k
            let mut actual = String::new();
83
6.51k
            let mut full = Vec::new();
84
6.51k
            let mut encoder = base.new_encoder(&mut actual);
85
6.51k
            let mut num_chunks = 0;
86
7.15M
            while !input.is_empty() {
87
7.14M
                let len = gen::nat(&mut input, 0, 3 * 256 - 1);
88
7.14M
                let chunk = gen::bytes(&mut input, len);
89
7.14M
                full.extend_from_slice(chunk);
90
7.14M
                encoder.append(chunk);
91
7.14M
                num_chunks += 1;
92
7.14M
            }
93
6.51k
            encoder.finalize();
94
6.51k
            output.insert("full_len", full.len());
95
6.51k
            output.insert("num_chunks", num_chunks);
96
6.51k
            assert_eq!(actual, base.encode(&full));
97
        }
98
11.9k
        "spec_decode_encode" => {
99
2.55k
            let (_, base) = gen_spec_base(&mut input, &mut output);
100
2.55k
            let true = base.is_canonical() else { return output.reject() };
101
2.28k
            let Ok(tmp) = base.decode(input) else { return output.reject() };
102
1.91k
            assert_eq!(base.encode(&tmp).as_bytes(), input);
103
        }
104
9.38k
        "spec_encode_decode" => {
105
8.86k
            let (_, base) = gen_spec_base(&mut input, &mut output);
106
8.86k
            assert_eq!(base.decode(base.encode(input).as_bytes()).unwrap(), input);
107
        }
108
520
        "spec_spec_base" => {
109
520
            let (_, base) = gen_spec_base(&mut input, &mut output);
110
520
            assert_eq!(base.specification().encoding().unwrap(), base);
111
        }
112
0
        x => unimplemented!("{x:?}"),
113
    }
114
50.0k
    output.0
115
51.0k
}
116
117
50.1k
fn gen_spec_base(input: &mut &[u8], output: &mut BothOutput) -> (Specification, Encoding) {
118
50.1k
    let base = gen::base(input);
119
50.1k
    let spec = base.specification();
120
    debug!("{spec:#?}");
121
    debug!("{input:?}");
122
50.1k
    stat_spec(output, &spec, &base);
123
50.1k
    output.insert("input_len", input.len());
124
50.1k
    (spec, base)
125
50.1k
}
126
127
50.6k
fn stat_spec(output: &mut BothOutput, spec: &Specification, base: &Encoding) {
128
50.6k
    output.insert("bit", spec.symbols.len().trailing_zeros() as usize);
129
50.6k
    output.insert("msb", (spec.bit_order == BitOrder::MostSignificantFirst) as usize);
130
50.6k
    output.insert("ctb", spec.check_trailing_bits as usize);
131
50.6k
    output.insert("pad", spec.padding.is_some() as usize);
132
50.6k
    output.insert("ignore_len", spec.ignore.len());
133
50.6k
    output.insert("wrap_col", spec.wrap.width);
134
50.6k
    output.insert("wrap_len", spec.wrap.separator.len());
135
50.6k
    output.insert("translate_len", spec.translate.from.len());
136
50.6k
    output.insert("is_canonical", base.is_canonical() as usize);
137
50.6k
}
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
51.0k
    fn default() -> Self {
148
        #[cfg(fuzzing)]
149
51.0k
        let output = libfuzzer_sys::Corpus::Keep;
150
        #[cfg(not(fuzzing))]
151
        let output = HashMap::default();
152
51.0k
        BothOutput(output)
153
51.0k
    }
154
}
155
156
impl BothOutput {
157
    #[cfg(fuzzing)]
158
535k
    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
1.01k
    fn reject(self) -> Output {
166
1.01k
        libfuzzer_sys::Corpus::Reject
167
1.01k
    }
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();