Coverage Report

Created: 2025-07-23 08:04

/src/image-png/fuzz/fuzz_targets/buf_independent.rs
Line
Count
Source (jump to first uncovered line)
1
//! This fuzzer tests that decoding results are the same regardless of the
2
//! details of how the `Read` trait exposes the underlying input via
3
//! the `fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>`
4
//! method:
5
//!
6
//! * Whole slice - `impl Read for &[u8]`:
7
//!     - The whole slice is available for reading (if it fits into `buf`)
8
//!     - No IO errors are expected
9
//!     - Motivation: This is the baseline
10
//! * Byte-by-byte - `SmalBuf<R>`:
11
//!     - At most 1 byte can be read in a single call to `read`
12
//!     - Motivation: Testing that decoding works regardless of how the input is split
13
//!       into multiple `read` calls.  (The test checks every possible `read` boundary in the input
14
//!       buffer, even though in practice file or network buffers would split the input into only a
15
//!       handful of chunks.)
16
//! * TODO: Intermittent EOFs:
17
//!     - Intermittently `read` report 0 available bytes.
18
//!     - Still no IO errors at the `Read` trait level
19
//!     - Motivation: Testing support for decoding a streaming or partial input
20
//!       (i.e. scenarios where initially only the first few interlaced passes
21
//!       can be decoded, and where decoding is resumed after getting more complete
22
//!       input).
23
24
#![no_main]
25
26
use libfuzzer_sys::fuzz_target;
27
28
use std::fmt::Debug;
29
use std::io::{BufRead, BufReader, Cursor, Seek};
30
31
mod smal_buf {
32
    use std::io::{BufRead, Cursor, Read, Seek};
33
34
    /// A reader that returns at most 1 byte in a single call to `read`.
35
    pub struct SmalBuf {
36
        inner: Cursor<Vec<u8>>,
37
    }
38
39
    impl SmalBuf {
40
15.8k
        pub fn new(inner: Vec<u8>) -> Self {
41
15.8k
            SmalBuf {
42
15.8k
                inner: Cursor::new(inner),
43
15.8k
            }
44
15.8k
        }
45
    }
46
47
    impl Read for SmalBuf {
48
32.4M
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
49
32.4M
            if buf.is_empty() {
50
0
                return Ok(0);
51
32.4M
            }
52
32.4M
            self.inner.read(&mut buf[..1])
53
32.4M
        }
54
    }
55
    impl BufRead for SmalBuf {
56
0
        fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
57
0
            let buf = self.inner.fill_buf()?;
58
0
            Ok(&buf[..buf.len().min(1)])
59
0
        }
60
61
0
        fn consume(&mut self, amt: usize) {
62
0
            self.inner.consume(amt);
63
0
        }
64
    }
65
    impl Seek for SmalBuf {
66
0
        fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
67
0
            self.inner.seek(pos)
68
0
        }
69
    }
70
}
71
72
mod intermittent_eofs {
73
74
    use std::cell::Cell;
75
    use std::io::{BufRead, Read, Seek};
76
    use std::rc::Rc;
77
78
    /// A reader that returns `std::io::ErrorKind::UnexpectedEof` errors in every other read.
79
    /// EOFs can be temporarily disabled and re-enabled later using the associated `EofController`.
80
    pub struct IntermittentEofs<R: BufRead + Seek> {
81
        inner: R,
82
83
        /// Controls whether intermittent EOFs happen at all.
84
        controller: Rc<EofController>,
85
86
        /// Controls whether an intermittent EOF will happen during the next `read`
87
        /// (when enabled, intermittent EOFs happen every other `read`).
88
        eof_soon: bool,
89
    }
90
91
    impl<R: BufRead + Seek> IntermittentEofs<R> {
92
7.92k
        pub fn new(inner: R) -> Self {
93
7.92k
            Self {
94
7.92k
                inner,
95
7.92k
                controller: Rc::new(EofController::new()),
96
7.92k
                eof_soon: true,
97
7.92k
            }
98
7.92k
        }
99
100
7.92k
        pub fn controller(&self) -> Rc<EofController> {
101
7.92k
            self.controller.clone()
102
7.92k
        }
103
    }
104
105
    impl<R: BufRead + Seek> Read for IntermittentEofs<R> {
106
26.2M
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
107
26.2M
            if self.controller.are_intermittent_eofs_enabled() && self.eof_soon {
108
10.0M
                self.eof_soon = false;
109
10.0M
                return Ok(0);
110
16.2M
            }
111
16.2M
112
16.2M
            self.eof_soon = true;
113
16.2M
            let inner_result = self.inner.read(buf);
114
16.2M
            if let Ok(0) = &inner_result {
115
6.14k
                self.controller.mark_inner_eof();
116
16.2M
            }
117
118
16.2M
            inner_result
119
26.2M
        }
120
    }
