From 345ad8bf8c7e7fa8a5b528da284568dad76b6d02 Mon Sep 17 00:00:00 2001 From: Ingo Date: Fri, 29 May 2015 01:06:34 +0200 Subject: [PATCH] Crash on Win64 when embedded jpeg thumb is corrupted, Issue 2795 --- rtengine/imageio.cc | 163 ++++++++++++++++++++++------------------ rtengine/rtthumbnail.cc | 9 --- 2 files changed, 89 insertions(+), 83 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 8662d9093..5c0d87f52 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -337,70 +337,104 @@ int ImageIO::loadPNG (Glib::ustring fname) { } return IMIO_SUCCESS; } + +typedef struct { + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ +} my_error_mgr; + +void my_error_exit (j_common_ptr cinfo) { + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_mgr *myerr = (my_error_mgr*) 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 */ +#if defined( WIN32 ) && defined( __x86_64__ ) + __builtin_longjmp(myerr->setjmp_buffer, 1); +#else + longjmp(myerr->setjmp_buffer, 1); +#endif +} + int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize) { jpeg_decompress_struct cinfo; - jpeg_error_mgr jerr; - cinfo.err = my_jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); + jpeg_memory_src (&cinfo,(const JOCTET*)buffer,bufsize); + + /* We use our private extension JPEG error handler. + Note that this struct must live as long as the main JPEG parameter + struct, to avoid dangling-pointer problems. + */ + my_error_mgr jerr; + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + + /* Establish the setjmp return context for my_error_exit to use. */ +#if defined( WIN32 ) && defined( __x86_64__ ) + if (__builtin_setjmp(jerr.setjmp_buffer)) { +#else + if (setjmp(jerr.setjmp_buffer)) { +#endif + /* If we get here, the JPEG code has signaled an error. + We need to clean up the JPEG object and return. + */ + jpeg_destroy_decompress(&cinfo); + return IMIO_READERROR; + } + - jpeg_memory_src (&cinfo,(const JOCTET*)buffer,bufsize); - if ( setjmp((reinterpret_cast(cinfo.src))->error_jmp_buf) == 0 ) - { - if (pl) { - pl->setProgressStr ("PROGRESSBAR_LOADJPEG"); - pl->setProgress (0.0); + if (pl) { + pl->setProgressStr ("PROGRESSBAR_LOADJPEG"); + pl->setProgress (0.0); - } - - setup_read_icc_profile (&cinfo); - - //jpeg_memory_src (&cinfo,buffer,bufsize); - jpeg_read_header(&cinfo, TRUE); - - deleteLoadedProfileData(); - loadedProfileDataJpg = true; - bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); - if (hasprofile) - embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); - else - embProfile = NULL; - - jpeg_start_decompress(&cinfo); - - unsigned int width = cinfo.output_width; - unsigned int height = cinfo.output_height; - - allocate (width, height); - - unsigned char *row=new unsigned char[width*3]; - while (cinfo.output_scanline < height) { - if (jpeg_read_scanlines(&cinfo,&row,1) < 1) { - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - delete [] row; - return IMIO_READERROR; - } - setScanline (cinfo.output_scanline-1, row, 8); - - if (pl && !(cinfo.output_scanline%100)) - pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height); - } - delete [] row; - - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - if (pl) { - pl->setProgressStr ("PROGRESSBAR_READY"); - pl->setProgress (1.0); - } - return IMIO_SUCCESS; } - else { - jpeg_destroy_decompress(&cinfo); - return IMIO_READERROR; + + setup_read_icc_profile (&cinfo); + + jpeg_read_header(&cinfo, TRUE); + + deleteLoadedProfileData(); + loadedProfileDataJpg = true; + bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); + if (hasprofile) + embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); + else + embProfile = NULL; + + jpeg_start_decompress(&cinfo); + + unsigned int width = cinfo.output_width; + unsigned int height = cinfo.output_height; + + allocate (width, height); + + unsigned char *row=new unsigned char[width*3]; + while (cinfo.output_scanline < height) { + if (jpeg_read_scanlines(&cinfo,&row,1) < 1) { + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + delete [] row; + return IMIO_READERROR; + } + setScanline (cinfo.output_scanline-1, row, 8); + + if (pl && !(cinfo.output_scanline%100)) + pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height); } + delete [] row; + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + if (pl) { + pl->setProgressStr ("PROGRESSBAR_READY"); + pl->setProgress (1.0); + } + return IMIO_SUCCESS; } int ImageIO::loadJPEG (Glib::ustring fname) { @@ -836,25 +870,6 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) { } -typedef struct { - struct jpeg_error_mgr pub; /* "public" fields */ - jmp_buf setjmp_buffer; /* for return to caller */ -} my_error_mgr; - -void my_error_exit (j_common_ptr cinfo) { - /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ - my_error_mgr *myerr = (my_error_mgr*) 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 */ -#if defined( WIN32 ) && defined( __x86_64__ ) - __builtin_longjmp(myerr->setjmp_buffer, 1); -#else - longjmp(myerr->setjmp_buffer, 1); -#endif -} // Quality 0..100, subsampling: 1=low quality, 2=medium, 3=high int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) { diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 557b791a4..d5f3f86bf 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -183,16 +183,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL const char* data((const char*)fdata(ri->get_thumbOffset(),ri->get_file())); if ( (unsigned char)data[1] == 0xd8 ) { -#if defined( __WIN32__ ) && defined( __x86_64__ ) - // This is a hack for Issue 2425, because loadJPEGFromMemory crashes on Win64 when jpg marker is incorrect - // (should be 0xff 0xd8, but is 0x02 0xd8 for mrw files) - std::string suffix = fname.length() > 4 ? fname.substr(fname.length()-3) : ""; - for (int i = 0; i < suffix.length(); i++) suffix[i] = std::tolower(suffix[i]); - if(suffix != "mrw" || (unsigned char)data[0] == 0xff) - err = img->loadJPEGFromMemory(data,ri->get_thumbLength()); -#else err = img->loadJPEGFromMemory(data,ri->get_thumbLength()); -#endif } else {