Coverage Report

Created: 2025-08-25 06:49

/src/image/fuzz/fuzzers/fuzzer_script_exr.rs
Line
Count
Source (jump to first uncovered line)
1
#![no_main]
2
#[macro_use]
3
extern crate libfuzzer_sys;
4
extern crate image;
5
6
use image::codecs::openexr::*;
7
use image::Limits;
8
use image::ExtendedColorType;
9
use image::ImageDecoder;
10
use image::ImageEncoder;
11
use image::ImageResult;
12
use std::io::{BufRead, Cursor, Seek, Write};
13
14
// "just dont panic"
15
41
fn roundtrip(bytes: &[u8]) -> ImageResult<()> {
16
    /// Read the file from the specified path into an `Rgba32FImage`.
17
    // TODO this method should probably already exist in the main image crate
18
54
    fn read_as_rgba_byte_image(read: impl BufRead + Seek) -> ImageResult<(u32, u32, Vec<u8>)> {
19
54
        let mut decoder = OpenExrDecoder::with_alpha_preference(read, Some(true))?;
20
38
        match usize::try_from(decoder.total_bytes()) {
21
38
            Ok(decoded_size) if decoded_size <= 256 * 1024 * 1024 => {
22
38
                decoder.set_limits(Limits::default())?;
23
38
                let (width, height) = decoder.dimensions();
24
38
                let mut buffer = vec![0; decoded_size];
25
38
                decoder.read_image(buffer.as_mut_slice())?;
26
26
                Ok((width, height, buffer))
27
            }
28
0
            _ => Err(image::ImageError::Limits(
29
0
                image::error::LimitError::from_kind(
30
0
                    image::error::LimitErrorKind::InsufficientMemory,
31
0
                ),
32
0
            )),
33
        }
34
54
    }
fuzzer_script_exr::roundtrip::read_as_rgba_byte_image::<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
Line
Count
Source
18
13
    fn read_as_rgba_byte_image(read: impl BufRead + Seek) -> ImageResult<(u32, u32, Vec<u8>)> {
19
13
        let mut decoder = OpenExrDecoder::with_alpha_preference(read, Some(true))?;
20
13
        match usize::try_from(decoder.total_bytes()) {
21
13
            Ok(decoded_size) if decoded_size <= 256 * 1024 * 1024 => {
22
13
                decoder.set_limits(Limits::default())?;
23
13
                let (width, height) = decoder.dimensions();
24
13
                let mut buffer = vec![0; decoded_size];
25
13
                decoder.read_image(buffer.as_mut_slice())?;
26
13
                Ok((width, height, buffer))
27
            }
28
0
            _ => Err(image::ImageError::Limits(
29
0
                image::error::LimitError::from_kind(
30
0
                    image::error::LimitErrorKind::InsufficientMemory,
31
0
                ),
32
0
            )),
33
        }
34
13
    }
fuzzer_script_exr::roundtrip::read_as_rgba_byte_image::<std::io::cursor::Cursor<&[u8]>>
Line
Count
Source
18
41
    fn read_as_rgba_byte_image(read: impl BufRead + Seek) -> ImageResult<(u32, u32, Vec<u8>)> {
19
41
        let mut decoder = OpenExrDecoder::with_alpha_preference(read, Some(true))?;
20
25
        match usize::try_from(decoder.total_bytes()) {
21
25
            Ok(decoded_size) if decoded_size <= 256 * 1024 * 1024 => {
22
25
                decoder.set_limits(Limits::default())?;
23
25
                let (width, height) = decoder.dimensions();
24
25
                let mut buffer = vec![0; decoded_size];
25
25
                decoder.read_image(buffer.as_mut_slice())?;
26
13
                Ok((width, height, buffer))
27
            }
28
0
            _ => Err(image::ImageError::Limits(
29
0
                image::error::LimitError::from_kind(
30
0
                    image::error::LimitErrorKind::InsufficientMemory,
31
0
                ),
32
0
            )),
33
        }
34
41
    }
35
36
    /// Write an `Rgba32FImage`.
37
    /// Assumes the writer is buffered. In most cases,
38
    /// you should wrap your writer in a `BufWriter` for best performance.
39
    // TODO this method should probably already exist in the main image crate
40
13
    fn write_rgba_image(
41
13
        write: impl Write + Seek,
42
13
        (width, height, data): &(u32, u32, Vec<u8>),
43
13
    ) -> ImageResult<()> {
44
13
        OpenExrEncoder::new(write).write_image(
45
13
            data.as_slice(),
46
13
            *width,
47
13
            *height,
48
13
            ExtendedColorType::Rgba32F,
49
13
        )
50
13
    }
51
52
41
    let decoded_image = read_as_rgba_byte_image(Cursor::new(bytes))?;
53
54
    #[allow(clippy::disallowed_methods)]
55
13
    let mut bytes = Vec::with_capacity(bytes.len() + 20);
56
13
    write_rgba_image(Cursor::new(&mut bytes), &decoded_image)?;
57
58
13
    let redecoded_image = read_as_rgba_byte_image(Cursor::new(bytes))?;
59
60
    // if both images are valid, assert read/write consistency
61
13
    assert_eq!(
62
        decoded_image, redecoded_image,
63
0
        "image was valid but was not reproducible"
64
    );
65
13
    Ok(())
66
41
}
67
68
fuzz_target!(|data: &[u8]| {
69
    let _img = roundtrip(data); // fixme not optimized away?
70
});