libjpeg decode crashes when JPEG data is bad

3.9k views Asked by At

I have some code that uses libjpeg to decode jpeg images in memory, but it crashes sometimes when the input data is bad. I'm not particularly familiar with libjpeg - I just slightly modified some cut&paste code. :) So I'm wondering how I can get it to report and error or something instead of crashing, so that I can just skip the bad image and move on to the next one...

Here's my code: I have one of these std::vector<unsigned char> m_jpegBuffer; and this method:

const IplImage* JpegImageSerializer::getImage()
{
    int offset, row_stride;
    JSAMPROW rowptr[1];
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    memset(&cinfo, 0, sizeof(cinfo));
    memset(&jerr, 0, sizeof(jerr));

    // Initialize the JPEG decompression object with default error handling
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

#ifdef NEED_SIGNAL_CATCHER
    enable_signal_catcher((j_common_ptr) &cinfo); // Now safe to enable signal catcher
#endif

    jpeg_mem_src(&cinfo, &this->m_jpegBuffer[0], this->m_jpegBuffer.size()); // Specify data source for decompression
    jpeg_read_header(&cinfo, TRUE); // Read file header, set default decompression parameters
    jpeg_start_decompress(&cinfo); // Start decompressor

    IplImage* pImage = cvCreateImage(cvSize(cinfo.image_width, cinfo.image_height),
                                                                     IPL_DEPTH_8U, 3);

    // Process data
    offset = 0;
    row_stride = cinfo.image_width * 3;
    while(cinfo.output_scanline < cinfo.output_height)
    {
        rowptr[0] = (JSAMPROW) &pImage->imageData[offset * row_stride];
        jpeg_read_scanlines(&cinfo, rowptr, 1);
        ++offset;
    }

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    return pImage;
}

Here are some examples of the output when it crashes. These log messages are not from my code - libjpeg itself must be printing these.

Premature end of JPEG file
Premature end of JPEG file
Corrupt JPEG data: premature end of data segment
Unsupported marker type 0xaf

Premature end of JPEG file
Premature end of JPEG file
Premature end of JPEG file
Premature end of JPEG file
Premature end of JPEG file
Corrupt JPEG data: premature end of data segment
Invalid JPEG file structure: two SOI markers

Note that the Premature end of JPEG file does not appear to cause a crash - I just get a resulting image that has a little artifact in the lower right corner... which is fine for what I'm doing. The last two lines, however, appear to occur only just before a crash.

2

There are 2 answers

0
deltheil On

By defaut libjpeg error handler exits the program (see jerror.c error_exit function). The documentation indicates that:

Applications may override [error_exit] if they want to get control back after an error

The library contains a sample code that explains how to do that: see example.c and please refer to the ERROR HANDLING section:

ERROR HANDLING: [...] Our example here shows how to override the "error_exit" method so that control is returned to the library's caller when a fatal error occurs, rather than calling exit() as the standard error_exit method does.

Then refer to the my_error_exit function:

METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  my_error_ptr myerr = (my_error_ptr) cinfo->err;

  /* Always display the message. */
  /* We could postpone this until after returning, if we chose. */
  (*cinfo->err->output_message) (cinfo);

  /* Return control to the setjmp point */
  longjmp(myerr->setjmp_buffer, 1);
}

The main decompression function (GLOBAL(int) read_JPEG_file (char * filename)) includes the code section that gets called when a fatal error occurs:

struct my_error_mgr jerr;

/* ... */

jerr.pub.error_exit = my_error_exit;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(jerr.setjmp_buffer)) {
  /* If we get here, the JPEG code has signaled an error.
   * We need to clean up the JPEG object, close the input file, and return.
   */
  jpeg_destroy_decompress(&cinfo);
  fclose(infile);
  return 0;
}

So you need to override the default error handler in a similar fashion.

0
Frank On

I have the same error.

check the jconfigint.h and config.h

#define SIZEOF_SIZE_T 4

32bit -> 4

64bit -> 8

if your target platform is 32bit, but “SIZEOF_SIZE_T 8” will got this error.

hopefully useful to you.