Image: Fix crash loading corrupted/invalid JPEG files

This commit is contained in:
Stenzek 2024-07-14 00:00:45 +10:00
parent b7da118f96
commit afea18f65e
No known key found for this signature in database

View file

@ -5,6 +5,7 @@
#include "common/bitutils.h" #include "common/bitutils.h"
#include "common/byte_stream.h" #include "common/byte_stream.h"
#include "common/fastjmp.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
@ -425,39 +426,41 @@ 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);
ERROR_LOG("libjpeg fatal error: {}", msg); ERROR_LOG("libjpeg fatal error: {}", msg);
longjmp(eh->jbuf, 1); fastjmp_jmp(&eh->jbuf, 1);
}; }
};
if (setjmp(eh->jbuf) == 0) } // namespace
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);
@ -584,13 +587,18 @@ 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);