summaryrefslogtreecommitdiff
path: root/libpng/contrib/oss-fuzz/newcc
diff options
context:
space:
mode:
Diffstat (limited to 'libpng/contrib/oss-fuzz/newcc')
-rw-r--r--libpng/contrib/oss-fuzz/newcc190
1 files changed, 190 insertions, 0 deletions
diff --git a/libpng/contrib/oss-fuzz/newcc b/libpng/contrib/oss-fuzz/newcc
new file mode 100644
index 000000000..0fc9e206c
--- /dev/null
+++ b/libpng/contrib/oss-fuzz/newcc
@@ -0,0 +1,190 @@
+
+// libpng_read_fuzzer.cc
+// Copyright 2017 Glenn Randers-Pehrson
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that may
+// be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE
+
+// Last changed in libpng 1.6.33beta03 [September 27, 2017]
+
+// The modifications in 2017 by Glenn Randers-Pehrson include
+// 1. addition of a PNG_CLEANUP macro,
+// 2. setting the option to ignore ADLER32 checksums,
+// 3. adding "#include <string.h>" which is needed on some platforms
+// to provide memcpy().
+// 4. adding read_end_info() and creating an end_info structure.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <vector>
+
+#define PNG_INTERNAL
+#include "png.h"
+
+struct BufState {
+ const uint8_t* data;
+ size_t bytes_left;
+};
+
+struct PngObjectHandler {
+ png_infop info_ptr = nullptr;
+ png_structp png_ptr = nullptr;
+ png_infop end_info_ptr = nullptr;
+ png_voidp row_ptr = nullptr;
+ BufState* buf_state = nullptr;
+
+ ~PngObjectHandler() {
+ if (row_ptr)
+ png_free(png_ptr, row_ptr);
+ if (end_info_ptr)
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);
+ else if (info_ptr)
+ png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
+ else
+ png_destroy_read_struct(&png_ptr, nullptr, nullptr);
+ delete buf_state;
+ }
+};
+
+void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
+ BufState* buf_state = static_cast<BufState*>(png_get_io_ptr(png_ptr));
+ if (length > buf_state->bytes_left) {
+ png_error(png_ptr, "read error");
+ }
+ memcpy(data, buf_state->data, length);
+ buf_state->bytes_left -= length;
+ buf_state->data += length;
+}
+
+static const int kPngHeaderSize = 8;
+
+// Entry point for LibFuzzer.
+// Roughly follows the libpng book example:
+// http://www.libpng.org/pub/png/book/chapter13.html
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size < kPngHeaderSize) {
+ return 0;
+ }
+
+ std::vector<unsigned char> v(data, data + size);
+ if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) {
+ // not a PNG.
+ return 0;
+ }
+
+ PngObjectHandler png_handler;
+ png_handler.png_ptr = nullptr;
+ png_handler.row_ptr = nullptr;
+ png_handler.info_ptr = nullptr;
+ png_handler.end_info_ptr = nullptr;
+
+ png_handler.png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+ if (!png_handler.png_ptr) {
+ return 0;
+ }
+
+#define PNG_CLEANUP \
+ if(png_handler.png_ptr) \
+ { \
+ if (png_handler.row_ptr) \
+ png_free(png_handler.png_ptr, png_handler.row_ptr); \
+ if (png_handler.end_info_ptr) \
+ png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
+ &png_handler.end_info_ptr); \
+ else if (png_handler.info_ptr) \
+ png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\
+ nullptr); \
+ else \
+ png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \
+ png_handler.png_ptr = nullptr; \
+ png_handler.row_ptr = nullptr; \
+ png_handler.info_ptr = nullptr; \
+ png_handler.end_info_ptr = nullptr; \
+ }
+
+ png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr);
+ if (!png_handler.info_ptr) {
+ PNG_CLEANUP
+ return 0;
+ }
+
+ png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr);
+ if (!png_handler.end_info_ptr) {
+ PNG_CLEANUP
+ return 0;
+ }
+
+ /* Treat benign errors as warnings */
+ png_set_benign_errors(png_handler.png_ptr, 1);
+
+ png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
+
+#ifdef PNG_IGNORE_ADLER32
+ png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
+#endif
+
+ // Setting up reading from buffer.
+ png_handler.buf_state = new BufState();
+ png_handler.buf_state->data = data + kPngHeaderSize;
+ png_handler.buf_state->bytes_left = size - kPngHeaderSize;
+ png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data);
+ png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize);
+
+ if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
+ PNG_CLEANUP
+ return 0;
+ }
+
+ // Reading.
+ png_read_info(png_handler.png_ptr, png_handler.info_ptr);
+ png_read_update_info(png_handler.png_ptr, png_handler.info_ptr);
+ png_handler.row_ptr = png_malloc(
+ png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr,
+ png_handler.info_ptr));
+
+ // reset error handler to put png_deleter into scope.
+ if (setjmp(png_jmpbuf(png_handler.png_ptr))) {
+ PNG_CLEANUP
+ return 0;
+ }
+
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type, compression_type;
+ int filter_type;
+
+ if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width,
+ &height, &bit_depth, &color_type, &interlace_type,
+ &compression_type, &filter_type)) {
+ PNG_CLEANUP
+ return 0;
+ }
+
+ // This is going to be too slow.
+ if (width && height > 100000000 / width) {
+ PNG_CLEANUP
+ return 0;
+ }
+
+ int passes = png_set_interlace_handling(png_handler.png_ptr);
+ png_start_read_image(png_handler.png_ptr);
+
+ /* To do: prevent the optimizer from removing this code entirely */
+ for (int pass = 0; pass < passes; ++pass) {
+ for (png_uint_32 y = 0; y < height; ++y) {
+ png_read_row(png_handler.png_ptr,
+ static_cast<png_bytep>(png_handler.row_ptr), nullptr);
+ }
+ }
+
+ png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);
+
+ PNG_CLEANUP
+
+ /* TO do: exercise the progressive reader here */
+
+ return 0;
+}