mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #5763
5763: Fix png error handling by setting jmpbuf r=def- a=Jupeyy else libpng will kill the thread on an error bcs it's a fatal error. broken skin can be found in discord bugs channel weeb_okayu ## Checklist - [x] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test (especially base/) or added coverage to integration test - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Jupeyy <jupjopjap@gmail.com>
This commit is contained in:
commit
59db32e9c2
|
@ -1,6 +1,7 @@
|
||||||
#include "image_loader.h"
|
#include "image_loader.h"
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
#include <base/system.h>
|
#include <base/system.h>
|
||||||
|
#include <csetjmp>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
|
@ -8,20 +9,22 @@
|
||||||
struct SLibPNGWarningItem
|
struct SLibPNGWarningItem
|
||||||
{
|
{
|
||||||
SImageByteBuffer *m_pByteLoader;
|
SImageByteBuffer *m_pByteLoader;
|
||||||
const char *pFileName;
|
const char *m_pFileName;
|
||||||
|
std::jmp_buf m_Buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void LibPNGError(png_structp png_ptr, png_const_charp error_msg)
|
[[noreturn]] static void LibPNGError(png_structp png_ptr, png_const_charp error_msg)
|
||||||
{
|
{
|
||||||
SLibPNGWarningItem *pUserStruct = (SLibPNGWarningItem *)png_get_error_ptr(png_ptr);
|
SLibPNGWarningItem *pUserStruct = (SLibPNGWarningItem *)png_get_error_ptr(png_ptr);
|
||||||
pUserStruct->m_pByteLoader->m_Err = -1;
|
pUserStruct->m_pByteLoader->m_Err = -1;
|
||||||
dbg_msg("libpng", "error for file \"%s\": %s", pUserStruct->pFileName, error_msg);
|
dbg_msg("libpng", "error for file \"%s\": %s", pUserStruct->m_pFileName, error_msg);
|
||||||
|
std::longjmp(pUserStruct->m_Buf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LibPNGWarning(png_structp png_ptr, png_const_charp warning_msg)
|
static void LibPNGWarning(png_structp png_ptr, png_const_charp warning_msg)
|
||||||
{
|
{
|
||||||
SLibPNGWarningItem *pUserStruct = (SLibPNGWarningItem *)png_get_error_ptr(png_ptr);
|
SLibPNGWarningItem *pUserStruct = (SLibPNGWarningItem *)png_get_error_ptr(png_ptr);
|
||||||
dbg_msg("libpng", "warning for file \"%s\": %s", pUserStruct->pFileName, warning_msg);
|
dbg_msg("libpng", "warning for file \"%s\": %s", pUserStruct->m_pFileName, warning_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool FileMatchesImageType(SImageByteBuffer &ByteLoader)
|
static bool FileMatchesImageType(SImageByteBuffer &ByteLoader)
|
||||||
|
@ -75,6 +78,7 @@ static void LibPNGSetImageFormat(EImageFormat &ImageFormat, int LibPNGColorType)
|
||||||
|
|
||||||
static void LibPNGDeleteReadStruct(png_structp pPNGStruct, png_infop pPNGInfo)
|
static void LibPNGDeleteReadStruct(png_structp pPNGStruct, png_infop pPNGInfo)
|
||||||
{
|
{
|
||||||
|
if(pPNGInfo != nullptr)
|
||||||
png_destroy_info_struct(pPNGStruct, &pPNGInfo);
|
png_destroy_info_struct(pPNGStruct, &pPNGInfo);
|
||||||
png_destroy_read_struct(&pPNGStruct, NULL, NULL);
|
png_destroy_read_struct(&pPNGStruct, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
@ -127,6 +131,15 @@ static int PngliteIncompatibility(png_structp pPNGStruct, png_infop pPNGInfo)
|
||||||
|
|
||||||
bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIncompatible, int &Width, int &Height, uint8_t *&pImageBuff, EImageFormat &ImageFormat)
|
bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIncompatible, int &Width, int &Height, uint8_t *&pImageBuff, EImageFormat &ImageFormat)
|
||||||
{
|
{
|
||||||
|
png_infop pPNGInfo = nullptr;
|
||||||
|
int ColorType;
|
||||||
|
png_byte BitDepth;
|
||||||
|
int ColorChannelCount;
|
||||||
|
int BytesInRow;
|
||||||
|
Height = 0;
|
||||||
|
png_bytepp pRowPointers = nullptr;
|
||||||
|
SLibPNGWarningItem UserErrorStruct = {&ByteLoader, pFileName, {}};
|
||||||
|
|
||||||
png_structp pPNGStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
png_structp pPNGStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
|
||||||
if(pPNGStruct == NULL)
|
if(pPNGStruct == NULL)
|
||||||
|
@ -135,7 +148,22 @@ bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIn
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
png_infop pPNGInfo = png_create_info_struct(pPNGStruct);
|
if(setjmp(UserErrorStruct.m_Buf))
|
||||||
|
{
|
||||||
|
if(pRowPointers != nullptr)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < Height; ++i)
|
||||||
|
{
|
||||||
|
delete[] pRowPointers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] pRowPointers;
|
||||||
|
LibPNGDeleteReadStruct(pPNGStruct, pPNGInfo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
png_set_error_fn(pPNGStruct, &UserErrorStruct, LibPNGError, LibPNGWarning);
|
||||||
|
|
||||||
|
pPNGInfo = png_create_info_struct(pPNGStruct);
|
||||||
|
|
||||||
if(pPNGInfo == NULL)
|
if(pPNGInfo == NULL)
|
||||||
{
|
{
|
||||||
|
@ -144,9 +172,6 @@ bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIn
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SLibPNGWarningItem UserErrorStruct = {&ByteLoader, pFileName};
|
|
||||||
png_set_error_fn(pPNGStruct, &UserErrorStruct, LibPNGError, LibPNGWarning);
|
|
||||||
|
|
||||||
if(!FileMatchesImageType(ByteLoader))
|
if(!FileMatchesImageType(ByteLoader))
|
||||||
{
|
{
|
||||||
LibPNGDeleteReadStruct(pPNGStruct, pPNGInfo);
|
LibPNGDeleteReadStruct(pPNGStruct, pPNGInfo);
|
||||||
|
@ -169,12 +194,10 @@ bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIn
|
||||||
|
|
||||||
Width = png_get_image_width(pPNGStruct, pPNGInfo);
|
Width = png_get_image_width(pPNGStruct, pPNGInfo);
|
||||||
Height = png_get_image_height(pPNGStruct, pPNGInfo);
|
Height = png_get_image_height(pPNGStruct, pPNGInfo);
|
||||||
int ColorType = png_get_color_type(pPNGStruct, pPNGInfo);
|
ColorType = png_get_color_type(pPNGStruct, pPNGInfo);
|
||||||
png_byte BitDepth = png_get_bit_depth(pPNGStruct, pPNGInfo);
|
BitDepth = png_get_bit_depth(pPNGStruct, pPNGInfo);
|
||||||
PngliteIncompatible = PngliteIncompatibility(pPNGStruct, pPNGInfo);
|
PngliteIncompatible = PngliteIncompatibility(pPNGStruct, pPNGInfo);
|
||||||
|
|
||||||
bool PNGErr = false;
|
|
||||||
|
|
||||||
if(BitDepth == 16)
|
if(BitDepth == 16)
|
||||||
{
|
{
|
||||||
png_set_strip_16(pPNGStruct);
|
png_set_strip_16(pPNGStruct);
|
||||||
|
@ -182,17 +205,17 @@ bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIn
|
||||||
else if(BitDepth > 8)
|
else if(BitDepth > 8)
|
||||||
{
|
{
|
||||||
dbg_msg("png", "non supported bit depth.");
|
dbg_msg("png", "non supported bit depth.");
|
||||||
PNGErr = true;
|
LibPNGDeleteReadStruct(pPNGStruct, pPNGInfo);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Width == 0 || Height == 0 || BitDepth == 0)
|
if(Width == 0 || Height == 0 || BitDepth == 0)
|
||||||
{
|
{
|
||||||
dbg_msg("png", "image had width, height or bit depth of 0.");
|
dbg_msg("png", "image had width, height or bit depth of 0.");
|
||||||
PNGErr = true;
|
LibPNGDeleteReadStruct(pPNGStruct, pPNGInfo);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!PNGErr)
|
|
||||||
{
|
|
||||||
if(ColorType == PNG_COLOR_TYPE_PALETTE)
|
if(ColorType == PNG_COLOR_TYPE_PALETTE)
|
||||||
png_set_palette_to_rgb(pPNGStruct);
|
png_set_palette_to_rgb(pPNGStruct);
|
||||||
|
|
||||||
|
@ -204,12 +227,12 @@ bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIn
|
||||||
|
|
||||||
png_read_update_info(pPNGStruct, pPNGInfo);
|
png_read_update_info(pPNGStruct, pPNGInfo);
|
||||||
|
|
||||||
int ColorChannelCount = LibPNGGetColorChannelCount(ColorType);
|
ColorChannelCount = LibPNGGetColorChannelCount(ColorType);
|
||||||
int BytesInRow = png_get_rowbytes(pPNGStruct, pPNGInfo);
|
BytesInRow = png_get_rowbytes(pPNGStruct, pPNGInfo);
|
||||||
|
|
||||||
if(BytesInRow == Width * ColorChannelCount)
|
if(BytesInRow == Width * ColorChannelCount)
|
||||||
{
|
{
|
||||||
png_bytepp pRowPointers = new png_bytep[Height];
|
pRowPointers = new png_bytep[Height];
|
||||||
for(int y = 0; y < Height; ++y)
|
for(int y = 0; y < Height; ++y)
|
||||||
{
|
{
|
||||||
pRowPointers[y] = new png_byte[BytesInRow];
|
pRowPointers[y] = new png_byte[BytesInRow];
|
||||||
|
@ -219,8 +242,6 @@ bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIn
|
||||||
|
|
||||||
if(ByteLoader.m_Err == 0)
|
if(ByteLoader.m_Err == 0)
|
||||||
pImageBuff = (uint8_t *)malloc((size_t)Height * (size_t)Width * (size_t)ColorChannelCount * sizeof(uint8_t));
|
pImageBuff = (uint8_t *)malloc((size_t)Height * (size_t)Width * (size_t)ColorChannelCount * sizeof(uint8_t));
|
||||||
else
|
|
||||||
PNGErr = true;
|
|
||||||
|
|
||||||
for(int i = 0; i < Height; ++i)
|
for(int i = 0; i < Height; ++i)
|
||||||
{
|
{
|
||||||
|
@ -229,17 +250,26 @@ bool LoadPNG(SImageByteBuffer &ByteLoader, const char *pFileName, int &PngliteIn
|
||||||
delete[] pRowPointers[i];
|
delete[] pRowPointers[i];
|
||||||
}
|
}
|
||||||
delete[] pRowPointers;
|
delete[] pRowPointers;
|
||||||
|
pRowPointers = nullptr;
|
||||||
|
|
||||||
|
if(ByteLoader.m_Err != 0)
|
||||||
|
{
|
||||||
|
LibPNGDeleteReadStruct(pPNGStruct, pPNGInfo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LibPNGSetImageFormat(ImageFormat, ColorType);
|
LibPNGSetImageFormat(ImageFormat, ColorType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PNGErr = true;
|
{
|
||||||
|
LibPNGDeleteReadStruct(pPNGStruct, pPNGInfo);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
png_destroy_info_struct(pPNGStruct, &pPNGInfo);
|
png_destroy_info_struct(pPNGStruct, &pPNGInfo);
|
||||||
png_destroy_read_struct(&pPNGStruct, NULL, NULL);
|
png_destroy_read_struct(&pPNGStruct, NULL, NULL);
|
||||||
|
|
||||||
return !PNGErr;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteDataFromLoadedBytes(png_structp pPNGStruct, png_bytep pOutBytes, png_size_t ByteCountToWrite)
|
static void WriteDataFromLoadedBytes(png_structp pPNGStruct, png_bytep pOutBytes, png_size_t ByteCountToWrite)
|
||||||
|
|
Loading…
Reference in a new issue