mirror of
https://github.com/fltk/fltk.git
synced 2026-05-27 19:10:24 +08:00
Fix usage of 'volatile' in src/Fl_JPEG_Image.cxx (#1207)
- allocate a new struct 'load_stat' on the heap - use struct load_stat to open image file (fp) and for error counters The previous fix of #1207 unfortunately decremented volatile variables which caused (plausible) compiler warnings by clang.
This commit is contained in:
+35
-40
@@ -206,11 +206,33 @@ static void jpeg_unprotected_mem_src(j_decompress_ptr cinfo, const unsigned char
|
|||||||
}
|
}
|
||||||
#endif // HAVE_LIBJPEG
|
#endif // HAVE_LIBJPEG
|
||||||
|
|
||||||
|
// The following struct is used to control reading an image file and some
|
||||||
|
// error conditions. It *must* be allocated on the heap (not as a local/stack
|
||||||
|
// variable) because otherwise the macOS/clang optimizer would optimize it
|
||||||
|
// away for some unknown reason. See GitHub Issue #1207.
|
||||||
|
// This struct also includes `FILE *fp` which had been allocated on the heap
|
||||||
|
// previously for a similar reason (gcc: [-Wclobbered]).
|
||||||
|
|
||||||
|
struct load_stat {
|
||||||
|
FILE *fp; // file pointer if reading from disk
|
||||||
|
int max_finish_decompress_err; // count errors and give up after a while
|
||||||
|
int max_destroy_decompress_err; // ... to avoid recursion and deadlock
|
||||||
|
|
||||||
|
load_stat() { // c'tor
|
||||||
|
fp = nullptr;
|
||||||
|
max_finish_decompress_err = 5;
|
||||||
|
max_destroy_decompress_err = 5;
|
||||||
|
}
|
||||||
|
~load_stat() { // d'tor
|
||||||
|
if (fp)
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This method reads JPEG image data and creates an RGB or grayscale image.
|
This method reads JPEG image data and creates an RGB or grayscale image.
|
||||||
To avoid code duplication, we set filename if we want to read form a file or
|
To avoid code duplication, we set filename if we want to read from a file
|
||||||
data to read from memory instead. Sharename can be set if the image is
|
or data to read from memory instead. Sharename can be set if the image is
|
||||||
supposed to be added to the Fl_Shared_Image list.
|
supposed to be added to the Fl_Shared_Image list.
|
||||||
*/
|
*/
|
||||||
void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const unsigned char *data, int data_length)
|
void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const unsigned char *data, int data_length)
|
||||||
@@ -220,18 +242,7 @@ void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const
|
|||||||
fl_jpeg_error_mgr jerr; // Error handler info
|
fl_jpeg_error_mgr jerr; // Error handler info
|
||||||
JSAMPROW row; // Sample row pointer
|
JSAMPROW row; // Sample row pointer
|
||||||
|
|
||||||
// The following variables are pointers allocating some private space that
|
struct load_stat *lstat = new load_stat();
|
||||||
// is not reset by 'setjmp()'. At least under macOS, it's necessay to make
|
|
||||||
// these variables volatile to avoid errors occurring when compiled with -O1 (issue #1207).
|
|
||||||
volatile char* max_finish_decompress_err; // count errors and give up after a while
|
|
||||||
volatile char* max_destroy_decompress_err; // to avoid recursion and deadlock
|
|
||||||
|
|
||||||
// Note: The file pointer fp must not be an automatic (stack) variable
|
|
||||||
// to avoid potential clobbering by setjmp/longjmp (gcc: [-Wclobbered]).
|
|
||||||
// Hence the actual 'fp' is allocated with operator new.
|
|
||||||
|
|
||||||
FILE** fp = new FILE*; // always allocate file pointer
|
|
||||||
*fp = NULL;
|
|
||||||
|
|
||||||
// Clear data...
|
// Clear data...
|
||||||
alloc_array = 0;
|
alloc_array = 0;
|
||||||
@@ -239,15 +250,15 @@ void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const
|
|||||||
|
|
||||||
// Open the image file if we read from the file system
|
// Open the image file if we read from the file system
|
||||||
if (filename) {
|
if (filename) {
|
||||||
if ((*fp = fl_fopen(filename, "rb")) == NULL) {
|
if ((lstat->fp = fl_fopen(filename, "rb")) == NULL) {
|
||||||
ld(ERR_FILE_ACCESS);
|
ld(ERR_FILE_ACCESS);
|
||||||
delete fp;
|
delete lstat;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (data==0L) {
|
if (data==0L) {
|
||||||
ld(ERR_FILE_ACCESS);
|
ld(ERR_FILE_ACCESS);
|
||||||
delete fp;
|
delete lstat;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,12 +268,6 @@ void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const
|
|||||||
jerr.pub_.error_exit = fl_jpeg_error_handler;
|
jerr.pub_.error_exit = fl_jpeg_error_handler;
|
||||||
jerr.pub_.output_message = fl_jpeg_output_handler;
|
jerr.pub_.output_message = fl_jpeg_output_handler;
|
||||||
|
|
||||||
// Setup error loop variables
|
|
||||||
max_finish_decompress_err = (char*)malloc(1); // allocate space on the frame for error counters
|
|
||||||
max_destroy_decompress_err = (char*)malloc(1); // otherwise, the variables are reset on the longjmp
|
|
||||||
*max_finish_decompress_err=10;
|
|
||||||
*max_destroy_decompress_err=10;
|
|
||||||
|
|
||||||
if (setjmp(jerr.errhand_))
|
if (setjmp(jerr.errhand_))
|
||||||
{
|
{
|
||||||
// JPEG error handling...
|
// JPEG error handling...
|
||||||
@@ -270,16 +275,14 @@ void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const
|
|||||||
if (filename) name = filename;
|
if (filename) name = filename;
|
||||||
else if (sharename) name = sharename;
|
else if (sharename) name = sharename;
|
||||||
Fl::warning("JPEG file \"%s\" is too large or contains errors!\n", name);
|
Fl::warning("JPEG file \"%s\" is too large or contains errors!\n", name);
|
||||||
|
|
||||||
// if any of the cleanup routines hits another error, we would end up
|
// if any of the cleanup routines hits another error, we would end up
|
||||||
// in a loop. So instead, we decrement max_err for some upper cleanup limit.
|
// in a loop. So instead, we decrement max_err for some upper cleanup limit.
|
||||||
if ( ((*max_finish_decompress_err)-- > 0) && array)
|
if ( ((lstat->max_finish_decompress_err)-- > 0) && array)
|
||||||
jpeg_finish_decompress(&dinfo);
|
jpeg_finish_decompress(&dinfo);
|
||||||
if ( (*max_destroy_decompress_err)-- > 0)
|
if ( (lstat->max_destroy_decompress_err)-- > 0)
|
||||||
jpeg_destroy_decompress(&dinfo);
|
jpeg_destroy_decompress(&dinfo);
|
||||||
|
|
||||||
if (*fp)
|
|
||||||
fclose(*fp);
|
|
||||||
|
|
||||||
w(0);
|
w(0);
|
||||||
h(0);
|
h(0);
|
||||||
d(0);
|
d(0);
|
||||||
@@ -290,17 +293,14 @@ void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const
|
|||||||
alloc_array = 0;
|
alloc_array = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free((void*)max_destroy_decompress_err);
|
|
||||||
free((void*)max_finish_decompress_err);
|
|
||||||
|
|
||||||
ld(ERR_FORMAT);
|
ld(ERR_FORMAT);
|
||||||
delete fp;
|
delete lstat;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg_create_decompress(&dinfo);
|
jpeg_create_decompress(&dinfo);
|
||||||
if (*fp) {
|
if (lstat->fp) {
|
||||||
jpeg_stdio_src(&dinfo, *fp);
|
jpeg_stdio_src(&dinfo, lstat->fp);
|
||||||
} else {
|
} else {
|
||||||
if (data_length==-1)
|
if (data_length==-1)
|
||||||
jpeg_unprotected_mem_src(&dinfo, data);
|
jpeg_unprotected_mem_src(&dinfo, data);
|
||||||
@@ -336,16 +336,11 @@ void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const
|
|||||||
jpeg_finish_decompress(&dinfo);
|
jpeg_finish_decompress(&dinfo);
|
||||||
jpeg_destroy_decompress(&dinfo);
|
jpeg_destroy_decompress(&dinfo);
|
||||||
|
|
||||||
free((void*)max_destroy_decompress_err);
|
delete lstat;
|
||||||
free((void*)max_finish_decompress_err);
|
|
||||||
|
|
||||||
if (*fp)
|
|
||||||
fclose(*fp);
|
|
||||||
|
|
||||||
if (sharename && w() && h()) {
|
if (sharename && w() && h()) {
|
||||||
Fl_Shared_Image *si = new Fl_Shared_Image(sharename, this);
|
Fl_Shared_Image *si = new Fl_Shared_Image(sharename, this);
|
||||||
si->add();
|
si->add();
|
||||||
}
|
}
|
||||||
delete fp;
|
|
||||||
#endif // HAVE_LIBJPEG
|
#endif // HAVE_LIBJPEG
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user