| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #include <fcntl.h> |
| #include <inttypes.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <libhfuzz/libhfuzz.h> |
| |
| #include "png.h" |
| #include "pngpriv.h" |
| #include "pngstruct.h" |
| |
| #if defined(__clang__) |
| #if __has_feature(memory_sanitizer) |
| #include <sanitizer/msan_interface.h> |
| #endif /* __has_feature(memory_sanitizer) */ |
| #endif /* defined(__clang__) */ |
| |
| void fatal(const char* s, ...) |
| { |
| va_list args; |
| va_start(args, s); |
| vfprintf(stderr, s, args); |
| fprintf(stderr, "\n"); |
| va_end(args); |
| _exit(EXIT_FAILURE); |
| } |
| |
| typedef struct { |
| const uint8_t* ptr; |
| size_t len; |
| size_t off; |
| } user_file_t; |
| |
| size_t total_alloc = 0ULL; |
| int null_fd = -1; |
| |
| void png_user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) |
| { |
| #if defined(__clang__) |
| #if __has_feature(memory_sanitizer) |
| __msan_poison(data, length); |
| #endif /* __has_feature(memory_sanitizer) */ |
| #endif /* defined(__clang__) */ |
| |
| user_file_t* f = (user_file_t*)png_ptr->io_ptr; |
| |
| if (length > f->len) { |
| png_error(png_ptr, "Read Error"); |
| return; |
| } |
| memcpy(data, &f->ptr[f->off], length); |
| f->len -= length; |
| f->off += length; |
| } |
| |
| int LLVMFuzzerInitialize(int* argc, char*** argv) |
| { |
| null_fd = open("/dev/null", O_WRONLY); |
| return 0; |
| } |
| |
| int LLVMFuzzerTestOneInput(const uint8_t* buf, size_t len) |
| { |
| png_structp png_ptr = NULL; |
| png_infop info_ptr = NULL; |
| |
| total_alloc = 0ULL; |
| png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
| if (!png_ptr) { |
| fatal("png_create_read_struct"); |
| } |
| |
| info_ptr = png_create_info_struct(png_ptr); |
| if (!info_ptr) { |
| png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); |
| fatal("png_create_info_struct()"); |
| } |
| |
| if (setjmp(png_jmpbuf(png_ptr))) { |
| png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
| return 0; |
| } |
| |
| png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); |
| png_set_user_limits(png_ptr, 10000U, 10000U); |
| png_set_chunk_cache_max(png_ptr, 1024ULL * 1024ULL * 64ULL); |
| png_set_chunk_malloc_max(png_ptr, 1024ULL * 1024ULL * 128ULL); |
| |
| user_file_t f = { |
| .ptr = buf, |
| .len = len, |
| .off = 0UL, |
| }; |
| png_set_read_fn(png_ptr, (void*)&f, png_user_read_data); |
| |
| png_read_png(png_ptr, info_ptr, ~(0), NULL); |
| |
| png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); |
| png_uint_32 row_bytes = png_get_rowbytes(png_ptr, info_ptr); |
| png_uint_32 height = png_get_image_height(png_ptr, info_ptr); |
| |
| for (png_uint_32 i = 0; i < height; i++) { |
| write(null_fd, row_pointers[i], row_bytes); |
| } |
| |
| /* Addtional API calls */ |
| png_uint_32 width, ret, res_x, res_y; |
| double file_gamma; |
| png_uint_16p hist; |
| int bit_depth, color_type, interlace_method, compression_method, filter_method, unit_type, num_palette, num_text; |
| png_textp text_ptr; |
| png_colorp palette; |
| png_timep mod_time; |
| png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, |
| &compression_method, &filter_method); |
| ret = png_get_gAMA(png_ptr, info_ptr, &file_gamma); |
| ret = png_get_hIST(png_ptr, info_ptr, &hist); |
| ret = png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type); |
| ret = png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); |
| ret = png_get_text(png_ptr, info_ptr, &text_ptr, &num_text); |
| ret = png_get_tIME(png_ptr, info_ptr, &mod_time); |
| png_voidp vp = png_get_progressive_ptr(png_ptr); |
| |
| png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
| |
| return 0; |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |