1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 23:33:05 +04:00

Merge pull request #28959 from Kumataro:fix28930

core: fix signed overflow UB in Point/Point3i::dot()
This commit is contained in:
Alexander Smorkalov
2026-05-07 21:25:07 +03:00
committed by GitHub
2 changed files with 236 additions and 0 deletions
@@ -1245,6 +1245,26 @@ _Tp Point_<_Tp>::dot(const Point_& pt) const
return saturate_cast<_Tp>(x*pt.x + y*pt.y);
}
template<> inline
int Point_<int>::dot(const Point_<int>& pt) const
{
const int64_t xx = (int64_t)x * pt.x;
const int64_t yy = (int64_t)y * pt.y;
// detect int64 overflow before adding
if (yy > 0 && xx > INT64_MAX - yy)
{
return INT32_MAX;
}
if (yy < 0 && xx < INT64_MIN - yy)
{
return INT32_MIN;
}
const int64_t v = xx + yy;
return cv::saturate_cast<int>(v);
}
template<typename _Tp> inline
double Point_<_Tp>::ddot(const Point_& pt) const
{
@@ -1490,6 +1510,50 @@ _Tp Point3_<_Tp>::dot(const Point3_& pt) const
return saturate_cast<_Tp>(x*pt.x + y*pt.y + z*pt.z);
}
template<> inline
int Point3_<int>::dot(const Point3_<int>& pt) const
{
const int64_t xx = (int64_t)x * pt.x;
const int64_t yy = (int64_t)y * pt.y;
const int64_t zz = (int64_t)z * pt.z;
// Sort the three products so that lo <= mid <= hi.
// We add in the order (lo + hi) first, then add mid.
// This minimizes the absolute value of the intermediate sum,
// reducing the chance of int64 overflow during addition.
int64_t lo = xx, mid = yy, hi = zz;
if (lo > mid) std::swap(lo, mid);
if (mid > hi) std::swap(mid, hi);
if (lo > mid) std::swap(lo, mid);
// Step 1: lo + hi
// If lo + hi overflows int64, the final result must saturate to INT32_MAX/INT32_MIN.
// The middle value (mid) cannot bring the result back into the int32 range,
// so we can return immediately without considering mid.
if (hi > 0 && lo > INT64_MAX - hi)
{
return INT32_MAX;
}
if (hi < 0 && lo < INT64_MIN - hi)
{
return INT32_MIN;
}
int64_t sum = lo + hi;
// Step 2: sum + mid
if (mid > 0 && sum > INT64_MAX - mid)
{
return INT32_MAX;
}
if (mid < 0 && sum < INT64_MIN - mid)
{
return INT32_MIN;
}
sum += mid;
return cv::saturate_cast<int>(sum);
}
template<typename _Tp> inline
double Point3_<_Tp>::ddot(const Point3_& pt) const
{
+172
View File
@@ -4229,5 +4229,177 @@ TEST(Core_FastMath, InlineIsInf)
EXPECT_EQ( cvIsInf(suf.f), 0);
}
////////////////////////////////////////////////////////////////////////////
// See https://github.com/opencv/opencv/issues/28930
typedef testing::TestWithParam<std::tuple<int,int,int,int, int>> Core_Point_DotProduct_regression28930;
TEST_P(Core_Point_DotProduct_regression28930, basic)
{
const int x1 = std::get<0>(GetParam());
const int y1 = std::get<1>(GetParam());
const int x2 = std::get<2>(GetParam());
const int y2 = std::get<3>(GetParam());
const int expect = std::get<4>(GetParam());
cv::Point pt1(x1, y1);
cv::Point pt2(x2, y2);
EXPECT_EQ(pt1.dot(pt2), expect) << "Failed for: (" << x1 << "," << y1 << ") dot (" << x2 << "," << y2 << ")";
}
INSTANTIATE_TEST_CASE_P(/* */, Core_Point_DotProduct_regression28930,
testing::Values(
// 1. INT_MIN*INT_MIN + INT_MIN*INT_MIN = 2^62 + 2^62 => Saturates to MAX
std::make_tuple( INT_MIN, INT_MIN,
INT_MIN, INT_MIN,
INT_MAX),
// 2. INT_MIN*INT_MAX + INT_MAX*INT_MAX = 4611686014132420609 + -4611686016279904256 = -2147483647
std::make_tuple( INT_MAX, INT_MIN,
INT_MAX, INT_MAX,
-2147483647),
// 3. INT_MAX*INT_MAX + INT_MAX*INT_MIN = 4611686014132420609 + -4611686016279904256 = -2147483647
std::make_tuple( INT_MAX, INT_MAX,
INT_MAX, INT_MIN,
-2147483647),
// 4. 46340^2 = 2147395600 (Under INT_MAX)
std::make_tuple( 46340, 0,
46340, 0,
2147395600),
// 5. 46341^2 = 2147488281 (Over INT_MAX) => Saturates to MAX
std::make_tuple( 46341, 0,
46341, 0,
INT_MAX),
// 6. -46340 * 46340 = -2147395600 (Over INT_MIN)
std::make_tuple( -46340, 0,
46340, 0,
-2147395600),
// 7. -46341 * 46341 = -2147488281 (Under INT_MIN) => Saturates to MIN
std::make_tuple( -46341, 0,
46341, 0,
INT_MIN),
// 8. Zero
std::make_tuple( 0, 0,
0, 0,
0),
// 9. Simple max
std::make_tuple( INT_MAX, 0,
1, 0,
INT_MAX)
));
typedef testing::TestWithParam<std::tuple<int,int,int,int,int,int, int>> Core_Point3i_DotProduct_regression28930;
TEST_P(Core_Point3i_DotProduct_regression28930, basic)
{
const int x1 = std::get<0>(GetParam());
const int y1 = std::get<1>(GetParam());
const int z1 = std::get<2>(GetParam());
const int x2 = std::get<3>(GetParam());
const int y2 = std::get<4>(GetParam());
const int z2 = std::get<5>(GetParam());
const int expect = std::get<6>(GetParam());
cv::Point3i pt1(x1, y1, z1);
cv::Point3i pt2(x2, y2, z2);
EXPECT_EQ(pt1.dot(pt2), expect) << "Failed for: (" << x1 << "," << y1 << "," << z1 << ") dot (" << x2 << "," << y2 << "," << z2 << ")";
}
INSTANTIATE_TEST_CASE_P(/* */, Core_Point3i_DotProduct_regression28930,
testing::Values(
// 1. INT_MIN*INT_MIN + INT_MIN*INT_MIN = 2^62 + 2^62 => Saturates to MAX
std::make_tuple( INT_MIN, INT_MIN, 0,
INT_MIN, INT_MIN, 0,
INT_MAX),
// 2. INT_MIN*INT_MAX + INT_MAX*INT_MAX = 4611686014132420609 + -4611686016279904256 = -2147483647
std::make_tuple( INT_MAX, INT_MIN, 0,
INT_MAX, INT_MAX, 0,
-2147483647),
// 3. INT_MAX*INT_MAX + INT_MAX*INT_MIN = 4611686014132420609 + -4611686016279904256 = -2147483647
std::make_tuple( INT_MAX, INT_MAX, 0,
INT_MAX, INT_MIN, 0,
-2147483647),
// 4. 46340^2 = 2147395600 (Under INT_MAX)
std::make_tuple( 46340, 0, 0,
46340, 0, 0,
2147395600),
// 5. 46341^2 = 2147488281 (Over INT_MAX) => Saturates to MAX
std::make_tuple( 46341, 0, 0,
46341, 0, 0,
INT_MAX),
// 6. -46340 * 46340 = -2147395600 (Over INT_MIN)
std::make_tuple( -46340, 0, 0,
46340, 0, 0,
-2147395600),
// 7. -46341 * 46341 = -2147488281 (Under INT_MIN) => Saturates to MIN
std::make_tuple( -46341, 0, 0,
46341, 0, 0,
INT_MIN),
// 8. Zero
std::make_tuple( 0, 0, 0,
0, 0, 0,
0),
// 9. Simple max
std::make_tuple( INT_MAX, 0, 0,
1, 0, 0,
INT_MAX),
// 10. All positive, no overflow
std::make_tuple( 1, 2, 3,
4, 5, 6,
(1*4 + 2*5 + 3*6)),
// 11. All negative, no overflow
std::make_tuple( -1, -2, -3,
-4, -5, -6,
(-1*-4 + -2*-5 + -3*-6)),
// 12. Three large positive products => saturate to MAX
std::make_tuple( INT_MAX, INT_MAX, INT_MAX,
INT_MAX, INT_MAX, INT_MAX,
INT_MAX),
// 13. Three large positive products from INT_MIN*INT_MIN => saturate to MAX
std::make_tuple( INT_MIN, INT_MIN, INT_MIN,
INT_MIN, INT_MIN, INT_MIN,
INT_MAX),
// 14. Three large negative products => saturate to MIN
std::make_tuple( INT_MIN, INT_MIN, INT_MIN,
INT_MAX, INT_MAX, INT_MAX,
INT_MIN),
// 15. Mixed signs: + + -
std::make_tuple( INT_MAX, INT_MAX, INT_MIN,
INT_MAX, INT_MAX, INT_MAX,
INT_MAX),
// 16. Mixed signs: + - +
std::make_tuple( INT_MAX, INT_MIN, INT_MAX,
INT_MAX, INT_MAX, INT_MAX,
INT_MAX),
// 17. Mixed signs: - + -
std::make_tuple( INT_MIN, INT_MAX, INT_MIN,
INT_MAX, INT_MAX, INT_MAX,
INT_MIN)
));
}} // namespace
/* End of file. */