From 65e6890f337736cc501aa61b8c083799350dc5d9 Mon Sep 17 00:00:00 2001 From: Adrian Kretz Date: Wed, 28 Jan 2026 12:23:43 +0100 Subject: [PATCH] Merge pull request #28386 from akretz:fix_issue_28385 Fix integer overflow in medianBlur #28386 The bug in #28385 is that the pointer arithmetic in https://github.com/opencv/opencv/blob/d8bc5b94b851d5b392c61e5b954fba992e18bb73/modules/imgproc/src/median_blur.simd.hpp#L666-L668 overflows if `i*sstep` is larger than `INT_MAX`, because both variables are of type `int`. If one operand is of type `size_t` instead, the other operand gets promoted to `size_t` before multiplication and overflow doesn't happen anymore. The test allocates 2.3GB for the Mat; I hope that's okay. This PR fixes #28385 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- modules/imgproc/src/median_blur.simd.hpp | 22 +++++++++++----------- modules/imgproc/test/test_filter.cpp | 13 +++++++++++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/modules/imgproc/src/median_blur.simd.hpp b/modules/imgproc/src/median_blur.simd.hpp index a3e7a101bb..0b9db8ebb4 100644 --- a/modules/imgproc/src/median_blur.simd.hpp +++ b/modules/imgproc/src/median_blur.simd.hpp @@ -360,7 +360,7 @@ medianBlur_8u_Om( const Mat& _src, Mat& _dst, int m ) uchar* dst = _dst.ptr(); int src_step = (int)_src.step, dst_step = (int)_dst.step; int cn = _src.channels(); - const uchar* src_max = src + size.height*src_step; + const uchar* src_max = src + (size_t)size.height*src_step; CV_Assert(cn > 0 && cn <= 4); #define UPDATE_ACC01( pix, cn, op ) \ @@ -381,8 +381,8 @@ medianBlur_8u_Om( const Mat& _src, Mat& _dst, int m ) if( x % 2 != 0 ) { - src_bottom = src_top += src_step*(size.height-1); - dst_cur += dst_step*(size.height-1); + src_bottom = src_top += (size_t)src_step*(size.height-1); + dst_cur += (size_t)dst_step*(size.height-1); src_step1 = -src_step1; dst_step1 = -dst_step1; } @@ -663,9 +663,9 @@ medianBlur_SortNet( const Mat& _src, Mat& _dst, int m ) size.width *= cn; for( i = 0; i < size.height; i++, dst += dstep ) { - const T* row0 = src + std::max(i - 1, 0)*sstep; - const T* row1 = src + i*sstep; - const T* row2 = src + std::min(i + 1, size.height-1)*sstep; + const T* row0 = src + (size_t)std::max(i - 1, 0)*sstep; + const T* row1 = src + (size_t)i*sstep; + const T* row2 = src + (size_t)std::min(i + 1, size.height-1)*sstep; int limit = cn; for(j = 0;; ) @@ -750,11 +750,11 @@ medianBlur_SortNet( const Mat& _src, Mat& _dst, int m ) for( i = 0; i < size.height; i++, dst += dstep ) { const T* row[5]; - row[0] = src + std::max(i - 2, 0)*sstep; - row[1] = src + std::max(i - 1, 0)*sstep; - row[2] = src + i*sstep; - row[3] = src + std::min(i + 1, size.height-1)*sstep; - row[4] = src + std::min(i + 2, size.height-1)*sstep; + row[0] = src + (size_t)std::max(i - 2, 0)*sstep; + row[1] = src + (size_t)std::max(i - 1, 0)*sstep; + row[2] = src + (size_t)i*sstep; + row[3] = src + (size_t)std::min(i + 1, size.height-1)*sstep; + row[4] = src + (size_t)std::min(i + 2, size.height-1)*sstep; int limit = cn*2; for(j = 0;; ) diff --git a/modules/imgproc/test/test_filter.cpp b/modules/imgproc/test/test_filter.cpp index 2920b71e8a..d8e831162e 100644 --- a/modules/imgproc/test/test_filter.cpp +++ b/modules/imgproc/test/test_filter.cpp @@ -2264,6 +2264,19 @@ TEST(Imgproc_MedianBlur, hires_regression_13409) ASSERT_EQ(0.0, cvtest::norm(dst_hires(Rect(516, 516, 1016, 1016)), dst_ref(Rect(4, 4, 1016, 1016)), NORM_INF)); } +TEST(Imgproc_MedianBlur, regression_28385) +{ + applyTestTag(CV_TEST_TAG_MEMORY_6GB); + + Mat out; + // create a matrix larger than 2^31 to check for signed 32 bit integer overflow + Mat img(50000, 50000, CV_8U); + Mat sub = img(Rect(0, 0, 100, 50000)); + // this crashes in case of overflow because of out-of-bounds memory access + medianBlur(sub, out, 3); + ASSERT_EQ(out.size(), Size(100, 50000)); +} + TEST(Imgproc_Sobel, s16_regression_13506) { Mat src = (Mat_(8, 16) << 127, 138, 130, 102, 118, 97, 76, 84, 124, 90, 146, 63, 130, 87, 212, 85,