Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ImfCheckFile and oss-fuzz tests #1257

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/lib/OpenEXR/ImfHeader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,21 @@ Header::setMaxTileSize (int maxWidth, int maxHeight)
maxTileHeight = maxHeight;
}

void
Header::getMaxImageSize (int& maxWidth, int& maxHeight)
{
maxWidth = maxImageWidth;
maxHeight = maxImageHeight;
}

void
Header::getMaxTileSize (int& maxWidth, int& maxHeight)
{
maxWidth = maxTileWidth;
maxHeight= maxTileHeight;
}


bool
Header::readsNothing ()
{
Expand Down
5 changes: 5 additions & 0 deletions src/lib/OpenEXR/ImfHeader.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,11 @@ class IMF_EXPORT_TYPE Header
static void setMaxImageSize (int maxWidth, int maxHeight);
IMF_EXPORT
static void setMaxTileSize (int maxWidth, int maxHeight);
IMF_EXPORT
static void getMaxImageSize (int& maxWidth, int& maxHeight);
IMF_EXPORT
static void getMaxTileSize (int& maxWidth, int& maxHeight);


//
// Check if the header reads nothing.
Expand Down
99 changes: 45 additions & 54 deletions src/lib/OpenEXRUtil/ImfCheckFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,11 +565,6 @@ readDeepTile (T& in, bool reduceMemory, bool reduceTime)

Box2i dataWindow = fileHeader.dataWindow ();

//
// use uint64_t for dimensions, since dataWindow+1 could overflow int storage
//
uint64_t height = static_cast<uint64_t> (dataWindow.size ().y) + 1;
uint64_t width = static_cast<uint64_t> (dataWindow.size ().x) + 1;
int bytesPerSample = calculateBytesPerPixel (in.header ());

const TileDescription& td = in.header ().tileDescription ();
Expand Down Expand Up @@ -1030,6 +1025,30 @@ template <class T>
bool
runChecks (T& source, bool reduceMemory, bool reduceTime)
{

//
// in reduceMemory/reduceTime mode, limit image size, tile size, and maximum deep samples
//

uint64_t oldMaxSampleCount = CompositeDeepScanLine::getMaximumSampleCount();

int maxImageWidth , maxImageHeight;
Header::getMaxImageSize(maxImageWidth,maxImageHeight);

int maxTileWidth , maxTileHeight;
Header::getMaxImageSize(maxTileWidth,maxTileHeight);


if( reduceMemory || reduceTime)
{
CompositeDeepScanLine::setMaximumSampleCount(1<<20);
Header::setMaxImageSize(2048,2048);
Header::setMaxTileSize(512,512);
}




//
// multipart test: also grab the type of the first part to
// check which other tests are expected to fail
Expand All @@ -1048,7 +1067,6 @@ runChecks (T& source, bool reduceMemory, bool reduceTime)
// If the MultiPartInputFile constructor throws an exception, the first part
// will assumed to be a wide image
//
bool firstPartWide = true;
bool largeTiles = true;

bool threw = false;
Expand All @@ -1057,17 +1075,6 @@ runChecks (T& source, bool reduceMemory, bool reduceTime)
{
MultiPartInputFile multi (source);
Box2i b = multi.header (0).dataWindow ();
uint64_t imageWidth = static_cast<uint64_t> (b.max.x) -
static_cast<uint64_t> (b.min.x) + 1ll;
uint64_t bytesPerPixel = calculateBytesPerPixel (multi.header (0));
uint64_t numLines =
numLinesInBuffer (multi.header (0).compression ());

// confirm first part is small enough to read without using excessive memory
if (imageWidth * bytesPerPixel * numLines <= gMaxBytesPerScanline)
{
firstPartWide = false;
}

//
// significant memory is also required to read a tiled file
Expand All @@ -1080,18 +1087,10 @@ runChecks (T& source, bool reduceMemory, bool reduceTime)
{
const TileDescription& tileDescription =
multi.header (0).tileDescription ();
uint64_t tilesPerScanline =
(imageWidth + tileDescription.xSize - 1ll) /
tileDescription.xSize;
uint64_t tileSize =
static_cast<uint64_t> (tileDescription.xSize) *
static_cast<uint64_t> (tileDescription.ySize);
int bytesPerPixel = calculateBytesPerPixel (multi.header (0));
if (tileSize * tilesPerScanline * bytesPerPixel >
gMaxTileBytesPerScanline)
{
firstPartWide = true;
}

if (tileSize * bytesPerPixel <= gMaxTileBytes)
{
Expand All @@ -1115,7 +1114,7 @@ runChecks (T& source, bool reduceMemory, bool reduceTime)
}

// read using both scanline interfaces (unless the image is wide and reduce memory enabled)
if (!reduceMemory || !firstPartWide)
if (!reduceMemory)
{
{
bool gotThrow = false;
Expand Down Expand Up @@ -1163,7 +1162,7 @@ runChecks (T& source, bool reduceMemory, bool reduceTime)
if (gotThrow && firstPartType == TILEDIMAGE) { threw = true; }
}

if (!reduceMemory || !firstPartWide)
if (!reduceMemory)
{
bool gotThrow = false;
resetInput (source);
Expand Down Expand Up @@ -1195,6 +1194,12 @@ runChecks (T& source, bool reduceMemory, bool reduceTime)
if (gotThrow && firstPartType == DEEPTILE) { threw = true; }
}



CompositeDeepScanLine::setMaximumSampleCount(oldMaxSampleCount);
Header::setMaxImageSize(maxImageWidth,maxImageHeight);
Header::setMaxTileSize(maxTileWidth,maxTileHeight);

return threw;
}

Expand Down Expand Up @@ -1621,26 +1626,18 @@ checkOpenEXRFile (
const char* fileName,
bool reduceMemory,
bool reduceTime,
bool enableCoreCheck)
bool runCoreCheck)
{
bool threw = false;

uint64_t oldMaxSampleCount = CompositeDeepScanLine::getMaximumSampleCount();

if( reduceMemory || reduceTime)
if (runCoreCheck)
{
CompositeDeepScanLine::setMaximumSampleCount(1<<20);
return runCoreChecks (fileName, reduceMemory, reduceTime);
}

if (enableCoreCheck)
else
{
threw = runCoreChecks (fileName, reduceMemory, reduceTime);
return runChecks (fileName, reduceMemory, reduceTime);
}
if (!threw) threw = runChecks (fileName, reduceMemory, reduceTime);

CompositeDeepScanLine::setMaximumSampleCount(oldMaxSampleCount);

return threw;
}

bool
Expand All @@ -1649,27 +1646,21 @@ checkOpenEXRFile (
size_t numBytes,
bool reduceMemory,
bool reduceTime,
bool enableCoreCheck)
bool runCoreCheck)
{
bool threw = false;
uint64_t oldMaxSampleCount = CompositeDeepScanLine::getMaximumSampleCount();

if( reduceMemory || reduceTime)
{
CompositeDeepScanLine::setMaximumSampleCount(1<<20);
}

if (enableCoreCheck)
threw = runCoreChecks (data, numBytes, reduceMemory, reduceTime);
if (!threw)
{
if (runCoreCheck)
{
return runCoreChecks (data, numBytes, reduceMemory, reduceTime);
}
else
{
PtrIStream stream (data, numBytes);
threw = runChecks (stream, reduceMemory, reduceTime);
return runChecks (stream, reduceMemory, reduceTime);
}

CompositeDeepScanLine::setMaximumSampleCount(oldMaxSampleCount);

return threw;
}

OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
5 changes: 3 additions & 2 deletions src/lib/OpenEXRUtil/ImfCheckFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
// if reduceTime is true and an error is found within the file, then future tests are reduced for speed.
// This may hide errors within the library.
//
// if runCoreCheck is true, only uses the OpenEXRCore (C) API, otherwise uses the OpenEXR (C++) API
//

IMFUTIL_EXPORT bool checkOpenEXRFile (
const char* fileName,
bool reduceMemory = false,
bool reduceTime = false,
bool enableCoreCheck = false);
bool runCoreCheck = false);

//
// overloaded version of checkOpenEXRFile that takes a pointer to in-memory data
Expand All @@ -42,7 +43,7 @@ IMFUTIL_EXPORT bool checkOpenEXRFile (
size_t numBytes,
bool reduceMemory = false,
bool reduceTime = false,
bool enableCoreCheck = false);
bool runCoreCheck = false);

OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
using OPENEXR_IMF_NAMESPACE::checkOpenEXRFile;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
checkOpenEXRFile ((const char*) data , size , true , true, true);
checkOpenEXRFile ((const char*) data , size , true , true, false);
return 0;
}

20 changes: 20 additions & 0 deletions src/test/OpenEXRFuzzTest/oss-fuzz/openexr_exrcorecheck_fuzzer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

//
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) Contributors to the OpenEXR Project.
//
// this file is found by the oss-fuzz project to generate a fuzzer. It is not part of
// OpenEXR's internal OpenEXRFuzzTest suite
//

#include <ImfNamespace.h>
#include <ImfCheckFile.h>
#include <stdint.h>

using OPENEXR_IMF_NAMESPACE::checkOpenEXRFile;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
checkOpenEXRFile ((const char*) data , size , true , true, true);
return 0;
}