From 14d1b8197a92251c00eed30d68ac81cc9f879b41 Mon Sep 17 00:00:00 2001 From: David Maciejak Date: Sat, 18 Feb 2023 21:58:28 +0800 Subject: [PATCH] WRaster: Avoid undefined setjmp() behavior with libjpeg 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 https://github.com/libjpeg-turbo/libjpeg-turbo/commit/410c028f3396d1fa9bcc72608079ff4d3d76b03e#diff-e7cb632359a2be17c1008b50f9ec85691cd5d66834d5fe8f63ef65ceb06682ee --- wrlib/load_jpeg.c | 91 +++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/wrlib/load_jpeg.c b/wrlib/load_jpeg.c index 76f7b662..9c2ef6be 100644 --- a/wrlib/load_jpeg.c +++ b/wrlib/load_jpeg.c @@ -95,19 +95,13 @@ 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) { @@ -115,63 +109,51 @@ RImage *RLoadJPEG(const char *file_name) 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++; @@ -179,13 +161,36 @@ RImage *RLoadJPEG(const char *file_name) } } - 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); +}