1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-09 23:34:20 +00:00

PNGImageFormat: Avoid crashing when attempting to write an invalid image

The default error handler could cause crashes, so we now set up a custom
error handler both when reading and writing PNGs.

The HeapBlock and BitmapData automatic variables have moved, so that
their destructors will still run as expected in the failure case. Note
that it's UB to call longjmp to unwind the stack to the previous setjmp,
if said unwinding would normally cause non-trivial destructors to run.
This commit is contained in:
reuk 2025-09-22 16:23:57 +01:00
parent 51c4a484ee
commit e0faa5c255
No known key found for this signature in database

View file

@ -332,14 +332,6 @@ namespace PNGHelpers
static_cast<OutputStream*> (png_get_io_ptr (png))->write (data, length); static_cast<OutputStream*> (png_get_io_ptr (png))->write (data, length);
} }
#if ! JUCE_USING_COREIMAGE_LOADER
static void JUCE_CDECL readCallback (png_structp png, png_bytep data, png_size_t length)
{
static_cast<InputStream*> (png_get_io_ptr (png))->read (data, (int) length);
}
struct PNGErrorStruct {};
static void JUCE_CDECL errorCallback (png_structp p, png_const_charp) static void JUCE_CDECL errorCallback (png_structp p, png_const_charp)
{ {
#ifdef PNG_SETJMP_SUPPORTED #ifdef PNG_SETJMP_SUPPORTED
@ -351,6 +343,14 @@ namespace PNGHelpers
static void JUCE_CDECL warningCallback (png_structp, png_const_charp) {} static void JUCE_CDECL warningCallback (png_structp, png_const_charp) {}
#if ! JUCE_USING_COREIMAGE_LOADER
static void JUCE_CDECL readCallback (png_structp png, png_bytep data, png_size_t length)
{
static_cast<InputStream*> (png_get_io_ptr (png))->read (data, (int) length);
}
struct PNGErrorStruct {};
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4611) JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4611)
static bool readHeader (InputStream& in, png_structp pngReadStruct, png_infop pngInfoStruct, jmp_buf& errorJumpBuf, static bool readHeader (InputStream& in, png_structp pngReadStruct, png_infop pngInfoStruct, jmp_buf& errorJumpBuf,
@ -528,15 +528,31 @@ Image PNGImageFormat::decodeImage (InputStream& in)
bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out) bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
{ {
if (! image.isValid())
return false;
using namespace pnglibNamespace; using namespace pnglibNamespace;
auto width = image.getWidth(); auto width = image.getWidth();
auto height = image.getHeight(); auto height = image.getHeight();
HeapBlock<uint8> rowData (width * 4);
const Image::BitmapData srcData (image, Image::BitmapData::readOnly);
auto pngWriteStruct = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); auto pngWriteStruct = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (pngWriteStruct == nullptr) if (pngWriteStruct == nullptr)
return false; return false;
jmp_buf errorJumpBuf;
png_set_error_fn (pngWriteStruct, &errorJumpBuf, PNGHelpers::errorCallback, PNGHelpers::warningCallback);
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4611)
if (setjmp (errorJumpBuf) != 0)
return false;
JUCE_END_IGNORE_WARNINGS_MSVC
auto pngInfoStruct = png_create_info_struct (pngWriteStruct); auto pngInfoStruct = png_create_info_struct (pngWriteStruct);
if (pngInfoStruct == nullptr) if (pngInfoStruct == nullptr)
@ -554,8 +570,6 @@ bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
PNG_COMPRESSION_TYPE_BASE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE); PNG_FILTER_TYPE_BASE);
HeapBlock<uint8> rowData (width * 4);
png_color_8 sig_bit; png_color_8 sig_bit;
sig_bit.red = 8; sig_bit.red = 8;
sig_bit.green = 8; sig_bit.green = 8;
@ -569,8 +583,6 @@ bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
png_set_shift (pngWriteStruct, &sig_bit); png_set_shift (pngWriteStruct, &sig_bit);
png_set_packing (pngWriteStruct); png_set_packing (pngWriteStruct);
const Image::BitmapData srcData (image, Image::BitmapData::readOnly);
for (int y = 0; y < height; ++y) for (int y = 0; y < height; ++y)
{ {
uint8* dst = rowData; uint8* dst = rowData;