diff --git a/modules/imgcodecs/src/grfmt_bmp.cpp b/modules/imgcodecs/src/grfmt_bmp.cpp index 77201b3af1..c8b604166c 100644 --- a/modules/imgcodecs/src/grfmt_bmp.cpp +++ b/modules/imgcodecs/src/grfmt_bmp.cpp @@ -233,9 +233,13 @@ bool BmpDecoder::readData( Mat& img ) bool color = img.channels() > 1; uchar gray_palette[256] = {0}; bool result = false; - int src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4; int nch = color ? 3 : 1; - int y, width3 = m_width*nch; + + const int effective_bpp = (m_bpp != 15) ? m_bpp : 16; + const RowPitchParams pitch_params = calculateRowPitch(m_width, effective_bpp, 4, "BMP"); + const int src_pitch = pitch_params.src_pitch; + const int width3 = calculateRowSize(m_width, nch, "BMP"); + int y; if( m_offset < 0 || !m_strm.isOpened()) return false; @@ -255,7 +259,9 @@ bool BmpDecoder::readData( Mat& img ) { CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp ); } - _bgr.allocate(m_width*3 + 32); + const size_t bgr_size = static_cast(m_width) * 3 + 32; + CV_CheckLT(bgr_size, MAX_IMAGE_ROW_SIZE, "BMP: bgr buffer size exceeds maximum allowed size"); + _bgr.allocate(bgr_size); } uchar *src = _src.data(), *bgr = _bgr.data(); diff --git a/modules/imgcodecs/src/grfmt_sunras.cpp b/modules/imgcodecs/src/grfmt_sunras.cpp index 0dd31b3b1a..06d55d2c44 100644 --- a/modules/imgcodecs/src/grfmt_sunras.cpp +++ b/modules/imgcodecs/src/grfmt_sunras.cpp @@ -133,10 +133,13 @@ bool SunRasterDecoder::readData( Mat& img ) size_t step = img.step; uchar gray_palette[256] = {0}; bool result = false; - int src_pitch = ((m_width*m_bpp + 7)/8 + 1) & -2; int nch = color ? 3 : 1; - int width3 = m_width*nch; - int y; + + const RowPitchParams pitch_params = calculateRowPitch(m_width, m_bpp, 2, "SunRaster"); + const int src_pitch = pitch_params.src_pitch; + const size_t bytes_per_row = pitch_params.bytes_per_row; + const int width3 = calculateRowSize(m_width, nch, "SunRaster"); + int y; if( m_offset < 0 || !m_strm.isOpened()) return false; @@ -169,7 +172,7 @@ bool SunRasterDecoder::readData( Mat& img ) } else { - uchar* line_end = src + (m_width*m_bpp + 7)/8; + uchar* line_end = src + bytes_per_row; uchar* tsrc = src; y = 0; diff --git a/modules/imgcodecs/src/utils.cpp b/modules/imgcodecs/src/utils.cpp index 3b597fe61c..5c3127792a 100644 --- a/modules/imgcodecs/src/utils.cpp +++ b/modules/imgcodecs/src/utils.cpp @@ -51,6 +51,37 @@ int validateToInt(size_t sz) return valueInt; } +RowPitchParams calculateRowPitch(int width, int bpp, int alignment, const char* format_name) +{ + CV_Assert(width > 0 && bpp > 0 && alignment > 0); + CV_Assert((alignment & (alignment - 1)) == 0); // must be power of 2 + + const size_t bits_per_row = static_cast(width) * static_cast(bpp); + const size_t bytes_per_row = (bits_per_row + 7) / 8; + const size_t aligned_pitch = (bytes_per_row + alignment - 1) & ~static_cast(alignment - 1); + + if (aligned_pitch >= MAX_IMAGE_ROW_SIZE) + CV_Error(cv::Error::StsOutOfRange, + cv::format("%s: src_pitch exceeds maximum allowed size", format_name)); + + RowPitchParams result; + result.src_pitch = validateToInt(aligned_pitch); + result.bytes_per_row = bytes_per_row; + return result; +} + +int calculateRowSize(int width, int nch, const char* format_name) +{ + CV_Assert(width > 0 && nch > 0); + + const size_t row_size = static_cast(width) * static_cast(nch); + if (row_size >= MAX_IMAGE_ROW_SIZE) + CV_Error(cv::Error::StsOutOfRange, + cv::format("%s: row size exceeds maximum allowed size", format_name)); + + return validateToInt(row_size); +} + #define SCALE 14 #define cR (int)(0.299*(1 << SCALE) + 0.5) #define cG (int)(0.587*(1 << SCALE) + 0.5) diff --git a/modules/imgcodecs/src/utils.hpp b/modules/imgcodecs/src/utils.hpp index 8b0ad1a9e9..3ed18eaaba 100644 --- a/modules/imgcodecs/src/utils.hpp +++ b/modules/imgcodecs/src/utils.hpp @@ -135,6 +135,16 @@ uchar* FillGrayRow4( uchar* data, uchar* indices, int len, uchar* palette ); uchar* FillColorRow1( uchar* data, uchar* indices, int len, PaletteEntry* palette ); uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette ); +static const size_t MAX_IMAGE_ROW_SIZE = static_cast(1) << 28; // 256 MB + +struct RowPitchParams { + int src_pitch; + size_t bytes_per_row; +}; + +RowPitchParams calculateRowPitch(int width, int bpp, int alignment, const char* format_name); +int calculateRowSize(int width, int nch, const char* format_name); + CV_INLINE bool isBigEndian( void ) { #ifdef WORDS_BIGENDIAN