Merge pull request #26720 from vrabaud:png_leak

Use RAII to avoid leaks in PNG reader.
This commit is contained in:
Alexander Smorkalov 2025-01-08 10:57:28 +03:00 committed by GitHub
commit 4b35101d55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 175 additions and 176 deletions

View File

@ -181,8 +181,6 @@ PngDecoder::PngDecoder()
{
m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
m_color_type = 0;
m_png_ptr = nullptr;
m_info_ptr = m_end_info = nullptr;
m_f = 0;
m_buf_supported = true;
m_buf_pos = 0;
@ -205,15 +203,6 @@ PngDecoder::~PngDecoder()
fclose( m_f );
m_f = nullptr;
}
if( m_png_ptr )
{
png_structp png_ptr = (png_structp)m_png_ptr;
png_infop info_ptr = (png_infop)m_info_ptr;
png_infop end_info = (png_infop)m_end_info;
png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
m_png_ptr = m_info_ptr = m_end_info = nullptr;
}
}
ImageDecoder PngDecoder::newDecoder() const
@ -240,19 +229,14 @@ bool PngDecoder::readHeader()
{
volatile bool result = false;
png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
png_infop info_ptr = nullptr;
png_infop end_info = nullptr;
PngPtrs png_ptrs;
png_structp png_ptr = png_ptrs.getPng();
png_infop info_ptr = png_ptrs.getInfo();
png_infop end_info = png_ptrs.getEndInfo();
if( png_ptr )
if( png_ptr && info_ptr && end_info )
{
info_ptr = png_create_info_struct( png_ptr );
end_info = png_create_info_struct( png_ptr );
m_buf_pos = 0;
if( info_ptr && end_info )
{
if( setjmp( png_jmpbuf( png_ptr ) ) == 0 )
{
unsigned char sig[8];
@ -266,7 +250,6 @@ bool PngDecoder::readHeader()
m_f = fopen(m_filename.c_str(), "rb");
if (!m_f)
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return false;
}
png_init_io(png_ptr, m_f);
@ -283,7 +266,6 @@ bool PngDecoder::readHeader()
if (!(id == id_IHDR && m_chunkIHDR.p.size() == 25))
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return false;
}
@ -294,7 +276,6 @@ bool PngDecoder::readHeader()
if ((m_f && feof(m_f)) || (!m_buf.empty() && m_buf_pos > m_buf.total()))
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return false;
}
@ -387,17 +368,10 @@ bool PngDecoder::readHeader()
}
}
}
}
if(result)
{
m_png_ptr = png_ptr;
m_info_ptr = info_ptr;
m_end_info = end_info;
}
else
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
m_png_ptrs = std::move(png_ptrs);
}
return result;
@ -430,8 +404,8 @@ bool PngDecoder::readData( Mat& img )
frameCur.setMat(mat_cur);
processing_start((void*)&frameRaw, mat_cur);
png_structp png_ptr = (png_structp)m_png_ptr;
png_infop info_ptr = (png_infop)m_info_ptr;
png_structp png_ptr = m_png_ptrs.getPng();
png_infop info_ptr = m_png_ptrs.getInfo();
while (true)
{
@ -540,11 +514,11 @@ bool PngDecoder::readData( Mat& img )
unsigned char** buffer = _buffer.data();
bool color = img.channels() > 1;
png_structp png_ptr = (png_structp)m_png_ptr;
png_infop info_ptr = (png_infop)m_info_ptr;
png_infop end_info = (png_infop)m_end_info;
png_structp png_ptr = m_png_ptrs.getPng();
png_infop info_ptr = m_png_ptrs.getInfo();
png_infop end_info = m_png_ptrs.getEndInfo();
if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
if( png_ptr && info_ptr && end_info && m_width && m_height )
{
if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
{
@ -735,30 +709,20 @@ bool PngDecoder::processing_start(void* frame_ptr, const Mat& img)
{
static uint8_t header[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
if (m_png_ptr)
{
png_structp png_ptr = (png_structp)m_png_ptr;
png_infop info_ptr = (png_infop)m_info_ptr;
png_infop end_info = (png_infop)m_end_info;
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
m_png_ptr = m_info_ptr = m_end_info = nullptr;
}
PngPtrs png_ptrs;
png_structp png_ptr = png_ptrs.getPng();
png_infop info_ptr = png_ptrs.getInfo();
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);
m_png_ptr = png_ptr;
m_info_ptr = info_ptr;
if (!png_ptr || !info_ptr)
if (!png_ptr || !info_ptr) {
return false;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
return false;
}
m_png_ptrs = std::move(png_ptrs);
png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
png_set_progressive_read_fn(png_ptr, frame_ptr, (png_progressive_info_ptr)info_fn, row_fn, NULL);
@ -787,24 +751,22 @@ bool PngDecoder::processing_finish()
{
static uint8_t footer[12] = { 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130 };
png_structp png_ptr = (png_structp)m_png_ptr;
png_infop info_ptr = (png_infop)m_info_ptr;
png_infop end_info = (png_infop)m_end_info;
png_structp png_ptr = m_png_ptrs.getPng();
png_infop info_ptr = m_png_ptrs.getInfo();
if (!png_ptr)
if (!png_ptr) {
m_png_ptrs.clear();
return false;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
m_png_ptrs.clear();
return false;
}
png_process_data(png_ptr, info_ptr, footer, 12);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
m_png_ptr = nullptr;
m_info_ptr = nullptr;
m_end_info = nullptr;
m_png_ptrs.clear();
return true;
}

View File

@ -140,10 +140,47 @@ protected:
size_t read_from_io(void* _Buffer, size_t _ElementSize, size_t _ElementCount);
uint32_t read_chunk(Chunk& chunk);
struct PngPtrs {
public:
PngPtrs() {
png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
if (png_ptr) {
info_ptr = png_create_info_struct( png_ptr );
end_info = png_create_info_struct( png_ptr );
} else {
info_ptr = end_info = nullptr;
}
}
~PngPtrs() {
clear();
}
PngPtrs& operator=(PngPtrs&& other) {
clear();
png_ptr = other.png_ptr;
info_ptr = other.info_ptr;
end_info = other.end_info;
other.png_ptr = nullptr;
other.info_ptr = other.end_info = nullptr;
return *this;
}
void clear() {
if (png_ptr) {
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
png_ptr = nullptr;
info_ptr = end_info = nullptr;
}
}
png_structp getPng() const { return png_ptr; }
png_infop getInfo() const { return info_ptr; }
png_infop getEndInfo() const { return end_info; }
private:
png_structp png_ptr; // pointer to decompression structure
png_infop info_ptr; // pointer to image information structure
png_infop end_info; // pointer to one more image information structure
};
PngPtrs m_png_ptrs;
int m_bit_depth;
void* m_png_ptr; // pointer to decompression structure
void* m_info_ptr; // pointer to image information structure
void* m_end_info; // pointer to one more image information structure
FILE* m_f;
int m_color_type;
Chunk m_chunkIHDR;