From ea6e2a8d80b5c00b5edf117b6de6d767106b9378 Mon Sep 17 00:00:00 2001 From: Lilith River Date: Tue, 7 Apr 2026 08:41:16 -0600 Subject: [PATCH] feat: add decode_comprehensive fuzz target with safe metadata probing New fuzz target exercises TiffHeader::parse, dimensions/colortype probing, chunk-by-chunk reading, and multi-IFD iteration. Guards get_chunk_type/chunk_dimensions behind dimensions() success check to avoid documented panics on non-image IFDs. --- fuzz/Cargo.toml | 6 +++ fuzz/fuzz_targets/decode_comprehensive.rs | 50 +++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 fuzz/fuzz_targets/decode_comprehensive.rs diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index f971d29..90325f2 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -23,3 +23,9 @@ name = "decode_image" path = "fuzz_targets/decode_image.rs" test = false doc = false + +[[bin]] +name = "decode_comprehensive" +path = "fuzz_targets/decode_comprehensive.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/decode_comprehensive.rs b/fuzz/fuzz_targets/decode_comprehensive.rs new file mode 100644 index 0000000..b0920bc --- /dev/null +++ b/fuzz/fuzz_targets/decode_comprehensive.rs @@ -0,0 +1,50 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: &[u8]| { + let cursor = std::io::Cursor::new(data); + + // Path 1: TiffHeader::parse (probe) + { + let _ = tiff::decoder::TiffHeader::parse(std::io::Cursor::new(data)); + } + + // Path 2: Full decode with strict limits + let mut decoder = match tiff::decoder::Decoder::open(cursor) { + Ok(d) => d, + Err(_) => return, + }; + + let mut limits = tiff::decoder::Limits::default(); + limits.decoding_buffer_size = 512 * 1024; + limits.ifd_value_size = 64 * 1024; + limits.intermediate_buffer_size = 512 * 1024; + + decoder = decoder.with_limits(limits); + + // Probe metadata — dimensions() triggers image validation, + // must succeed before get_chunk_type/chunk_dimensions (they unwrap image) + let dims_ok = decoder.dimensions().is_ok(); + let _ = decoder.colortype(); + if dims_ok { + let _ = decoder.get_chunk_type(); + let _ = decoder.chunk_dimensions(); + } + let _ = decoder.more_images(); + + // Read chunks individually if available + let _ = decoder.read_chunk(0); + + // Read full image + let _ = decoder.read_image(); + + // Iterate through all IFDs + while decoder.more_images() { + if decoder.next_image().is_err() { + break; + } + let _ = decoder.dimensions(); + let _ = decoder.colortype(); + let _ = decoder.read_image(); + } +});