SDL_image: JPEG: Add error-recovery when saving with libjpeg

From 5baa3c8c7a64ccb00c6a9ec926d238a7e2e6a50a Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL REDACTED]>
Date: Mon, 11 Mar 2024 19:25:27 +0000
Subject: [PATCH] JPEG: Add error-recovery when saving with libjpeg

Because we have set up libjpeg to use my_error_exit, we need to call
setjmp() before the first time it might possibly call longjmp().
Otherwise, on error we'll do a non-local goto to an uninitialized
pointer and crash.

Resolves: https://github.com/libsdl-org/SDL_image/issues/429
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 src/IMG_jpg.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/IMG_jpg.c b/src/IMG_jpg.c
index bb772189..6e78a1d5 100644
--- a/src/IMG_jpg.c
+++ b/src/IMG_jpg.c
@@ -482,6 +482,7 @@ struct savejpeg_vars
 {
     struct jpeg_compress_struct cinfo;
     struct my_error_mgr jerr;
+    Sint64 original_offset;
 };
 
 static int JPEG_SaveJPEG_RW(struct savejpeg_vars *vars, SDL_Surface *jpeg_surface, SDL_RWops *dst, int quality)
@@ -490,6 +491,14 @@ static int JPEG_SaveJPEG_RW(struct savejpeg_vars *vars, SDL_Surface *jpeg_surfac
     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;
+    vars->original_offset = SDL_RWtell(dst);
+
+    if(setjmp(vars->jerr.escape)) {
+        /* If we get here, libjpeg found an error */
+        lib.jpeg_destroy_compress(&vars->cinfo);
+        SDL_RWseek(dst, vars->original_offset, SDL_RW_SEEK_SET);
+        return IMG_SetError("Error saving JPEG with libjpeg");
+    }
 
     lib.jpeg_create_compress(&vars->cinfo);
     jpeg_SDL_RW_dest(&vars->cinfo, dst);