summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-06-29 02:54:16 +1000
committer Vas Crabb <vas@vastheman.com>2021-06-29 05:40:17 +1000
commit18737febb5c76d38a464dfdb760f6f2a6a32af14 (patch)
tree1487423bc4bee2e4ea73cab12578fdcbe9114865
parent8c12c611817cbade57ca6ab5235436a6e766ea34 (diff)
emu/rendutil.cpp: Use setjmp/longjmp for libjpeg error unwinding.
Apparently Linux AArch64 has issues with throwing exceptions across C function frames.
-rw-r--r--src/emu/rendutil.cpp160
1 files changed, 90 insertions, 70 deletions
diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp
index 443887b6305..a902a51bd85 100644
--- a/src/emu/rendutil.cpp
+++ b/src/emu/rendutil.cpp
@@ -17,6 +17,9 @@
#include "jpeglib.h"
#include "jerror.h"
+#include <csetjmp>
+#include <cstdlib>
+
namespace {
@@ -113,6 +116,18 @@ void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::core_file &file)
src->next_input_byte = nullptr;
}
+
+struct jpeg_setjmp_error_mgr : public jpeg_error_mgr
+{
+ jpeg_setjmp_error_mgr()
+ {
+ jpeg_std_error(this);
+ error_exit = [] (j_common_ptr cinfo) { std::longjmp(static_cast<jpeg_setjmp_error_mgr *>(cinfo->err)->m_jump_buffer, 1); };
+ }
+
+ std::jmp_buf m_jump_buffer;
+};
+
} // anonymous namespace
@@ -672,73 +687,74 @@ void render_load_jpeg(bitmap_argb32 &bitmap, util::core_file &file)
// deallocate previous bitmap
bitmap.reset();
- // create a JPEG source for the file
+ // set up context for error handling
jpeg_decompress_struct cinfo;
- jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr);
- jerr.error_exit = [] (j_common_ptr cinfo) { throw cinfo->err; };
+ jpeg_setjmp_error_mgr jerr;
+ cinfo.err = &jerr;
JSAMPARRAY buffer = nullptr;
- try
+ int w, h, s, row_stride, j, i;
+ if (setjmp(jerr.m_jump_buffer)) // setjmp must be used in control expression
{
- jpeg_create_decompress(&cinfo);
- cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
- jpeg_corefile_source::source(&cinfo, file);
-
- // read JPEG header and start decompression
- jpeg_read_header(&cinfo, TRUE);
- jpeg_start_decompress(&cinfo);
-
- // allocates the destination bitmap
- int w = cinfo.output_width;
- int h = cinfo.output_height;
- int s = cinfo.output_components;
- bitmap.allocate(w, h);
+ char msg[1024];
+ (cinfo.err->format_message)(reinterpret_cast<j_common_ptr>(&cinfo), msg);
+ osd_printf_error("JPEG error reading data from file: %s\n", msg);
+ bitmap.reset();
+ goto cleanup; // use goto to ensure longjmp can't cross an initialisation
+ }
- // allocates a buffer to receive the information and copy them into the bitmap
- int row_stride = cinfo.output_width * cinfo.output_components;
- JSAMPARRAY buffer = reinterpret_cast<JSAMPARRAY>(malloc(sizeof(JSAMPROW)));
- buffer[0] = reinterpret_cast<JSAMPROW>(malloc(sizeof(JSAMPLE) * row_stride));
+ // create a JPEG source for the file
+ jpeg_create_decompress(&cinfo);
+ cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
+ jpeg_corefile_source::source(&cinfo, file);
+
+ // read JPEG header and start decompression
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ // allocates the destination bitmap
+ w = cinfo.output_width;
+ h = cinfo.output_height;
+ s = cinfo.output_components;
+ bitmap.allocate(w, h);
+
+ // allocates a buffer to receive the information and copy them into the bitmap
+ row_stride = cinfo.output_width * cinfo.output_components;
+ buffer = reinterpret_cast<JSAMPARRAY>(std::malloc(sizeof(JSAMPROW)));
+ buffer[0] = reinterpret_cast<JSAMPROW>(std::malloc(sizeof(JSAMPLE) * row_stride));
+
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ j = cinfo.output_scanline;
+ jpeg_read_scanlines(&cinfo, buffer, 1);
- while (cinfo.output_scanline < cinfo.output_height)
+ if (s == 1)
{
- int j = cinfo.output_scanline;
- jpeg_read_scanlines(&cinfo, buffer, 1);
-
- if (s == 1)
- {
- for (int i = 0; i < w; ++i)
- bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
+ for (i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i], buffer[0][i], buffer[0][i]);
- }
- else if (s == 3)
- {
- for (int i = 0; i < w; ++i)
- bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
- }
- else
- {
- osd_printf_error("Cannot read JPEG data from file.\n");
- bitmap.reset();
- break;
- }
}
-
- // finish decompression and frees the memory
- jpeg_finish_decompress(&cinfo);
- }
- catch (jpeg_error_mgr *)
- {
- char msg[1024];
- (cinfo.err->format_message)(reinterpret_cast<j_common_ptr>(&cinfo), msg);
- osd_printf_error("JPEG error reading data from file: %s\n", msg);
- bitmap.reset();
+ else if (s == 3)
+ {
+ for (i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
+ }
+ else
+ {
+ osd_printf_error("Cannot read JPEG data from file.\n");
+ bitmap.reset();
+ break;
+ }
}
+
+ // finish decompression and free the memory
+ jpeg_finish_decompress(&cinfo);
+cleanup:
jpeg_destroy_decompress(&cinfo);
if (buffer)
{
if (buffer[0])
- free(buffer[0]);
- free(buffer);
+ std::free(buffer[0]);
+ std::free(buffer);
}
}
@@ -917,18 +933,21 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info
ru_imgformat render_detect_image(util::core_file &file)
{
// PNG: check for valid header
- util::png_error const png = util::png_info::verify_header(file);
- file.seek(0, SEEK_SET);
- if (util::png_error::NONE == png)
- return RENDUTIL_IMGFORMAT_PNG;
+ {
+ util::png_error const png = util::png_info::verify_header(file);
+ file.seek(0, SEEK_SET);
+ if (util::png_error::NONE == png)
+ return RENDUTIL_IMGFORMAT_PNG;
+ }
// JPEG: attempt to read header with libjpeg
- jpeg_decompress_struct cinfo;
- jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr);
- jerr.error_exit = [] (j_common_ptr cinfo) { throw cinfo->err; };
- try
{
+ jpeg_decompress_struct cinfo;
+ jpeg_setjmp_error_mgr jerr;
+ cinfo.err = &jerr;
+ if (setjmp(jerr.m_jump_buffer)) // setjmp must be used in control expression
+ goto notjpeg; // use goto to ensure longjmp can't cross an initialisation
+
jpeg_create_decompress(&cinfo);
cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
jpeg_corefile_source::source(&cinfo, file);
@@ -936,18 +955,19 @@ ru_imgformat render_detect_image(util::core_file &file)
jpeg_destroy_decompress(&cinfo);
file.seek(0, SEEK_SET);
return RENDUTIL_IMGFORMAT_JPEG;
- }
- catch (jpeg_error_mgr *)
- {
+
+ notjpeg:
jpeg_destroy_decompress(&cinfo);
file.seek(0, SEEK_SET);
}
// Microsoft DIB: check for valid header
- util::msdib_error const msdib = util::msdib_verify_header(file);
- file.seek(0, SEEK_SET);
- if (util::msdib_error::NONE == msdib)
- return RENDUTIL_IMGFORMAT_MSDIB;
+ {
+ util::msdib_error const msdib = util::msdib_verify_header(file);
+ file.seek(0, SEEK_SET);
+ if (util::msdib_error::NONE == msdib)
+ return RENDUTIL_IMGFORMAT_MSDIB;
+ }
// TODO: add more as necessary
return RENDUTIL_IMGFORMAT_UNKNOWN;