From 6b954677c0e57b1c1b8201210aa31d956d79c9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 14 Jul 2017 12:00:53 +0200 Subject: [core] fix undefined behavior for division through 0 --- src/mbgl/text/collision_feature.cpp | 2 +- src/mbgl/text/collision_tile.cpp | 25 ++++++++++++++++--------- src/mbgl/util/math.hpp | 13 +++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/mbgl/text/collision_feature.cpp b/src/mbgl/text/collision_feature.cpp index 022ee50644..3eb08da8d1 100644 --- a/src/mbgl/text/collision_feature.cpp +++ b/src/mbgl/text/collision_feature.cpp @@ -135,7 +135,7 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo // This makes our calculation spot-on at scale=2, and on the conservative side for // lower scales const float distanceToInnerEdge = std::max(std::fabs(boxDistanceToAnchor - firstBoxOffset) - step / 2, 0.0f); - float maxScale = labelLength / 2 / distanceToInnerEdge; + float maxScale = util::division(labelLength / 2, distanceToInnerEdge, std::numeric_limits::infinity()); // The box maxScale calculations are designed to be conservative on collisions in the scale range // [1,2]. At scale=1, each box has 50% overlap, and at scale=2, the boxes are lined up edge diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp index b3fbe6f8a3..cc9b602f08 100644 --- a/src/mbgl/text/collision_tile.cpp +++ b/src/mbgl/text/collision_tile.cpp @@ -20,7 +20,11 @@ CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_ rotationMatrix = { { angle_cos, -angle_sin, angle_sin, angle_cos } }; reverseRotationMatrix = { { angle_cos, angle_sin, -angle_sin, angle_cos } }; - perspectiveRatio = 1.0f + 0.5f * ((config.cameraToTileDistance / config.cameraToCenterDistance) - 1.0f); + perspectiveRatio = + 1.0f + + 0.5f * (util::division(config.cameraToTileDistance, config.cameraToCenterDistance, 1.0f) - + 1.0f); + minScale /= perspectiveRatio; maxScale /= perspectiveRatio; @@ -30,22 +34,25 @@ CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_ // purposes, but we still want to use the yStretch approximation // here because we can't adjust the aspect ratio of the collision // boxes at render time. - yStretch = util::max(1.0f, config.cameraToTileDistance / (config.cameraToCenterDistance * std::cos(config.pitch))); + yStretch = util::max( + 1.0f, util::division(config.cameraToTileDistance, + config.cameraToCenterDistance * std::cos(config.pitch), 1.0f)); } - float CollisionTile::findPlacementScale(const Point& anchor, const CollisionBox& box, const float boxMaxScale, const Point& blockingAnchor, const CollisionBox& blocking) { float minPlacementScale = minScale; // Find the lowest scale at which the two boxes can fit side by side without overlapping. // Original algorithm: - float s1 = (blocking.x1 - box.x2) / (anchor.x - blockingAnchor.x); // scale at which new box is to the left of old box - float s2 = (blocking.x2 - box.x1) / (anchor.x - blockingAnchor.x); // scale at which new box is to the right of old box - float s3 = (blocking.y1 - box.y2) * yStretch / (anchor.y - blockingAnchor.y); // scale at which new box is to the top of old box - float s4 = (blocking.y2 - box.y1) * yStretch / (anchor.y - blockingAnchor.y); // scale at which new box is to the bottom of old box - if (std::isnan(s1) || std::isnan(s2)) s1 = s2 = 1; - if (std::isnan(s3) || std::isnan(s4)) s3 = s4 = 1; + const float s1 = util::division(blocking.x1 - box.x2, anchor.x - blockingAnchor.x, + 1.0f); // scale at which new box is to the left of old box + const float s2 = util::division(blocking.x2 - box.x1, anchor.x - blockingAnchor.x, + 1.0f); // scale at which new box is to the right of old box + const float s3 = util::division((blocking.y1 - box.y2) * yStretch, anchor.y - blockingAnchor.y, + 1.0f); // scale at which new box is to the top of old box + const float s4 = util::division((blocking.y2 - box.y1) * yStretch, anchor.y - blockingAnchor.y, + 1.0f); // scale at which new box is to the bottom of old box float collisionFreeScale = util::min(util::max(s1, s2), util::max(s3, s4)); diff --git a/src/mbgl/util/math.hpp b/src/mbgl/util/math.hpp index f969ecaedd..eb3c7d0fde 100644 --- a/src/mbgl/util/math.hpp +++ b/src/mbgl/util/math.hpp @@ -106,5 +106,18 @@ T smoothstep(T edge0, T edge1, T x) { return t * t * (T(3) - T(2) * t); } +template +inline T division(const T dividend, const T divisor, const T nan) { + if (divisor == 0) { + if (dividend == 0) { + return nan; + } else { + return std::copysign(std::numeric_limits::infinity(), dividend); + } + } else { + return dividend / divisor; + } +} + } // namespace util } // namespace mbgl -- cgit v1.2.1