Skip to content

Commit

Permalink
WRaster: Avoid undefined setjmp() behavior with libjpeg
Browse files Browse the repository at this point in the history
Fix compiler warning:
load_jpeg.c: In function 'RLoadJPEG':
load_jpeg.c:100:17: warning: variable 'image' might be clobbered by 'longjmp' or 'vfork' [-Wclobbered]

As it was not working to only set the RImage *image as volatile,
I had to refactor the code by following the example from
libjpeg-turbo/libjpeg-turbo@410c028#diff-e7cb632359a2be17c1008b50f9ec85691cd5d66834d5fe8f63ef65ceb06682ee
  • Loading branch information
dmaciejak authored and crmafra committed Feb 19, 2023
1 parent 4d65834 commit 14d1b81
Showing 1 changed file with 48 additions and 43 deletions.
91 changes: 48 additions & 43 deletions wrlib/load_jpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,97 +95,102 @@ static noreturn void my_error_exit(j_common_ptr cinfo)
longjmp(myerr->setjmp_buffer, 1);
}

RImage *RLoadJPEG(const char *file_name)
static RImage *do_read_jpeg_file(struct jpeg_decompress_struct *cinfo, const char *file_name)
{
RImage *image = NULL;
struct jpeg_decompress_struct cinfo;
int i;
unsigned char *ptr;
JSAMPROW buffer[1], bptr;
FILE *file;
/* 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.
*/
struct my_error_mgr jerr;

file = fopen(file_name, "rb");
if (!file) {
RErrorCode = RERR_OPEN;
return NULL;
}

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 (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(file);
return NULL;
}
jpeg_create_decompress(cinfo);
jpeg_stdio_src(cinfo, file);
jpeg_read_header(cinfo, TRUE);

jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, file);
jpeg_read_header(&cinfo, TRUE);
if (cinfo.image_width < 1 || cinfo.image_height < 1) {
if (cinfo->image_width < 1 || cinfo->image_height < 1) {
buffer[0] = NULL; /* Initialize pointer to avoid spurious free in cleanup code */
RErrorCode = RERR_BADIMAGEFILE;
goto abort_and_release_resources;
}

buffer[0] = (JSAMPROW) malloc(cinfo.image_width * cinfo.num_components);
buffer[0] = (JSAMPROW) malloc(cinfo->image_width * cinfo->num_components);
if (!buffer[0]) {
RErrorCode = RERR_NOMEMORY;
goto abort_and_release_resources;
}

if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
cinfo.out_color_space = JCS_GRAYSCALE;
if (cinfo->jpeg_color_space == JCS_GRAYSCALE)
cinfo->out_color_space = JCS_GRAYSCALE;
else
cinfo.out_color_space = JCS_RGB;
cinfo->out_color_space = JCS_RGB;

cinfo.quantize_colors = FALSE;
cinfo.do_fancy_upsampling = FALSE;
cinfo.do_block_smoothing = FALSE;
jpeg_calc_output_dimensions(&cinfo);
image = RCreateImage(cinfo.image_width, cinfo.image_height, False);
cinfo->quantize_colors = FALSE;
cinfo->do_fancy_upsampling = FALSE;
cinfo->do_block_smoothing = FALSE;
jpeg_calc_output_dimensions(cinfo);
image = RCreateImage(cinfo->image_width, cinfo->image_height, False);
if (!image) {
RErrorCode = RERR_NOMEMORY;
goto abort_and_release_resources;
}

jpeg_start_decompress(&cinfo);
jpeg_start_decompress(cinfo);
ptr = image->data;
if (cinfo.out_color_space == JCS_RGB) {
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, (JDIMENSION) 1);
if (cinfo->out_color_space == JCS_RGB) {
while (cinfo->output_scanline < cinfo->output_height) {
jpeg_read_scanlines(cinfo, buffer, (JDIMENSION) 1);
bptr = buffer[0];
memcpy(ptr, bptr, cinfo.image_width * 3);
ptr += cinfo.image_width * 3;
memcpy(ptr, bptr, cinfo->image_width * 3);
ptr += cinfo->image_width * 3;
}
} else {
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, (JDIMENSION) 1);
while (cinfo->output_scanline < cinfo->output_height) {
jpeg_read_scanlines(cinfo, buffer, (JDIMENSION) 1);
bptr = buffer[0];
for (i = 0; i < cinfo.image_width; i++) {
for (i = 0; i < cinfo->image_width; i++) {
*ptr++ = *bptr;
*ptr++ = *bptr;
*ptr++ = *bptr++;
}
}
}

jpeg_finish_decompress(&cinfo);
jpeg_finish_decompress(cinfo);

abort_and_release_resources:
jpeg_destroy_decompress(&cinfo);
jpeg_destroy_decompress(cinfo);
fclose(file);
if (buffer[0])
free(buffer[0]);

return image;
}

RImage *RLoadJPEG(const char *file_name)
{
struct jpeg_decompress_struct cinfo;
/* 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.
*/
struct my_error_mgr jerr;

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 (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);
return NULL;
}
return do_read_jpeg_file(&cinfo, file_name);
}

0 comments on commit 14d1b81

Please sign in to comment.