From 7b11cd3a11c939c957eeff71af7feddaa86e7f82 Mon Sep 17 00:00:00 2001 From: "Daniel J. Hofmann" Date: Thu, 22 Dec 2016 12:56:58 +0100 Subject: [PATCH] Makes Types in Squared Dist Calculation Explicit, see #3483. --- src/util/coordinate_calculation.cpp | 11 ++++++++--- unit_tests/util/coordinate_calculation.cpp | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp index 3ba1f22a3..cfc2846ce 100644 --- a/src/util/coordinate_calculation.cpp +++ b/src/util/coordinate_calculation.cpp @@ -21,10 +21,15 @@ namespace coordinate_calculation // Does not project the coordinates! std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rhs) { - const std::uint64_t dx = static_cast(lhs.lon - rhs.lon); - const std::uint64_t dy = static_cast(lhs.lat - rhs.lat); + std::int64_t d_lon = static_cast(lhs.lon - rhs.lon); + std::int64_t d_lat = static_cast(lhs.lat - rhs.lat); - return dx * dx + dy * dy; + std::int64_t sq_lon = d_lon * d_lon; + std::int64_t sq_lat = d_lat * d_lat; + + std::uint64_t result = static_cast(sq_lon + sq_lat); + + return result; } double haversineDistance(const Coordinate coordinate_1, const Coordinate coordinate_2) diff --git a/unit_tests/util/coordinate_calculation.cpp b/unit_tests/util/coordinate_calculation.cpp index 3bea3eb86..83fbb9e2c 100644 --- a/unit_tests/util/coordinate_calculation.cpp +++ b/unit_tests/util/coordinate_calculation.cpp @@ -311,4 +311,18 @@ BOOST_AUTO_TEST_CASE(circleCenter) BOOST_CHECK(!result); } +// For overflow issue #3483, introduced in 68ee4eab61548. Run with -fsanitize=integer. +BOOST_AUTO_TEST_CASE(squaredEuclideanDistance) +{ + // Overflow happens when left hand side values are smaller than right hand side values, + // then `lhs - rhs` will be negative but stored in a uint64_t (wraps around). + + Coordinate lhs(FloatLongitude{-180}, FloatLatitude{-90}); + Coordinate rhs(FloatLongitude{180}, FloatLatitude{90}); + + const auto result = coordinate_calculation::squaredEuclideanDistance(lhs, rhs); + + BOOST_CHECK_EQUAL(result, 162000000000000000ull); +} + BOOST_AUTO_TEST_SUITE_END()