| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #include <fcntl.h> |
| #include <setjmp.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <libhfuzz/libhfuzz.h> |
| |
| #include "cderror.h" |
| #include "jpeglib.h" |
| |
| struct jpeg_decompress_struct cinfo; |
| int null_fd = -1; |
| |
| struct jpegErrorManager { |
| struct jpeg_error_mgr pub; |
| jmp_buf setjmp_buffer; |
| }; |
| |
| struct jpegErrorManager jerr; |
| |
| void jpegErrorExit(j_common_ptr cinfo) { |
| struct jpegErrorManager* myerr = (struct jpegErrorManager*)cinfo->err; |
| longjmp(myerr->setjmp_buffer, 1); |
| } |
| |
| static const char* const cdjpeg_message_table[] = { |
| #include "cderror.h" |
| NULL}; |
| |
| static uint64_t max_total_pixels = 1000000000ULL; /* 1G */ |
| int LLVMFuzzerInitialize(int* argc, char*** argv) { |
| null_fd = open("/dev/null", O_WRONLY); |
| |
| cinfo.err = jpeg_std_error(&jerr.pub); |
| jerr.pub.error_exit = jpegErrorExit; |
| |
| jerr.pub.addon_message_table = cdjpeg_message_table; |
| jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE; |
| jerr.pub.last_addon_message = JMSG_LASTADDONCODE; |
| |
| jpeg_create_decompress(&cinfo); |
| |
| /* If there are any arguments provided, limit width*height to this value */ |
| if (*argc > 1) { |
| max_total_pixels = strtoull((*argv)[1], NULL, 0); |
| } |
| return 0; |
| } |
| |
| int LLVMFuzzerTestOneInput(const uint8_t* buf, size_t len) { |
| if (setjmp(jerr.setjmp_buffer)) { |
| goto out; |
| } |
| |
| jpeg_mem_src(&cinfo, buf, len); |
| jpeg_read_header(&cinfo, TRUE); |
| |
| /* Limit total number of pixels to decode to 50M */ |
| uint64_t total_pix = (uint64_t)cinfo.output_height * (uint64_t)cinfo.output_width; |
| if (total_pix > max_total_pixels) { |
| goto out; |
| } |
| |
| cinfo.mem->max_memory_to_use = (1024ULL * 1024ULL * 1024ULL); |
| cinfo.mem->max_alloc_chunk = (1024ULL * 1024ULL * 1024ULL); |
| |
| jpeg_start_decompress(&cinfo); |
| |
| int row_stride = cinfo.output_width * cinfo.output_components; |
| JSAMPARRAY buffer = |
| (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1); |
| while (cinfo.output_scanline < cinfo.output_height) { |
| #if defined(__clang__) |
| #if __has_feature(memory_sanitizer) |
| __msan_poison(buffer[0], row_stride); |
| #endif /* __has_feature(memory_sanitizer) */ |
| #endif /* defined(__clang__) */ |
| jpeg_read_scanlines(&cinfo, buffer, 1); |
| write(null_fd, buffer[0], row_stride); |
| } |
| |
| out: |
| jpeg_abort_decompress(&cinfo); |
| return 0; |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |