From 88f2f459db381e865ef2df78aa5123adcf32110e Mon Sep 17 00:00:00 2001 From: perry_lin <2628192835@qq.com> Date: Sun, 30 Aug 2026 17:04:25 +0800 Subject: [PATCH] Merge pull request #29069 from perrylin4:fix/11988-rect-unsigned-intersection core: fix unsigned Rect intersection for disjoint rectangles (#11988) - #29069 Fixes #11988 ## Problem `Rect_<_Tp>::operator&` / `operator&=` returned a non-empty rectangle when two **unsigned** rectangles do not overlap. ### Example: ```cpp cv::Rect_ r1(0, 0, 1, 1); cv::Rect_ r2(2, 2, 1, 1); auto inter = r1 & r2; // was [1 x 1 from (2, 2)], expected empty ``` Root cause: the previous implementation subtracted edge coordinates before checking overlap. For `unsigned _Tp`, expressions like `width - (x_max - x_min)` can underflow when rectangles are disjoint. ### Solution Add a check for underflow ### Tests Added regression test `Core_Rect.test_unsigned_overflow in modules/core/test/test_misc.cpp`. --- modules/core/include/opencv2/core/types.hpp | 9 +++++++++ modules/core/test/test_misc.cpp | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/modules/core/include/opencv2/core/types.hpp b/modules/core/include/opencv2/core/types.hpp index 1f54d9563d..1c962dcae4 100644 --- a/modules/core/include/opencv2/core/types.hpp +++ b/modules/core/include/opencv2/core/types.hpp @@ -2012,6 +2012,15 @@ Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b ) a = Rect_<_Tp>(); return a; } + + // If the delta between x/y coordinates exceeds the corresponding width/height, + // the rectangles cannot overlap and `width - delta` would underflow for unsigned types. + if (Rx_min.width < (Rx_max.x - Rx_min.x) || + Ry_min.height < (Ry_max.y - Ry_min.y)) { + a = Rect_<_Tp>(); + return a; + } + // We now know that either Rx_min.x >= 0, or // Rx_min.x < 0 && Rx_min.x + Rx_min.width >= Rx_max.x and therefore // Rx_min.width >= (Rx_max.x - Rx_min.x) which means (Rx_max.x - Rx_min.x) diff --git a/modules/core/test/test_misc.cpp b/modules/core/test/test_misc.cpp index 94b4d83781..1682ff27ea 100644 --- a/modules/core/test/test_misc.cpp +++ b/modules/core/test/test_misc.cpp @@ -996,6 +996,17 @@ REGISTER_TYPED_TEST_CASE_P(Rect_Test, Overflows, OnTheEdge); typedef ::testing::Types RectTypes; INSTANTIATE_TYPED_TEST_CASE_P(Negative_Test, Rect_Test, RectTypes); +TEST(Core_Rect, test_unsigned_overflow_11988) +{ + typedef Rect_ R; + R r1(0, 0, 1u, 1u); + R r2(2u, 2u, 1u, 1u); + auto inter = r1 & r2; + EXPECT_EQ(R(), inter); + EXPECT_EQ(0u, inter.area()); + EXPECT_TRUE(inter.empty()); +} + // Expected that SkipTestException thrown in the constructor should skip test but not fail struct TestFixtureSkip: public ::testing::Test { TestFixtureSkip(bool throwEx = true) {