Skip to content
Open
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
54 changes: 39 additions & 15 deletions projects/opencv/core_fuzzer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <cstddef>
#include <cstdint>
#include <algorithm>

#include <opencv2/opencv.hpp>
#include <fuzzer/FuzzedDataProvider.h>
Expand All @@ -23,37 +24,56 @@ namespace {
bool GetCVImage(const std::string& image_string, const int max_pixels,
cv::Mat* original_image) {
if (image_string.empty()) return false;

// Limit input size to prevent OOM
if (max_pixels > 0 && image_string.size() > static_cast<size_t>(max_pixels) * 3) {
// Rough estimate: assume up to 3 bytes per pixel for color images
return false;
}

std::vector<uchar> raw_data(image_string.size());
const char* ptr = image_string.data();
std::copy(ptr, ptr + image_string.size(), raw_data.data());
try {
*original_image = cv::imdecode(raw_data, cv::IMREAD_UNCHANGED);
} catch (cv::Exception e) {}

// Check if decoded image exceeds max_pixels limit
if (max_pixels > 0 && !original_image->empty()) {
int total_pixels = original_image->rows * original_image->cols;
if (total_pixels > max_pixels) {
original_image->release();
return false;
}
}
} catch (cv::Exception& e) {
// Explicitly return false on exception
return false;
}
return !original_image->empty();
}

void TestExternalMethods(const cv::Mat& mat) {
try{
cv::sum(mat);
} catch (cv::Exception e) {}
} catch (cv::Exception& e) {}
try {
cv::mean(mat);
} catch (cv::Exception e) {}
} catch (cv::Exception& e) {}
try {
cv::trace(mat);
} catch (cv::Exception e) {}
} catch (cv::Exception& e) {}
}

void TestInternalMethods(const cv::Mat& mat) {
try {
mat.t();
} catch (cv::Exception e) {}
} catch (cv::Exception& e) {}
try {
mat.inv();
} catch (cv::Exception e) {}
} catch (cv::Exception& e) {}
try {
mat.diag();
} catch (cv::Exception e) {}
} catch (cv::Exception& e) {}
}

void TestSplitAndMerge(const cv::Mat& image) {
Expand All @@ -68,25 +88,29 @@ void TestSplitAndMerge(const cv::Mat& image) {
} // namespace

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Prepares a backup image we will use if we cannot successfully get an image
// by decoding the string.
std::vector<uint8_t> image_data = {data, data + size};
FuzzedDataProvider fuzzed_data_provider(data, size);

// Consume max_pixels with reasonable bounds
int max_pixels = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 1000000);

// Limit backup image size using max_pixels
size_t backup_size = std::min(size, static_cast<size_t>(max_pixels));
std::vector<uint8_t> image_data(data, data + backup_size);
cv::Mat backup_image =
cv::Mat(1, image_data.size(), CV_8UC1, image_data.data());

FuzzedDataProvider fuzzed_data_provider(data, size);
const int max_pixels = fuzzed_data_provider.ConsumeIntegral<int>();
const std::string image_string =
fuzzed_data_provider.ConsumeRemainingBytesAsString();
cv::Mat original_image;

// Tests the clone method.
cv::Mat cloned_image = GetCVImage(image_string, max_pixels, &original_image)
? original_image.clone()
: backup_image.clone();

// TODO: enabling the following crashes right away.
// TestExternalMethods(cloned_image);
// Test all methods - catch exceptions to prevent crashes
TestExternalMethods(cloned_image);
TestInternalMethods(cloned_image);
TestSplitAndMerge(cloned_image);
return 0;
}
}
Loading