From a5eac02dacd8a8940ffccd1b8d0783c0b5f8ec7d Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Sun, 27 Apr 2025 14:51:02 +0300
Subject: [PATCH] Factor out parts of IMG_LoadJPG where locals can be clobbered
by longjmp
Also a minor tidy-up in IMG_LoadPNG()
( Reference issue: https://github.com/libsdl-org/SDL_image/issues/435 )
( Backport from SDL2 commit: 0dfa3d848c577481c4f97058267eda17b7f61aa8 )
---
IMG_jpg.c | 134 +++++++++++++++++++++++++++++++-----------------------
IMG_png.c | 34 ++++++++------
2 files changed, 98 insertions(+), 70 deletions(-)
diff --git a/IMG_jpg.c b/IMG_jpg.c
index 9dd0e4c65..ecda75e90 100644
--- a/IMG_jpg.c
+++ b/IMG_jpg.c
@@ -371,53 +371,41 @@ static void output_no_message(j_common_ptr cinfo)
/* do nothing */
}
-/* Load a JPEG type image from an SDL datasource */
-SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
-{
- int start;
+struct loadjpeg_vars {
+ const char *error;
+ SDL_Surface *surface;
struct jpeg_decompress_struct cinfo;
- JSAMPROW rowptr[1];
- SDL_Surface *surface = NULL;
struct my_error_mgr jerr;
+};
- if ( !src ) {
- /* The error message has been set in SDL_RWFromFile */
- return NULL;
- }
- start = SDL_RWtell(src);
-
- if ( (IMG_Init(IMG_INIT_JPG) & IMG_INIT_JPG) == 0 ) {
- return NULL;
- }
+static SDL_bool LIBJPEG_LoadJPG_RW(SDL_RWops *src, struct loadjpeg_vars *vars)
+{
+ JSAMPROW rowptr[1];
/* Create a decompression structure and load the JPEG header */
- cinfo.err = lib.jpeg_std_error(&jerr.errmgr);
- jerr.errmgr.error_exit = my_error_exit;
- jerr.errmgr.output_message = output_no_message;
- if(setjmp(jerr.escape)) {
+ vars->cinfo.err = lib.jpeg_std_error(&vars->jerr.errmgr);
+ vars->jerr.errmgr.error_exit = my_error_exit;
+ vars->jerr.errmgr.output_message = output_no_message;
+ if (setjmp(vars->jerr.escape)) {
/* If we get here, libjpeg found an error */
- lib.jpeg_destroy_decompress(&cinfo);
- if ( surface != NULL ) {
- SDL_FreeSurface(surface);
- }
- SDL_RWseek(src, start, RW_SEEK_SET);
- IMG_SetError("JPEG loading error");
- return NULL;
+ vars->error = "JPEG loading error";
+ lib.jpeg_destroy_decompress(&vars->cinfo);
+ return SDL_FALSE;
}
- lib.jpeg_create_decompress(&cinfo);
- jpeg_SDL_RW_src(&cinfo, src);
- lib.jpeg_read_header(&cinfo, TRUE);
+ lib.jpeg_create_decompress(&vars->cinfo);
+ jpeg_SDL_RW_src(&vars->cinfo, src);
+ lib.jpeg_read_header(&vars->cinfo, TRUE);
- if(cinfo.num_components == 4) {
+ if (vars->cinfo.num_components == 4) {
/* Set 32-bit Raw output */
- cinfo.out_color_space = JCS_CMYK;
- cinfo.quantize_colors = FALSE;
- lib.jpeg_calc_output_dimensions(&cinfo);
+ vars->cinfo.out_color_space = JCS_CMYK;
+ vars->cinfo.quantize_colors = FALSE;
+ lib.jpeg_calc_output_dimensions(&vars->cinfo);
/* Allocate an output surface to hold the image */
- surface = SDL_AllocSurface(SDL_SWSURFACE,
- cinfo.output_width, cinfo.output_height, 32,
+ vars->surface = SDL_AllocSurface(SDL_SWSURFACE,
+ vars->cinfo.output_width, vars->cinfo.output_height, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
#else
@@ -425,19 +413,19 @@ SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
#endif
} else {
/* Set 24-bit RGB output */
- cinfo.out_color_space = JCS_RGB;
- cinfo.quantize_colors = FALSE;
+ vars->cinfo.out_color_space = JCS_RGB;
+ vars->cinfo.quantize_colors = FALSE;
#ifdef FAST_JPEG
- cinfo.scale_num = 1;
- cinfo.scale_denom = 1;
- cinfo.dct_method = JDCT_FASTEST;
- cinfo.do_fancy_upsampling = FALSE;
+ vars->cinfo.scale_num = 1;
+ vars->cinfo.scale_denom = 1;
+ vars->cinfo.dct_method = JDCT_FASTEST;
+ vars->cinfo.do_fancy_upsampling = FALSE;
#endif
- lib.jpeg_calc_output_dimensions(&cinfo);
+ lib.jpeg_calc_output_dimensions(&vars->cinfo);
/* Allocate an output surface to hold the image */
- surface = SDL_AllocSurface(SDL_SWSURFACE,
- cinfo.output_width, cinfo.output_height, 24,
+ vars->surface = SDL_AllocSurface(SDL_SWSURFACE,
+ vars->cinfo.output_width, vars->cinfo.output_height, 24,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
0x0000FF, 0x00FF00, 0xFF0000,
#else
@@ -446,24 +434,56 @@ SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
0);
}
- if ( surface == NULL ) {
- lib.jpeg_destroy_decompress(&cinfo);
- SDL_RWseek(src, start, RW_SEEK_SET);
- IMG_SetError("Out of memory");
- return NULL;
+ if (vars->surface == NULL) {
+ vars-> error = "Out of memory";
+ lib.jpeg_destroy_decompress(&vars->cinfo);
+ return SDL_FALSE;
}
/* Decompress the image */
- lib.jpeg_start_decompress(&cinfo);
- while ( cinfo.output_scanline < cinfo.output_height ) {
- rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels +
- cinfo.output_scanline * surface->pitch;
- lib.jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
+ lib.jpeg_start_decompress(&vars->cinfo);
+ while (vars->cinfo.output_scanline < vars->cinfo.output_height) {
+ rowptr[0] = (JSAMPROW)(Uint8 *)vars->surface->pixels +
+ vars->cinfo.output_scanline * vars->surface->pitch;
+ lib.jpeg_read_scanlines(&vars->cinfo, rowptr, (JDIMENSION) 1);
+ }
+ lib.jpeg_finish_decompress(&vars->cinfo);
+ lib.jpeg_destroy_decompress(&vars->cinfo);
+
+ return SDL_TRUE;
+}
+
+/* Load a JPEG type image from an SDL datasource */
+SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
+{
+ int start;
+ struct loadjpeg_vars vars;
+
+ if (!src) {
+ /* The error message has been set in SDL_RWFromFile */
+ return NULL;
+ }
+
+ if ((IMG_Init(IMG_INIT_JPG) & IMG_INIT_JPG) == 0) {
+ return NULL;
+ }
+
+ start = SDL_RWtell(src);
+ memset(&vars, 0, sizeof(vars));
+
+ if (LIBJPEG_LoadJPG_RW(src, &vars)) {
+ return vars.surface;
+ }
+
+ SDL_RWseek(src, start, RW_SEEK_SET);
+ if (vars.surface) {
+ SDL_FreeSurface(vars.surface);
+ }
+ if (vars.error) {
+ IMG_SetError("%s", vars.error);
}
- lib.jpeg_finish_decompress(&cinfo);
- lib.jpeg_destroy_decompress(&cinfo);
- return(surface);
+ return NULL;
}
#else
diff --git a/IMG_png.c b/IMG_png.c
index e757ac964..0618fff13 100644
--- a/IMG_png.c
+++ b/IMG_png.c
@@ -345,7 +345,7 @@ struct loadpng_vars {
png_bytep *row_pointers;
};
-static void LIBPNG_LoadPNG_RW(SDL_RWops *src, struct loadpng_vars *vars)
+static SDL_bool LIBPNG_LoadPNG_RW(SDL_RWops *src, struct loadpng_vars *vars)
{
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, num_channels;
@@ -363,14 +363,14 @@ static void LIBPNG_LoadPNG_RW(SDL_RWops *src, struct loadpng_vars *vars)
NULL,NULL,NULL);
if (vars->png_ptr == NULL) {
vars->error = "Couldn't allocate memory for PNG file or incompatible PNG dll";
- return;
+ return SDL_FALSE;
}
/* Allocate/initialize the memory for image information. REQUIRED. */
vars->info_ptr = lib.png_create_info_struct(vars->png_ptr);
if (vars->info_ptr == NULL) {
vars->error = "Couldn't create image information for PNG file";
- return;
+ return SDL_FALSE;
}
/* Set error handling if you are using setjmp/longjmp method (this is
@@ -384,7 +384,7 @@ static void LIBPNG_LoadPNG_RW(SDL_RWops *src, struct loadpng_vars *vars)
#endif
{
vars->error = "Error reading the PNG file.";
- return;
+ return SDL_FALSE;
}
/* Set up the input control */
@@ -471,7 +471,7 @@ static void LIBPNG_LoadPNG_RW(SDL_RWops *src, struct loadpng_vars *vars)
bit_depth*num_channels, Rmask,Gmask,Bmask,Amask);
if (vars->surface == NULL) {
vars->error = "Out of memory";
- return;
+ return SDL_FALSE;
}
if (ckey != -1) {
@@ -488,7 +488,7 @@ static void LIBPNG_LoadPNG_RW(SDL_RWops *src, struct loadpng_vars *vars)
vars->row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*height);
if (vars->row_pointers == NULL) {
vars->error = "Out of memory";
- return;
+ return SDL_FALSE;
}
for (row = 0; row < (int)height; row++) {
vars->row_pointers[row] = (png_bytep)
@@ -528,12 +528,15 @@ static void LIBPNG_LoadPNG_RW(SDL_RWops *src, struct loadpng_vars *vars)
}
}
}
+
+ return SDL_TRUE;
}
SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
{
int start;
struct loadpng_vars vars;
+ SDL_bool success;
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
@@ -547,7 +550,7 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
start = SDL_RWtell(src);
memset(&vars, 0, sizeof(vars));
- LIBPNG_LoadPNG_RW(src, &vars);
+ success = LIBPNG_LoadPNG_RW(src, &vars);
if (vars.png_ptr) {
lib.png_destroy_read_struct(&vars.png_ptr,
@@ -557,15 +560,20 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
if (vars.row_pointers) {
free(vars.row_pointers);
}
+ if (success) {
+ return vars.surface;
+ }
+
+ SDL_RWseek(src, start, RW_SEEK_SET);
+ if (vars.surface) {
+ SDL_FreeSurface(vars.surface);
+ vars.surface = NULL;
+ }
if (vars.error) {
- SDL_RWseek(src, start, RW_SEEK_SET);
- if (vars.surface) {
- SDL_FreeSurface(vars.surface);
- vars.surface = NULL;
- }
IMG_SetError(vars.error);
}
- return vars.surface;
+
+ return NULL;
}
#else