mirror of
https://github.com/opencv/opencv.git
synced 2025-07-24 14:06:27 +08:00
Merge pull request #26720 from vrabaud:png_leak
Use RAII to avoid leaks in PNG reader.
This commit is contained in:
commit
4b35101d55
@ -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,164 +229,149 @@ 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 )
|
||||
{
|
||||
if( setjmp( png_jmpbuf( png_ptr ) ) == 0 )
|
||||
unsigned char sig[8];
|
||||
uint32_t id = 0;
|
||||
Chunk chunk;
|
||||
|
||||
if( !m_buf.empty() )
|
||||
png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
|
||||
else
|
||||
{
|
||||
unsigned char sig[8];
|
||||
uint32_t id = 0;
|
||||
Chunk chunk;
|
||||
|
||||
if( !m_buf.empty() )
|
||||
png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
|
||||
else
|
||||
m_f = fopen(m_filename.c_str(), "rb");
|
||||
if (!m_f)
|
||||
{
|
||||
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);
|
||||
|
||||
if (fread(sig, 1, 8, m_f))
|
||||
id = read_chunk(m_chunkIHDR);
|
||||
return false;
|
||||
}
|
||||
png_init_io(png_ptr, m_f);
|
||||
|
||||
if (id != id_IHDR)
|
||||
{
|
||||
read_from_io(&sig, 8, 1);
|
||||
if (fread(sig, 1, 8, m_f))
|
||||
id = read_chunk(m_chunkIHDR);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(id == id_IHDR && m_chunkIHDR.p.size() == 25))
|
||||
if (id != id_IHDR)
|
||||
{
|
||||
read_from_io(&sig, 8, 1);
|
||||
id = read_chunk(m_chunkIHDR);
|
||||
}
|
||||
|
||||
if (!(id == id_IHDR && m_chunkIHDR.p.size() == 25))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
m_is_fcTL_loaded = false;
|
||||
id = read_chunk(chunk);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
while (true)
|
||||
if (id == id_IDAT)
|
||||
{
|
||||
m_is_fcTL_loaded = false;
|
||||
id = read_chunk(chunk);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (id == id_IDAT)
|
||||
{
|
||||
if (m_f)
|
||||
fseek(m_f, 0, SEEK_SET);
|
||||
else
|
||||
m_buf_pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (id == id_acTL && chunk.p.size() == 20)
|
||||
{
|
||||
m_animation.loop_count = png_get_uint_32(&chunk.p[12]);
|
||||
|
||||
if (chunk.p[8] > 0)
|
||||
{
|
||||
chunk.p[8] = 0;
|
||||
chunk.p[9] = 0;
|
||||
m_frame_count = png_get_uint_32(&chunk.p[8]);
|
||||
m_frame_count++;
|
||||
}
|
||||
else
|
||||
m_frame_count = png_get_uint_32(&chunk.p[8]);
|
||||
}
|
||||
|
||||
if (id == id_fcTL)
|
||||
{
|
||||
m_is_fcTL_loaded = true;
|
||||
w0 = png_get_uint_32(&chunk.p[12]);
|
||||
h0 = png_get_uint_32(&chunk.p[16]);
|
||||
x0 = png_get_uint_32(&chunk.p[20]);
|
||||
y0 = png_get_uint_32(&chunk.p[24]);
|
||||
delay_num = png_get_uint_16(&chunk.p[28]);
|
||||
delay_den = png_get_uint_16(&chunk.p[30]);
|
||||
dop = chunk.p[32];
|
||||
bop = chunk.p[33];
|
||||
}
|
||||
|
||||
if (id == id_bKGD)
|
||||
{
|
||||
int bgcolor = png_get_uint_32(&chunk.p[8]);
|
||||
m_animation.bgcolor[3] = (bgcolor >> 24) & 0xFF;
|
||||
m_animation.bgcolor[2] = (bgcolor >> 16) & 0xFF;
|
||||
m_animation.bgcolor[1] = (bgcolor >> 8) & 0xFF;
|
||||
m_animation.bgcolor[0] = bgcolor & 0xFF;
|
||||
}
|
||||
|
||||
if (id == id_PLTE || id == id_tRNS)
|
||||
m_chunksInfo.push_back(chunk);
|
||||
if (m_f)
|
||||
fseek(m_f, 0, SEEK_SET);
|
||||
else
|
||||
m_buf_pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
png_uint_32 wdth, hght;
|
||||
int bit_depth, color_type, num_trans=0;
|
||||
png_bytep trans;
|
||||
png_color_16p trans_values;
|
||||
|
||||
png_read_info( png_ptr, info_ptr );
|
||||
png_get_IHDR(png_ptr, info_ptr, &wdth, &hght,
|
||||
&bit_depth, &color_type, 0, 0, 0);
|
||||
|
||||
m_width = (int)wdth;
|
||||
m_height = (int)hght;
|
||||
m_color_type = color_type;
|
||||
m_bit_depth = bit_depth;
|
||||
|
||||
if (bit_depth <= 8 || bit_depth == 16)
|
||||
if (id == id_acTL && chunk.p.size() == 20)
|
||||
{
|
||||
switch (color_type)
|
||||
m_animation.loop_count = png_get_uint_32(&chunk.p[12]);
|
||||
|
||||
if (chunk.p[8] > 0)
|
||||
{
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
|
||||
if (num_trans > 0)
|
||||
m_type = CV_8UC4;
|
||||
else
|
||||
m_type = CV_8UC3;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
chunk.p[8] = 0;
|
||||
chunk.p[9] = 0;
|
||||
m_frame_count = png_get_uint_32(&chunk.p[8]);
|
||||
m_frame_count++;
|
||||
}
|
||||
else
|
||||
m_frame_count = png_get_uint_32(&chunk.p[8]);
|
||||
}
|
||||
|
||||
if (id == id_fcTL)
|
||||
{
|
||||
m_is_fcTL_loaded = true;
|
||||
w0 = png_get_uint_32(&chunk.p[12]);
|
||||
h0 = png_get_uint_32(&chunk.p[16]);
|
||||
x0 = png_get_uint_32(&chunk.p[20]);
|
||||
y0 = png_get_uint_32(&chunk.p[24]);
|
||||
delay_num = png_get_uint_16(&chunk.p[28]);
|
||||
delay_den = png_get_uint_16(&chunk.p[30]);
|
||||
dop = chunk.p[32];
|
||||
bop = chunk.p[33];
|
||||
}
|
||||
|
||||
if (id == id_bKGD)
|
||||
{
|
||||
int bgcolor = png_get_uint_32(&chunk.p[8]);
|
||||
m_animation.bgcolor[3] = (bgcolor >> 24) & 0xFF;
|
||||
m_animation.bgcolor[2] = (bgcolor >> 16) & 0xFF;
|
||||
m_animation.bgcolor[1] = (bgcolor >> 8) & 0xFF;
|
||||
m_animation.bgcolor[0] = bgcolor & 0xFF;
|
||||
}
|
||||
|
||||
if (id == id_PLTE || id == id_tRNS)
|
||||
m_chunksInfo.push_back(chunk);
|
||||
}
|
||||
|
||||
png_uint_32 wdth, hght;
|
||||
int bit_depth, color_type, num_trans=0;
|
||||
png_bytep trans;
|
||||
png_color_16p trans_values;
|
||||
|
||||
png_read_info( png_ptr, info_ptr );
|
||||
png_get_IHDR(png_ptr, info_ptr, &wdth, &hght,
|
||||
&bit_depth, &color_type, 0, 0, 0);
|
||||
|
||||
m_width = (int)wdth;
|
||||
m_height = (int)hght;
|
||||
m_color_type = color_type;
|
||||
m_bit_depth = bit_depth;
|
||||
|
||||
if (bit_depth <= 8 || bit_depth == 16)
|
||||
{
|
||||
switch (color_type)
|
||||
{
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
|
||||
if (num_trans > 0)
|
||||
m_type = CV_8UC4;
|
||||
break;
|
||||
default:
|
||||
m_type = CV_8UC1;
|
||||
}
|
||||
if (bit_depth == 16)
|
||||
m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
|
||||
result = true;
|
||||
else
|
||||
m_type = CV_8UC3;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
m_type = CV_8UC4;
|
||||
break;
|
||||
default:
|
||||
m_type = CV_8UC1;
|
||||
}
|
||||
if (bit_depth == 16)
|
||||
m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user