Skip to content

Commit f448690

Browse files
authored
Impose memory limits in openexr_exrgaps_fuzzer (#2419)
This applies the memory limits in effect in `openexr_exrcheck_fuzzer` to the new `openexr_exrgaps_fuzzer`. Without the limits, the fuzzer can generate test case images that are valid but exceed the limits of the fuzzing environment. Addresses https://issues.oss-fuzz.com/issues/513282267 Addresses https://issues.oss-fuzz.com/issues/512988066 Made-with: Cursor Signed-off-by: Cary Phillips <cary@ilm.com>
1 parent 227656e commit f448690

1 file changed

Lines changed: 86 additions & 0 deletions

File tree

src/test/oss-fuzz/openexr_exrgaps_fuzzer.cc

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,30 @@
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

4750
namespace IMF = OPENEXR_IMF_NAMESPACE;
4851

4952
namespace {
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+
5170
constexpr size_t kMaxInput = 4 * 1024 * 1024;
5271
constexpr int kMaxTilesPerCall = 16;
5372
constexpr int kMaxParts = 8;
@@ -56,6 +75,68 @@ constexpr int kMaxParts = 8;
5675
// boundary and small-range cases without burning iteration time.
5776
constexpr 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+
59140
std::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

272356
extern "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

Comments
 (0)