Merge pull request #27750 from Kumataro:fix27744

png: add setjmp() to detect libpng internal error for APNG
This commit is contained in:
Alexander Smorkalov 2025-09-11 10:23:46 +03:00 committed by GitHub
commit 16c8308674
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -434,138 +434,147 @@ bool PngDecoder::readData( Mat& img )
if (!processing_start((void*)&frameRaw, mat_cur))
return false;
while (true)
// See https://github.com/opencv/opencv/issues/27744
if( setjmp( png_jmpbuf ( m_png_ptr ) ) == 0 )
{
id = read_chunk(chunk);
if (!id)
return false;
if (id == id_fcTL && m_is_IDAT_loaded)
while (true)
{
if (!m_is_fcTL_loaded)
id = read_chunk(chunk);
if (!id)
return false;
if (id == id_fcTL && m_is_IDAT_loaded)
{
m_mat_raw.copyTo(m_animation.still_image);
}
else
{
if (processing_finish())
if (!m_is_fcTL_loaded)
{
if (dop == 2)
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
if (x0 + w0 > frameCur.getWidth() || y0 + h0 > frameCur.getHeight())
return false;
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
if (!delay_den)
delay_den = 100;
m_animation.durations.push_back(cvRound(1000. * delay_num / delay_den));
if (mat_cur.channels() == img.channels())
m_mat_raw.copyTo(m_animation.still_image);
}
else
{
if (processing_finish())
{
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
mat_cur.convertTo(img, CV_8U, 1. / 255);
if (dop == 2)
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
if (x0 + w0 > frameCur.getWidth() || y0 + h0 > frameCur.getHeight())
return false;
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
if (!delay_den)
delay_den = 100;
m_animation.durations.push_back(cvRound(1000. * delay_num / delay_den));
if (mat_cur.channels() == img.channels())
{
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
mat_cur.convertTo(img, CV_8U, 1. / 255);
else
mat_cur.copyTo(img);
}
else
mat_cur.copyTo(img);
{
Mat mat_cur_scaled;
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
mat_cur.convertTo(mat_cur_scaled, CV_8U, 1. / 255);
else
mat_cur_scaled = mat_cur;
if (img.channels() == 1)
cvtColor(mat_cur_scaled, img, COLOR_BGRA2GRAY);
else if (img.channels() == 3)
cvtColor(mat_cur_scaled, img, COLOR_BGRA2BGR);
}
if (dop != 2)
{
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
if (dop == 1)
for (j = 0; j < h0; j++)
memset(frameNext.getRows()[y0 + j] + x0 * img.channels(), 0, w0 * img.channels());
}
}
else
{
Mat mat_cur_scaled;
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
mat_cur.convertTo(mat_cur_scaled, CV_8U, 1. / 255);
else
mat_cur_scaled = mat_cur;
if (img.channels() == 1)
cvtColor(mat_cur_scaled, img, COLOR_BGRA2GRAY);
else if (img.channels() == 3)
cvtColor(mat_cur_scaled, img, COLOR_BGRA2BGR);
return false;
}
}
if (dop != 2)
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 (int(x0 + w0) > img.cols || int(y0 + h0) > img.rows || dop > 2 || bop > 1)
{
return false;
}
memcpy(&m_chunkIHDR.p[8], &chunk.p[12], 8);
if (m_is_fcTL_loaded)
return true;
else
{
m_is_fcTL_loaded = true;
ClearPngPtr();
if (!processing_start((void*)&frameRaw, mat_cur))
return false;
}
}
else if (id == id_IDAT)
{
m_is_IDAT_loaded = true;
png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size());
}
else if (id == id_fdAT && m_is_fcTL_loaded)
{
m_is_IDAT_loaded = true;
png_save_uint_32(&chunk.p[4], static_cast<uint32_t>(chunk.p.size() - 16));
memcpy(&chunk.p[8], "IDAT", 4);
png_process_data(m_png_ptr, m_info_ptr, &chunk.p[4], chunk.p.size() - 4);
}
else if (id == id_IEND)
{
if (processing_finish())
{
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
if (!delay_den)
delay_den = 100;
m_animation.durations.push_back(cvRound(1000.*delay_num/delay_den));
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U && mat_cur.channels() == img.channels())
mat_cur.convertTo(img, CV_8U, 1. / 255);
else
{
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
if (dop == 1)
for (j = 0; j < h0; j++)
memset(frameNext.getRows()[y0 + j] + x0 * img.channels(), 0, w0 * img.channels());
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
mat_cur.convertTo(mat_cur, CV_8U, 1. / 255);
if (mat_cur.channels() == img.channels())
mat_cur.copyTo(img);
else if (img.channels() == 1)
cvtColor(mat_cur, img, COLOR_BGRA2GRAY);
else if (img.channels() == 3)
cvtColor(mat_cur, img, COLOR_BGRA2BGR);
}
}
else
{
return false;
}
}
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 (int(x0 + w0) > img.cols || int(y0 + h0) > img.rows || dop > 2 || bop > 1)
{
return false;
}
memcpy(&m_chunkIHDR.p[8], &chunk.p[12], 8);
if (m_is_fcTL_loaded)
return true;
else
{
m_is_fcTL_loaded = true;
ClearPngPtr();
if (!processing_start((void*)&frameRaw, mat_cur))
return false;
}
}
else if (id == id_IDAT)
{
m_is_IDAT_loaded = true;
png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size());
}
else if (id == id_fdAT && m_is_fcTL_loaded)
{
m_is_IDAT_loaded = true;
png_save_uint_32(&chunk.p[4], static_cast<uint32_t>(chunk.p.size() - 16));
memcpy(&chunk.p[8], "IDAT", 4);
png_process_data(m_png_ptr, m_info_ptr, &chunk.p[4], chunk.p.size() - 4);
}
else if (id == id_IEND)
{
if (processing_finish())
{
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
if (!delay_den)
delay_den = 100;
m_animation.durations.push_back(cvRound(1000.*delay_num/delay_den));
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U && mat_cur.channels() == img.channels())
mat_cur.convertTo(img, CV_8U, 1. / 255);
else
{
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
mat_cur.convertTo(mat_cur, CV_8U, 1. / 255);
if (mat_cur.channels() == img.channels())
mat_cur.copyTo(img);
else if (img.channels() == 1)
cvtColor(mat_cur, img, COLOR_BGRA2GRAY);
else if (img.channels() == 3)
cvtColor(mat_cur, img, COLOR_BGRA2BGR);
}
}
else
return false;
return true;
png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size());
}
else
png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size());
return false;
}
else
{
// libpng internal error is detected.
return false;
}
return false;
}
volatile bool result = false;