Image: Fix crash loading corrupted/invalid JPEG files

Backport from: afea18f65e
This commit is contained in:
KamFretoZ 2024-08-22 22:52:50 +07:00 committed by lightningterror
parent fd5a652270
commit 9a50218400
1 changed files with 35 additions and 29 deletions

View File

@ -8,6 +8,7 @@
#include "ScopedGuard.h" #include "ScopedGuard.h"
#include "StringUtil.h" #include "StringUtil.h"
#include <common/FastJmp.h>
#include <jpeglib.h> #include <jpeglib.h>
#include <png.h> #include <png.h>
#include <webp/decode.h> #include <webp/decode.h>
@ -383,39 +384,40 @@ namespace
struct JPEGErrorHandler struct JPEGErrorHandler
{ {
jpeg_error_mgr err; jpeg_error_mgr err;
jmp_buf jbuf; fastjmp_buf jbuf;
};
} // namespace
static bool HandleJPEGError(JPEGErrorHandler* eh) JPEGErrorHandler()
{ {
jpeg_std_error(&eh->err); jpeg_std_error(&err);
err.error_exit = &ErrorExit;
}
eh->err.error_exit = [](j_common_ptr cinfo) { static void ErrorExit(j_common_ptr cinfo)
{
JPEGErrorHandler* eh = (JPEGErrorHandler*)cinfo->err; JPEGErrorHandler* eh = (JPEGErrorHandler*)cinfo->err;
char msg[JMSG_LENGTH_MAX]; char msg[JMSG_LENGTH_MAX];
eh->err.format_message(cinfo, msg); eh->err.format_message(cinfo, msg);
Console.ErrorFmt("libjpeg fatal error: {}", msg); Console.ErrorFmt("libjpeg fatal error: {}", msg);
longjmp(eh->jbuf, 1); fastjmp_jmp(&eh->jbuf, 1);
}
}; };
} // namespace
if (setjmp(eh->jbuf) == 0)
return true;
return false;
}
template <typename T> template <typename T>
static bool WrapJPEGDecompress(RGBA8Image* image, T setup_func) static bool WrapJPEGDecompress(RGBA8Image* image, T setup_func)
{ {
std::vector<u8> scanline; std::vector<u8> scanline;
jpeg_decompress_struct info = {};
JPEGErrorHandler err; // NOTE: Be **very** careful not to allocate memory after calling this function.
if (!HandleJPEGError(&err)) // It won't get freed, because fastjmp does not unwind the stack.
JPEGErrorHandler errhandler;
if (fastjmp_set(&errhandler.jbuf) != 0)
{
jpeg_destroy_decompress(&info);
return false; return false;
}
jpeg_decompress_struct info; info.err = &errhandler.err;
info.err = &err.err;
jpeg_create_decompress(&info); jpeg_create_decompress(&info);
setup_func(info); setup_func(info);
@ -541,13 +543,17 @@ template <typename T>
static bool WrapJPEGCompress(const RGBA8Image& image, u8 quality, T setup_func) static bool WrapJPEGCompress(const RGBA8Image& image, u8 quality, T setup_func)
{ {
std::vector<u8> scanline; std::vector<u8> scanline;
jpeg_compress_struct info = {};
JPEGErrorHandler err; // NOTE: Be **very** careful not to allocate memory after calling this function.
if (!HandleJPEGError(&err)) // It won't get freed, because fastjmp does not unwind the stack.
JPEGErrorHandler errhandler;
if (fastjmp_set(&errhandler.jbuf) != 0)
{
jpeg_destroy_compress(&info);
return false; return false;
}
jpeg_compress_struct info; info.err = &errhandler.err;
info.err = &err.err;
jpeg_create_compress(&info); jpeg_create_compress(&info);
setup_func(info); setup_func(info);