mirror of
https://github.com/GerbilSoft/rom-properties.git
synced 2025-06-18 11:35:38 -04:00
[librpbase] RpPng: Work around a potential libpng crash when attempting to read empty data as a PNG image.
Check the magic number before initializing libpng. It seems there's something wrong with MSVC 2022 (17.6.5) that causes a release build of libpng to crash when calling longjmp() on Windows 10. If this is in fact a compiler bug, and upgrading the compiler fixes it, then I'll need to switch away from my Windows 7 VM because MSVC 17.6 is the last version to support Windows 7 as a build environment. See #451: libpng errors crash due to libpng setjmp/longjmp (Windows 10, release builds only) Reported by @Masamune3210.
This commit is contained in:
parent
223cee6c9c
commit
34f76050cb
5
NEWS.md
5
NEWS.md
@ -2,6 +2,11 @@
|
||||
|
||||
## v2.6 (released 2025/??/??)
|
||||
|
||||
* Bug fixes:
|
||||
* Windows: Work around a potential libpng crash when attempting to read
|
||||
empty data as a PNG image. (Needs more debugging for a proper fix...)
|
||||
* See #451: libpng errors crash due to libpng setjmp/longjmp (Windows 10, release builds only)
|
||||
* Reported by @Masamune3210.
|
||||
* Other changes:
|
||||
* rpcli: Added more colorization for warning messages.
|
||||
* rpcli: Refactored console handling into a separate library, libgsvt.
|
||||
|
@ -21,6 +21,7 @@ using namespace LibRpTexture;
|
||||
#include "RpPngWriter.hpp"
|
||||
|
||||
// C++ STL classes
|
||||
using std::array;
|
||||
using std::unique_ptr;
|
||||
|
||||
// Image format libraries
|
||||
@ -243,8 +244,9 @@ static rp_image_ptr loadPng(png_structp png_ptr, png_infop info_ptr)
|
||||
// WARNING: Do NOT initialize any C++ objects past this point!
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
// PNG read failed.
|
||||
// FIXME: This is crashing in MSVC 2022 (17.6.5) release builds on Windows 10.
|
||||
png_free(png_ptr, row_pointers);
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -270,7 +272,7 @@ static rp_image_ptr loadPng(png_structp png_ptr, png_infop info_ptr)
|
||||
width > 32768 || height > 32768)
|
||||
{
|
||||
// Image size is either invalid or too big.
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef PNG_sBIT_SUPPORTED
|
||||
@ -386,7 +388,7 @@ static rp_image_ptr loadPng(png_structp png_ptr, png_infop info_ptr)
|
||||
|
||||
default:
|
||||
// Unsupported color type.
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (bit_depth > 8) {
|
||||
@ -423,14 +425,14 @@ static rp_image_ptr loadPng(png_structp png_ptr, png_infop info_ptr)
|
||||
img = std::make_shared<rp_image>(width, height, fmt);
|
||||
if (!img->isValid()) {
|
||||
// Could not allocate the image.
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Allocate the row pointers.
|
||||
row_pointers = static_cast<const png_byte**>(
|
||||
png_malloc(png_ptr, sizeof(const png_byte*) * height));
|
||||
if (!row_pointers) {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Initialize the row pointers array.
|
||||
@ -473,14 +475,15 @@ static rp_image_ptr loadPng(png_structp png_ptr, png_infop info_ptr)
|
||||
*/
|
||||
rp_image_ptr load(IRpFile *file)
|
||||
{
|
||||
if (!file)
|
||||
return nullptr;
|
||||
if (!file) {
|
||||
return {};
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && (defined(ZLIB_IS_DLL) || defined(PNG_IS_DLL))
|
||||
// Delay load verification.
|
||||
if (DelayLoad_test_zlib_and_png() != 0) {
|
||||
// Delay load failed.
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
#else /* !defined(_MSC_VER) || (!defined(ZLIB_IS_DLL) && !defined(PNG_IS_DLL)) */
|
||||
// zlib isn't in a DLL, but we need to ensure that the
|
||||
@ -488,6 +491,14 @@ rp_image_ptr load(IRpFile *file)
|
||||
get_crc_table();
|
||||
#endif /* defined(_MSC_VER) && (defined(ZLIB_IS_DLL) || defined(PNG_IS_DLL)) */
|
||||
|
||||
// Verify the PNG header.
|
||||
static constexpr array<uint8_t, 8> png_magic = {{0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n'}};
|
||||
uint8_t file_header[8];
|
||||
size_t size = file->seekAndRead(0, file_header, sizeof(file_header));
|
||||
if (size != sizeof(file_header) || memcmp(file_header, png_magic.data(), sizeof(file_header)) != 0) {
|
||||
// Not a valid PNG file.
|
||||
return {};
|
||||
}
|
||||
// Rewind the file.
|
||||
file->rewind();
|
||||
|
||||
@ -497,12 +508,12 @@ rp_image_ptr load(IRpFile *file)
|
||||
// Initialize libpng.
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
if (!png_ptr) {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef PNG_WARNINGS_SUPPORTED
|
||||
@ -536,8 +547,9 @@ int save(const IRpFilePtr &file, const rp_image_const_ptr &img)
|
||||
{
|
||||
assert((bool)file);
|
||||
assert(img != nullptr);
|
||||
if (!file || !file->isOpen() || !img)
|
||||
if (!file || !file->isOpen() || !img) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Create a PNG writer.
|
||||
RpPngWriter pngWriter(file, img);
|
||||
@ -567,8 +579,9 @@ int save(const char *filename, const rp_image_const_ptr &img)
|
||||
assert(filename != nullptr);
|
||||
assert(filename[0] != '\0');
|
||||
assert(img != nullptr);
|
||||
if (!filename || filename[0] == '\0' || !img)
|
||||
if (!filename || filename[0] == '\0' || !img) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Create a PNG writer.
|
||||
RpPngWriter pngWriter(filename, img);
|
||||
@ -599,8 +612,9 @@ int save(const wchar_t *filename, const rp_image_const_ptr &img)
|
||||
assert(filename != nullptr);
|
||||
assert(filename[0] != L'\0');
|
||||
assert(img != nullptr);
|
||||
if (!filename || filename[0] == L'\0' || !img)
|
||||
if (!filename || filename[0] == L'\0' || !img) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Create a PNG writer.
|
||||
RpPngWriter pngWriter(filename, img);
|
||||
|
Loading…
Reference in New Issue
Block a user