121
    impl<R: BufRead + Seek> BufRead for IntermittentEofs<R> {
122
0
        fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
123
0
            self.inner.fill_buf()
124
0
        }
125
126
0
        fn consume(&mut self, amt: usize) {
127
0
            self.inner.consume(amt);
128
0
        }
129
    }
130
    impl<R: BufRead + Seek> Seek for IntermittentEofs<R> {
131
0
        fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
132
0
            self.inner.seek(pos)
133
0
        }
134
    }
135
136
    pub struct EofController {
137
        are_intermittent_eofs_enabled: Cell<bool>,
138
        did_reach_inner_eof: Cell<bool>,
139
    }
140
141
    impl EofController {
142
7.92k
        fn new() -> Self {
143
7.92k
            Self {
144
7.92k
                are_intermittent_eofs_enabled: Cell::new(true),
145
7.92k
                did_reach_inner_eof: Cell::new(false),
146
7.92k
            }
147
7.92k
        }
148
149
3.79k
        pub fn enable_intermittent_eofs(&self) {
150
3.79k
            self.are_intermittent_eofs_enabled.set(true);
151
3.79k
        }
152
153
7.92k
        pub fn disable_intermittent_eofs(&self) {
154
7.92k
            self.are_intermittent_eofs_enabled.set(false);
155
7.92k
        }
156
157
26.2M
        fn are_intermittent_eofs_enabled(&self) -> bool {
158
26.2M
            self.are_intermittent_eofs_enabled.get()
159
26.2M
        }
160
161
6.14k
        fn mark_inner_eof(&self) {
162
6.14k
            self.did_reach_inner_eof.set(true);
163
6.14k
        }
164
165
10.0M
        pub fn did_reach_inner_eof(&self) -> bool {
166
10.0M
            self.did_reach_inner_eof.get()
167
10.0M
        }
168
    }
169
}
170
171
fuzz_target!(|data: &[u8]| {
172
    let _ = test_data(data);
173
});
174
175
trait BufReadSeek: BufRead + Seek {}
176
impl<T> BufReadSeek for T where T: BufRead + Seek {}
177
178
#[inline(always)]
179
7.92k
fn test_data<'a>(data: &'a [u8]) -> Result<(), ()> {
180
7.92k
    let baseline_reader = Box::new(Cursor::new(data));
181
7.92k
    let byte_by_byte_reader = Box::new(smal_buf::SmalBuf::new(data.to_owned()));
182
7.92k
    let intermittent_eofs_reader = Box::new(intermittent_eofs::IntermittentEofs::new(
183
7.92k
        smal_buf::SmalBuf::new(data.to_owned()),
184
7.92k
    ));
185
7.92k
    let intermittent_eofs_controller = intermittent_eofs_reader.controller();
186
7.92k
187
7.92k
    // `Decoder` used to internally wrap the provided reader with a `BufReader`. Now that it has
188
7.92k
    // been removed, fuzzing would be far too slow if we didn't use a BufReader here.
189
7.92k
    let data_readers: Vec<BufReader<Box<dyn BufReadSeek>>> = vec![
190
7.92k
        BufReader::new(baseline_reader),
191
7.92k
        BufReader::new(byte_by_byte_reader),
192
7.92k
        BufReader::new(intermittent_eofs_reader),
193
7.92k
    ];
194
7.92k
195
7.92k
    let decoders = data_readers
196
7.92k
        .into_iter()
197
23.7k
        .map(|data_reader| {
198
23.7k
            // Small limits, we don't need them hopefully.
199
23.7k
            let limits = png::Limits { bytes: 1 << 16 };
200
23.7k
            png::Decoder::new_with_limits(data_reader, limits)
201
23.7k
        })
202
7.92k
        .collect::<Vec<_>>();
203
7.92k
204
7.92k
    // `Decoder.read_info` consumes `self` and is therefore not resumable.  To work around that
205
7.92k
    // let's temporarily disable intermittent EOFs:
206
7.92k
    intermittent_eofs_controller.disable_intermittent_eofs();
207
7.92k
    let mut png_readers = decoders
208
7.92k
        .into_iter()
209
23.7k
        .map(|decoder| decoder.read_info())
210
7.92k
        .assert_all_results_are_consistent()
211
7.92k
        .collect::<Result<Vec<_>, _>>()
212
7.92k
        .map_err(|_| ())?;
213
3.79k
    intermittent_eofs_controller.enable_intermittent_eofs();
214
3.79k
215
3.79k
    let info = png_readers
216
3.79k
        .iter()
217
11.3k
        .map(|r| r.info().clone())
218
7.59k
        .assert_all_items_are_same(|lhs: &png::Info, rhs: &png::Info| {
219
7.59k
            assert_same_info(lhs, rhs);
220
7.59k
221
7.59k
            // The assert below is somewhat redundant, but we use `raw_bytes`
222
7.59k
            // later on, so let's double-check that it's the same everywhere.
223
7.59k
            assert_eq!(lhs.raw_bytes(), rhs.raw_bytes());
224
7.59k
        });
225
3.79k
    if info.raw_bytes() > 5_000_000 {
226
144
        return Err(());
227
3.65k
    }
228
3.65k
229
3.65k
    let mut buffers = vec![vec![0; info.raw_bytes()]; png_readers.len()];
230
    loop {
231
4.28k
        let output_infos = png_readers
232
4.28k
            .iter_mut()
233
4.28k
            .zip(buffers.iter_mut())
234
4.28k
            .enumerate()
235
12.8k
            .map(|(i, (png_reader, buffer))| {
236
12.8k
                let eof_controller = if i == 2 {
237
4.28k
                    Some(&intermittent_eofs_controller)
238
                } else {
239
8.57k
                    None
240
                };
241
10.0M
                retry_after_eofs(eof_controller, || {
242
10.0M
                    png_reader.next_frame(buffer.as_mut_slice())
243
10.0M
                })
244
12.8k
            })
245
4.28k
            .assert_all_results_are_consistent()
246
4.28k
            .collect::<Result<Vec<_>, _>>()
247
4.28k
            .map_err(|_| ())?;
248
635
        output_infos.into_iter().assert_all_items_are_equal();
249
635
        buffers.iter().assert_all_items_are_equal();
250
    }
251
7.92k
}
252
253
12.8k
fn retry_after_eofs<T>(
254
12.8k
    eof_controller: Option<&std::rc::Rc<intermittent_eofs::EofController>>,
255
12.8k
    mut f: impl FnMut() -> Result<T, png::DecodingError>,
256
12.8k
) -> Result<T, png::DecodingError> {
257
    loop {
258
10.0M
        let result = f();
259
10.0M
        match result.as_ref() {
260
10.0M
            Err(png::DecodingError::IoError(e)) => {
261
10.0M
                if e.kind() == std::io::ErrorKind::UnexpectedEof {
262
10.0M
                    if let Some(ctrl) = eof_controller {
263
10.0M
                        if !ctrl.did_reach_inner_eof() {
264
10.0M
                            continue;
265
2.72k
                        }
266
5.45k
                    }
267
0
                }
268
            }
269
4.67k
            _ => (),
270
        }
271
12.8k
        break result;
272
12.8k
    }
273
12.8k
}
274
275
7.59k
fn assert_same_info(lhs: &png::Info, rhs: &png::Info) {
276
7.59k
    // Check that all decoders report the same `IHDR` fields.
277
7.59k
    assert_eq!(lhs.width, rhs.width);
278
7.59k
    assert_eq!(lhs.height, rhs.height);
279
7.59k
    assert_eq!(lhs.bit_depth, rhs.bit_depth);
280
7.59k
    assert_eq!(lhs.color_type, rhs.color_type);
281
7.59k
    assert_eq!(lhs.interlaced, rhs.interlaced);
282
283
    // Check all other `Info` fields that implement `Eq`.
284
7.59k
    assert_eq!(lhs.chrm_chunk, rhs.chrm_chunk);
285
7.59k
    assert_eq!(lhs.gama_chunk, rhs.gama_chunk);
286
7.59k
    assert_eq!(lhs.icc_profile, rhs.icc_profile);
287
7.59k
    assert_eq!(lhs.palette, rhs.palette);
288
7.59k
    assert_eq!(lhs.source_chromaticities, rhs.source_chromaticities);
289
7.59k
    assert_eq!(lhs.source_gamma, rhs.source_gamma);
290
7.59k
    assert_eq!(lhs.srgb, rhs.srgb);
291
7.59k
    assert_eq!(lhs.trns, rhs.trns);
292
7.59k
}
293
294
trait IteratorExtensionsForFuzzing: Iterator + Sized {
295
    /// Verifies that either 1) all items in the iterator are `Ok(_)` or 2) all items in the
296
    /// iterator are `Err(_)`.  Passes through unmodified iterator items.
297
12.2k
    fn assert_all_results_are_consistent<T>(self) -> impl Iterator<Item = Self::Item>
298
12.2k
    where
299
12.2k
        Self: Iterator<Item = Result<T, png::DecodingError>>,
300
12.2k
    {
301
12.2k
        // Eagerly collect all the items - this makes sure we check consistency of *all* results,
302
12.2k
        // even if a downstream iterator combinator consumes items lazily and never "pumps" some
303
12.2k
        // items via `next`.  (`iter.take(2)` is one example of such lazy consumer;
304
12.2k
        // `iter_of_results.collect::<Result<Vec<_>, _>>()` is another.)
305
12.2k
        let all_results = self.collect::<Vec<_>>();
306
12.2k
307
21.0k
        let any_err = all_results.iter().any(|res| res.is_err());
<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::slice::iter::IterMut<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, core::slice::iter::IterMut<alloc::vec::Vec<u8>>>>, buf_independent::test_data::{closure#5}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::OutputInfo>::{closure#0}
Line
Count
Source
307
5.55k
        let any_err = all_results.iter().any(|res| res.is_err());
<core::iter::adapters::map::Map<alloc::vec::into_iter::IntoIter<png::decoder::Decoder<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#1}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>::{closure#0}
Line
Count
Source
307
15.5k
        let any_err = all_results.iter().any(|res| res.is_err());
308
27.7k
        let any_ok = all_results.iter().any(|res| res.is_ok());
<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::slice::iter::IterMut<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, core::slice::iter::IterMut<alloc::vec::Vec<u8>>>>, buf_independent::test_data::{closure#5}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::OutputInfo>::{closure#1}
Line
Count
Source
308
11.5k
        let any_ok = all_results.iter().any(|res| res.is_ok());
<core::iter::adapters::map::Map<alloc::vec::into_iter::IntoIter<png::decoder::Decoder<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#1}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>::{closure#1}
Line
Count
Source
308
16.1k
        let any_ok = all_results.iter().any(|res| res.is_ok());
309
12.2k
        if any_err && any_ok {
310
            // Replacing `Self::Item` with an "ok" string, because we want to support items
311
            // that do not implement `Debug`.
312
0
            let printable_results = all_results.iter().map(|res| res.as_ref().map(|_| "ok"));
Unexecuted instantiation: <core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::slice::iter::IterMut<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, core::slice::iter::IterMut<alloc::vec::Vec<u8>>>>, buf_independent::test_data::{closure#5}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::OutputInfo>::{closure#2}
Unexecuted instantiation: <core::iter::adapters::map::Map<alloc::vec::into_iter::IntoIter<png::decoder::Decoder<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#1}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>::{closure#2}
Unexecuted instantiation: <core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::slice::iter::IterMut<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, core::slice::iter::IterMut<alloc::vec::Vec<u8>>>>, buf_independent::test_data::{closure#5}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::OutputInfo>::{closure#2}::{closure#0}
Unexecuted instantiation: <core::iter::adapters::map::Map<alloc::vec::into_iter::IntoIter<png::decoder::Decoder<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#1}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>::{closure#2}::{closure#0}
313
0
            for (i, res) in printable_results.enumerate() {
314
0
                eprintln!("Result #{i}: {res:?}");
315
0
            }
316
0
            panic!("Inconsistent results - some are Ok(_) and some are Err(_)");
317
12.2k
        }
318
12.2k
319
12.2k
        all_results.into_iter()
320
12.2k
    }
<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::slice::iter::IterMut<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, core::slice::iter::IterMut<alloc::vec::Vec<u8>>>>, buf_independent::test_data::{closure#5}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::OutputInfo>
Line
Count
Source
297
4.28k
    fn assert_all_results_are_consistent<T>(self) -> impl Iterator<Item = Self::Item>
298
4.28k
    where
299
4.28k
        Self: Iterator<Item = Result<T, png::DecodingError>>,
300
4.28k
    {
301
4.28k
        // Eagerly collect all the items - this makes sure we check consistency of *all* results,
302
4.28k
        // even if a downstream iterator combinator consumes items lazily and never "pumps" some
303
4.28k
        // items via `next`.  (`iter.take(2)` is one example of such lazy consumer;
304
4.28k
        // `iter_of_results.collect::<Result<Vec<_>, _>>()` is another.)
305
4.28k
        let all_results = self.collect::<Vec<_>>();
306
4.28k
307
4.28k
        let any_err = all_results.iter().any(|res| res.is_err());
308
4.28k
        let any_ok = all_results.iter().any(|res| res.is_ok());
309
4.28k
        if any_err && any_ok {
310
            // Replacing `Self::Item` with an "ok" string, because we want to support items
311
            // that do not implement `Debug`.
312
0
            let printable_results = all_results.iter().map(|res| res.as_ref().map(|_| "ok"));
313
0
            for (i, res) in printable_results.enumerate() {
314
0
                eprintln!("Result #{i}: {res:?}");
315
0
            }
316
0
            panic!("Inconsistent results - some are Ok(_) and some are Err(_)");
317
4.28k
        }
318
4.28k
319
4.28k
        all_results.into_iter()
320
4.28k
    }
<core::iter::adapters::map::Map<alloc::vec::into_iter::IntoIter<png::decoder::Decoder<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#1}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_results_are_consistent::<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>
Line
Count
Source
297
7.92k
    fn assert_all_results_are_consistent<T>(self) -> impl Iterator<Item = Self::Item>
298
7.92k
    where
299
7.92k
        Self: Iterator<Item = Result<T, png::DecodingError>>,
300
7.92k
    {
301
7.92k
        // Eagerly collect all the items - this makes sure we check consistency of *all* results,
302
7.92k
        // even if a downstream iterator combinator consumes items lazily and never "pumps" some
303
7.92k
        // items via `next`.  (`iter.take(2)` is one example of such lazy consumer;
304
7.92k
        // `iter_of_results.collect::<Result<Vec<_>, _>>()` is another.)
305
7.92k
        let all_results = self.collect::<Vec<_>>();
306
7.92k
307
7.92k
        let any_err = all_results.iter().any(|res| res.is_err());
308
7.92k
        let any_ok = all_results.iter().any(|res| res.is_ok());
309
7.92k
        if any_err && any_ok {
310
            // Replacing `Self::Item` with an "ok" string, because we want to support items
311
            // that do not implement `Debug`.
312
0
            let printable_results = all_results.iter().map(|res| res.as_ref().map(|_| "ok"));
313
0
            for (i, res) in printable_results.enumerate() {
314
0
                eprintln!("Result #{i}: {res:?}");
315
0
            }
316
0
            panic!("Inconsistent results - some are Ok(_) and some are Err(_)");
317
7.92k
        }
318
7.92k
319
7.92k
        all_results.into_iter()
320
7.92k
    }
321
322
    /// Verifies that all items in the iterator are the same (according to their `Eq`
323
    /// implementation).  Returns one of the items.
324
1.27k
    fn assert_all_items_are_equal(self) -> Self::Item
325
1.27k
    where
326
1.27k
        Self::Item: Debug + Eq,
327
1.27k
    {
328
2.54k
        self.assert_all_items_are_same(|lhs, rhs| assert_eq!(lhs, rhs))
<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}
Line
Count
Source
328
1.27k
        self.assert_all_items_are_same(|lhs, rhs| assert_eq!(lhs, rhs))
<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}
Line
Count
Source
328
1.27k
        self.assert_all_items_are_same(|lhs, rhs| assert_eq!(lhs, rhs))
329
1.27k
    }
<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal
Line
Count
Source
324
635
    fn assert_all_items_are_equal(self) -> Self::Item
325
635
    where
326
635
        Self::Item: Debug + Eq,
327
635
    {
328
635
        self.assert_all_items_are_same(|lhs, rhs| assert_eq!(lhs, rhs))
329
635
    }
<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal
Line
Count
Source
324
635
    fn assert_all_items_are_equal(self) -> Self::Item
325
635
    where
326
635
        Self::Item: Debug + Eq,
327
635
    {
328
635
        self.assert_all_items_are_same(|lhs, rhs| assert_eq!(lhs, rhs))
329
635
    }
330
331
    /// Verifies that all items in the iterator are the same (according to the `assert_same`
332
    /// function.  Returns one of the items.
333
5.06k
    fn assert_all_items_are_same<F>(self, mut assert_same: F) -> <Self as Iterator>::Item
334
5.06k
    where
335
5.06k
        F: for<'a, 'b> FnMut(&'a Self::Item, &'b Self::Item),
336
5.06k
    {
337
5.06k
        self.enumerate()
338
10.1k
            .reduce(|(i, lhs), (j, rhs)| {
339
10.1k
                let panic = {
340
10.1k
                    let mut assert_same = std::panic::AssertUnwindSafe(&mut assert_same);
341
10.1k
                    let lhs = std::panic::AssertUnwindSafe(&lhs);
342
10.1k
                    let rhs = std::panic::AssertUnwindSafe(&rhs);
343
10.1k
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}>::{closure#0}::{closure#0}
Line
Count
Source
343
1.27k
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}>::{closure#0}::{closure#0}
Line
Count
Source
343
1.27k
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
<core::iter::adapters::map::Map<core::slice::iter::Iter<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#3}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<buf_independent::test_data::{closure#4}>::{closure#0}::{closure#0}
Line
Count
Source
343
7.59k
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
344
10.1k
                };
345
10.1k
                match panic {
346
10.1k
                    Ok(_) => (),
347
0
                    Err(panic) => {
348
0
                        eprintln!("Difference found when comparing item #{i} and #{j}.");
349
0
                        std::panic::resume_unwind(panic);
350
                    }
351
                }
352
10.1k
                (
353
10.1k
                    j, lhs, /* Arbitrary - could just as well return `rhs` */
354
10.1k
                )
355
10.1k
            })
<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}>::{closure#0}
Line
Count
Source
338
1.27k
            .reduce(|(i, lhs), (j, rhs)| {
339
1.27k
                let panic = {
340
1.27k
                    let mut assert_same = std::panic::AssertUnwindSafe(&mut assert_same);
341
1.27k
                    let lhs = std::panic::AssertUnwindSafe(&lhs);
342
1.27k
                    let rhs = std::panic::AssertUnwindSafe(&rhs);
343
1.27k
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
344
1.27k
                };
345
1.27k
                match panic {
346
1.27k
                    Ok(_) => (),
347
0
                    Err(panic) => {
348
0
                        eprintln!("Difference found when comparing item #{i} and #{j}.");
349
0
                        std::panic::resume_unwind(panic);
350
                    }
351
                }
352
1.27k
                (
353
1.27k
                    j, lhs, /* Arbitrary - could just as well return `rhs` */
354
1.27k
                )
355
1.27k
            })
<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}>::{closure#0}
Line
Count
Source
338
1.27k
            .reduce(|(i, lhs), (j, rhs)| {
339
1.27k
                let panic = {
340
1.27k
                    let mut assert_same = std::panic::AssertUnwindSafe(&mut assert_same);
341
1.27k
                    let lhs = std::panic::AssertUnwindSafe(&lhs);
342
1.27k
                    let rhs = std::panic::AssertUnwindSafe(&rhs);
343
1.27k
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
344
1.27k
                };
345
1.27k
                match panic {
346
1.27k
                    Ok(_) => (),
347
0
                    Err(panic) => {
348
0
                        eprintln!("Difference found when comparing item #{i} and #{j}.");
349
0
                        std::panic::resume_unwind(panic);
350
                    }
351
                }
352
1.27k
                (
353
1.27k
                    j, lhs, /* Arbitrary - could just as well return `rhs` */
354
1.27k
                )
355
1.27k
            })
<core::iter::adapters::map::Map<core::slice::iter::Iter<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#3}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<buf_independent::test_data::{closure#4}>::{closure#0}
Line
Count
Source
338
7.59k
            .reduce(|(i, lhs), (j, rhs)| {
339
7.59k
                let panic = {
340
7.59k
                    let mut assert_same = std::panic::AssertUnwindSafe(&mut assert_same);
341
7.59k
                    let lhs = std::panic::AssertUnwindSafe(&lhs);
342
7.59k
                    let rhs = std::panic::AssertUnwindSafe(&rhs);
343
7.59k
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
344
7.59k
                };
345
7.59k
                match panic {
346
7.59k
                    Ok(_) => (),
347
0
                    Err(panic) => {
348
0
                        eprintln!("Difference found when comparing item #{i} and #{j}.");
349
0
                        std::panic::resume_unwind(panic);
350
                    }
351
                }
352
7.59k
                (
353
7.59k
                    j, lhs, /* Arbitrary - could just as well return `rhs` */
354
7.59k
                )
355
7.59k
            })
356
5.06k
            .map(|(_index, item)| item)
<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}>::{closure#1}
Line
Count
Source
356
635
            .map(|(_index, item)| item)
<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}>::{closure#1}
Line
Count
Source
356
635
            .map(|(_index, item)| item)
<core::iter::adapters::map::Map<core::slice::iter::Iter<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#3}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<buf_independent::test_data::{closure#4}>::{closure#1}
Line
Count
Source
356
3.79k
            .map(|(_index, item)| item)
357
5.06k
            .expect("Expecting a non-empty iterator")
358
5.06k
    }
<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<<core::slice::iter::Iter<alloc::vec::Vec<u8>> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}>
Line
Count
Source
333
635
    fn assert_all_items_are_same<F>(self, mut assert_same: F) -> <Self as Iterator>::Item
334
635
    where
335
635
        F: for<'a, 'b> FnMut(&'a Self::Item, &'b Self::Item),
336
635
    {
337
635
        self.enumerate()
338
635
            .reduce(|(i, lhs), (j, rhs)| {
339
                let panic = {
340
                    let mut assert_same = std::panic::AssertUnwindSafe(&mut assert_same);
341
                    let lhs = std::panic::AssertUnwindSafe(&lhs);
342
                    let rhs = std::panic::AssertUnwindSafe(&rhs);
343
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
344
                };
345
                match panic {
346
                    Ok(_) => (),
347
                    Err(panic) => {
348
                        eprintln!("Difference found when comparing item #{i} and #{j}.");
349
                        std::panic::resume_unwind(panic);
350
                    }
351
                }
352
                (
353
                    j, lhs, /* Arbitrary - could just as well return `rhs` */
354
                )
355
635
            })
356
635
            .map(|(_index, item)| item)
357
635
            .expect("Expecting a non-empty iterator")
358
635
    }
<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<<alloc::vec::into_iter::IntoIter<png::decoder::OutputInfo> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_equal::{closure#0}>
Line
Count
Source
333
635
    fn assert_all_items_are_same<F>(self, mut assert_same: F) -> <Self as Iterator>::Item
334
635
    where
335
635
        F: for<'a, 'b> FnMut(&'a Self::Item, &'b Self::Item),
336
635
    {
337
635
        self.enumerate()
338
635
            .reduce(|(i, lhs), (j, rhs)| {
339
                let panic = {
340
                    let mut assert_same = std::panic::AssertUnwindSafe(&mut assert_same);
341
                    let lhs = std::panic::AssertUnwindSafe(&lhs);
342
                    let rhs = std::panic::AssertUnwindSafe(&rhs);
343
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
344
                };
345
                match panic {
346
                    Ok(_) => (),
347
                    Err(panic) => {
348
                        eprintln!("Difference found when comparing item #{i} and #{j}.");
349
                        std::panic::resume_unwind(panic);
350
                    }
351
                }
352
                (
353
                    j, lhs, /* Arbitrary - could just as well return `rhs` */
354
                )
355
635
            })
356
635
            .map(|(_index, item)| item)
357
635
            .expect("Expecting a non-empty iterator")
358
635
    }
<core::iter::adapters::map::Map<core::slice::iter::Iter<png::decoder::Reader<std::io::buffered::bufreader::BufReader<alloc::boxed::Box<dyn buf_independent::BufReadSeek>>>>, buf_independent::test_data::{closure#3}> as buf_independent::IteratorExtensionsForFuzzing>::assert_all_items_are_same::<buf_independent::test_data::{closure#4}>
Line
Count
Source
333
3.79k
    fn assert_all_items_are_same<F>(self, mut assert_same: F) -> <Self as Iterator>::Item
334
3.79k
    where
335
3.79k
        F: for<'a, 'b> FnMut(&'a Self::Item, &'b Self::Item),
336
3.79k
    {
337
3.79k
        self.enumerate()
338
3.79k
            .reduce(|(i, lhs), (j, rhs)| {
339
                let panic = {
340
                    let mut assert_same = std::panic::AssertUnwindSafe(&mut assert_same);
341
                    let lhs = std::panic::AssertUnwindSafe(&lhs);
342
                    let rhs = std::panic::AssertUnwindSafe(&rhs);
343
                    std::panic::catch_unwind(move || assert_same(*lhs, *rhs))
344
                };
345
                match panic {
346
                    Ok(_) => (),
347
                    Err(panic) => {
348
                        eprintln!("Difference found when comparing item #{i} and #{j}.");
349
                        std::panic::resume_unwind(panic);
350
                    }
351
                }
352
                (
353
                    j, lhs, /* Arbitrary - could just as well return `rhs` */
354
                )
355
3.79k
            })
356
3.79k
            .map(|(_index, item)| item)
357
3.79k
            .expect("Expecting a non-empty iterator")
358
3.79k
    }
359
}
360
361
impl<T> IteratorExtensionsForFuzzing for T where T: Iterator + Sized {}