4343#include < ImfDeepFrameBuffer.h>
4444#include < ImfTileDescriptionAttribute.h>
4545#include < ImfPartType.h>
46+ #include < ImfCompositeDeepScanLine.h>
47+ #include < ImfTiledMisc.h>
48+ #include < ImfCompressor.h>
4649
4750namespace IMF = OPENEXR_IMF_NAMESPACE ;
4851
4952namespace {
5053
54+ using IMATH_NAMESPACE ::Box2i;
55+
56+ //
57+ // Match ImfCheckFile.cpp limits used when reduceMemory or reduceTime is true
58+ // (runChecks and readMultiPart).
59+ //
60+ constexpr int kMaxImageWidth = 2048 ;
61+ constexpr int kMaxImageHeight = 2048 ;
62+ constexpr int kMaxTileWidth = 512 ;
63+ constexpr int kMaxTileHeight = 512 ;
64+ constexpr uint64_t kMaxDeepSamples = 1ULL << 20 ;
65+
66+ constexpr uint64_t kMaxBytesPerScanline = 8000000 ;
67+ constexpr uint64_t kMaxTileBytesPerScanline = 8000000 ;
68+ constexpr uint64_t kMaxTileBytes = 1000 * 1000 ;
69+
5170constexpr size_t kMaxInput = 4 * 1024 * 1024 ;
5271constexpr int kMaxTilesPerCall = 16 ;
5372constexpr int kMaxParts = 8 ;
@@ -56,6 +75,68 @@ constexpr int kMaxParts = 8;
5675// boundary and small-range cases without burning iteration time.
5776constexpr int kMaxRangeSide = 8 ;
5877
78+ void
79+ apply_fuzz_limits ()
80+ {
81+ static bool limits_applied = false ;
82+ if (limits_applied) return ;
83+ limits_applied = true ;
84+
85+ IMF::CompositeDeepScanLine::setMaximumSampleCount (kMaxDeepSamples );
86+ IMF::Header::setMaxImageSize (kMaxImageWidth , kMaxImageHeight );
87+ IMF::Header::setMaxTileSize (kMaxTileWidth , kMaxTileHeight );
88+ }
89+
90+ //
91+ // Return true if readMultiPart would skip pixel I/O for this part with
92+ // reduceMemory enabled (wide scanline groups or oversized tiles).
93+ //
94+ bool
95+ part_exceeds_memory_limits (const IMF ::Header& hdr)
96+ {
97+ const Box2i& b = hdr.dataWindow ();
98+ const int bytesPerPixel =
99+ static_cast <int > (IMF::calculateBytesPerPixel (hdr));
100+ const uint64_t imageWidth =
101+ static_cast <uint64_t > (b.max .x - b.min .x + 1 );
102+ const uint64_t scanlinesInBuffer =
103+ static_cast <uint64_t > (IMF::numLinesInBuffer (hdr.compression ()));
104+
105+ if (imageWidth * static_cast <uint64_t > (bytesPerPixel) * scanlinesInBuffer >
106+ kMaxBytesPerScanline )
107+ {
108+ return true ;
109+ }
110+
111+ if (!hdr.hasTileDescription ()) return false ;
112+
113+ const IMF ::TileDescription& td = hdr.tileDescription ();
114+ const uint64_t tilesPerScanline =
115+ (imageWidth + static_cast <uint64_t > (td.xSize ) - 1 ) /
116+ static_cast <uint64_t > (td.xSize );
117+ uint64_t tileSize = static_cast <uint64_t > (td.xSize ) *
118+ static_cast <uint64_t > (td.ySize );
119+
120+ if (tileSize * tilesPerScanline *
121+ static_cast <uint64_t > (bytesPerPixel) >
122+ kMaxTileBytesPerScanline )
123+ {
124+ return true ;
125+ }
126+
127+ if (hdr.hasType () && hdr.type () == IMF ::DEEPTILE )
128+ {
129+ tileSize *= std::max (
130+ static_cast <size_t > (bytesPerPixel), sizeof (unsigned int ));
131+ }
132+ else
133+ {
134+ tileSize *= static_cast <uint64_t > (bytesPerPixel);
135+ }
136+
137+ return tileSize > kMaxTileBytes ;
138+ }
139+
59140std::string write_temp (const uint8_t * data, size_t size)
60141{
61142 char path[] = " /tmp/exr_gaps_XXXXXX" ;
@@ -110,6 +191,7 @@ test_tiled_random_coords (
110191 // deep tiled. MultiPartInputFile auto-synthesizes a "type"
111192 // attribute, so we must check the value rather than presence.
112193 if (hdr.hasType () && hdr.type () == IMF ::DEEPTILE ) continue ;
194+ if (part_exceeds_memory_limits (hdr)) continue ;
113195 try
114196 {
115197 IMF ::TiledInputPart tip (mpif, p);
@@ -157,6 +239,7 @@ test_tiled_range (
157239 {
158240 const IMF ::Header& hdr = mpif.header (p);
159241 if (!hdr.hasTileDescription ()) continue ;
242+ if (part_exceeds_memory_limits (hdr)) continue ;
160243 try
161244 {
162245 IMF ::TiledInputPart tip (mpif, p);
@@ -203,6 +286,7 @@ test_deep_tiled (
203286 const IMF ::Header& hdr = mpif.header (p);
204287 // DeepTiledInputPart only accepts deep tiled parts.
205288 if (!hdr.hasType () || hdr.type () != IMF ::DEEPTILE ) continue ;
289+ if (part_exceeds_memory_limits (hdr)) continue ;
206290 try
207291 {
208292 IMF ::DeepTiledInputPart dtip (mpif, p);
@@ -271,6 +355,8 @@ test_part_iteration (
271355
272356extern " C" int LLVMFuzzerTestOneInput (const uint8_t * data, size_t size)
273357{
358+ apply_fuzz_limits ();
359+
274360 if (size < 4 || size > kMaxInput ) return 0 ;
275361
276362 uint8_t mode = data[0 ] % 4 ;
0 commit comments