Bypass boost::numeric_cast checks for coordinate values that have already been validated (#4059)

(i.e. stuff that's stored in our datafiles).  Keep those checks for user-supplied values
(i.e. coordinates coming from files during preprocessing, or coordinates supplied by users
 during requests)
This commit is contained in:
Daniel Patterson 2017-05-19 10:52:44 -07:00 committed by GitHub
parent 4964d0dcbd
commit 570d81c6dd
4 changed files with 71 additions and 20 deletions

View File

@ -111,15 +111,15 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::_1,
qi::_2)];
location_rule =
(double_ > qi::lit(',') >
double_)[qi::_val = ph::bind(
[](double lon, double lat) {
return util::Coordinate(util::toFixed(util::FloatLongitude{lon}),
util::toFixed(util::FloatLatitude{lat}));
},
qi::_1,
qi::_2)];
location_rule = (double_ > qi::lit(',') >
double_)[qi::_val = ph::bind(
[](double lon, double lat) {
return util::Coordinate(
util::toFixed(util::UnsafeFloatLongitude{lon}),
util::toFixed(util::UnsafeFloatLatitude{lat}));
},
qi::_1,
qi::_2)];
polyline_rule = qi::as_string[qi::lit("polyline(") > +polyline_chars > ')']
[qi::_val = ph::bind(

View File

@ -53,16 +53,29 @@ struct latitude
struct longitude
{
};
struct unsafelatitude
{
};
struct unsafelongitude
{
};
}
// Internal lon/lat types - assumed to be range safe
using FixedLatitude = Alias<std::int32_t, tag::latitude>;
using FixedLongitude = Alias<std::int32_t, tag::longitude>;
using FloatLatitude = Alias<double, tag::latitude>;
using FloatLongitude = Alias<double, tag::longitude>;
// Types used for external input data - conversion functions perform extra
// range checks on these (toFixed/toFloat, etc)
using UnsafeFloatLatitude = Alias<double, tag::unsafelatitude>;
using UnsafeFloatLongitude = Alias<double, tag::unsafelongitude>;
static_assert(std::is_pod<FixedLatitude>(), "FixedLatitude is not a valid alias");
static_assert(std::is_pod<FixedLongitude>(), "FixedLongitude is not a valid alias");
static_assert(std::is_pod<FloatLatitude>(), "FloatLatitude is not a valid alias");
static_assert(std::is_pod<FloatLongitude>(), "FloatLongitude is not a valid alias");
static_assert(std::is_pod<UnsafeFloatLatitude>(), "UnsafeFloatLatitude is not a valid alias");
static_assert(std::is_pod<UnsafeFloatLongitude>(), "UnsafeFloatLongitude is not a valid alias");
/**
* Converts a typed latitude from floating to fixed representation.
@ -72,6 +85,21 @@ static_assert(std::is_pod<FloatLongitude>(), "FloatLongitude is not a valid alia
* \see Coordinate, toFloating
*/
inline FixedLatitude toFixed(const FloatLatitude floating)
{
const auto latitude = static_cast<double>(floating);
const auto fixed = static_cast<std::int32_t>(std::round(latitude * COORDINATE_PRECISION));
return FixedLatitude{fixed};
}
/**
* Converts a typed latitude from floating to fixed representation. Also performs an overflow check
* to ensure that the value fits inside the fixed representation.
*
* \param floating typed latitude in floating representation.
* \return typed latitude in fixed representation
* \see Coordinate, toFloating
*/
inline FixedLatitude toFixed(const UnsafeFloatLatitude floating)
{
const auto latitude = static_cast<double>(floating);
const auto fixed =
@ -87,6 +115,21 @@ inline FixedLatitude toFixed(const FloatLatitude floating)
* \see Coordinate, toFloating
*/
inline FixedLongitude toFixed(const FloatLongitude floating)
{
const auto longitude = static_cast<double>(floating);
const auto fixed = static_cast<std::int32_t>(std::round(longitude * COORDINATE_PRECISION));
return FixedLongitude{fixed};
}
/**
* Converts a typed longitude from floating to fixed representation. Also performns an overflow
* check to ensure that the value fits inside the fixed representation.
*
* \param floating typed longitude in floating representation.
* \return typed latitude in fixed representation
* \see Coordinate, toFloating
*/
inline FixedLongitude toFixed(const UnsafeFloatLongitude floating)
{
const auto longitude = static_cast<double>(floating);
const auto fixed =
@ -104,7 +147,7 @@ inline FixedLongitude toFixed(const FloatLongitude floating)
inline FloatLatitude toFloating(const FixedLatitude fixed)
{
const auto latitude = static_cast<std::int32_t>(fixed);
const auto floating = boost::numeric_cast<double>(latitude / COORDINATE_PRECISION);
const auto floating = static_cast<double>(latitude) / COORDINATE_PRECISION;
return FloatLatitude{floating};
}
@ -118,7 +161,7 @@ inline FloatLatitude toFloating(const FixedLatitude fixed)
inline FloatLongitude toFloating(const FixedLongitude fixed)
{
const auto longitude = static_cast<std::int32_t>(fixed);
const auto floating = boost::numeric_cast<double>(longitude / COORDINATE_PRECISION);
const auto floating = static_cast<double>(longitude) / COORDINATE_PRECISION;
return FloatLongitude{floating};
}
@ -152,6 +195,11 @@ struct Coordinate
{
}
Coordinate(const UnsafeFloatLongitude lon_, const UnsafeFloatLatitude lat_)
: Coordinate(toFixed(lon_), toFixed(lat_))
{
}
Coordinate(const FixedLongitude lon_, const FixedLatitude lat_) : lon(lon_), lat(lat_) {}
template <class T> Coordinate(const T &coordinate) : lon(coordinate.lon), lat(coordinate.lat)

View File

@ -54,8 +54,8 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
const ExtractionNode &result_node)
{
external_memory.all_nodes_list.push_back(
{util::toFixed(util::FloatLongitude{input_node.location().lon()}),
util::toFixed(util::FloatLatitude{input_node.location().lat()}),
{util::toFixed(util::UnsafeFloatLongitude{input_node.location().lon()}),
util::toFixed(util::UnsafeFloatLatitude{input_node.location().lat()}),
OSMNodeID{static_cast<std::uint64_t>(input_node.id())},
result_node.barrier,
result_node.traffic_lights});

View File

@ -125,14 +125,17 @@ BOOST_AUTO_TEST_CASE(compute_angle)
end = Coordinate{FloatLongitude{1 + std::numeric_limits<double>::epsilon()}, FloatLatitude{0}};
angle = coordinate_calculation::computeAngle(first, middle, end);
BOOST_CHECK_EQUAL(angle, 180);
}
// Invalid values
BOOST_CHECK_THROW(
coordinate_calculation::computeAngle(
Coordinate(FloatLongitude{0}, FloatLatitude{0}),
Coordinate(FloatLongitude{1}, FloatLatitude{0}),
Coordinate(FloatLongitude{std::numeric_limits<double>::max()}, FloatLatitude{0})),
boost::numeric::positive_overflow);
BOOST_AUTO_TEST_CASE(invalid_values)
{
// Invalid values for unsafe types
BOOST_CHECK_THROW(coordinate_calculation::computeAngle(
Coordinate(UnsafeFloatLongitude{0}, UnsafeFloatLatitude{0}),
Coordinate(UnsafeFloatLongitude{1}, UnsafeFloatLatitude{0}),
Coordinate(UnsafeFloatLongitude{std::numeric_limits<double>::max()},
UnsafeFloatLatitude{0})),
boost::numeric::positive_overflow);
}
// Regression test for bug captured in #1347