Skip to content

Commit

Permalink
Safer JSON cast from floating point to integer across platforms
Browse files Browse the repository at this point in the history
Summary:
facebookincubator#8899

When casting from floating point to integer, first cast losslessly into `double`, then check if it can be cast into `int64_t` using boundaries from `folly::constexpr_clamp_cast`, if it fits then we do another integer to integer cast which is trivial.

Reviewed By: bikramSingh91

Differential Revision: D54313505

fbshipit-source-id: 7ad5cf182fe3ac8b304679b7e95eff21cee51d00
  • Loading branch information
Yuhta authored and facebook-github-bot committed Feb 29, 2024
1 parent 0d49436 commit 93b2544
Showing 1 changed file with 18 additions and 6 deletions.
24 changes: 18 additions & 6 deletions velox/functions/prestosql/types/JsonType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,16 +569,28 @@ simdjson::simdjson_result<T> fromString(const std::string_view& s) {
template <typename To, typename From>
simdjson::error_code convertIfInRange(From x, exec::GenericWriter& writer) {
static_assert(std::is_signed_v<From> && std::is_signed_v<To>);
static_assert(std::is_integral_v<To> || !std::is_integral_v<From>);
if constexpr (!std::is_same_v<To, From>) {
constexpr From kMin = std::numeric_limits<To>::lowest();
constexpr From kMax = std::numeric_limits<To>::max();
if constexpr (std::is_integral_v<To> == std::is_integral_v<From>) {
if constexpr (sizeof(To) < sizeof(From)) {
constexpr From kMin = std::numeric_limits<To>::lowest();
constexpr From kMax = std::numeric_limits<To>::max();
if (!(kMin <= x && x <= kMax)) {
return simdjson::NUMBER_OUT_OF_RANGE;
}
}
writer.castTo<To>() = x;
return simdjson::SUCCESS;
} else {
static_assert(std::is_integral_v<To> && !std::is_integral_v<From>);
// Upper/lower bound values that could be accurately represented in both
// int64_t and double types. Same values are used by
// folly::constexpr_clamp_cast.
constexpr double kMin = -9223372036854774784.0;
constexpr double kMax = 9223372036854774784.0;
if (!(kMin <= x && x <= kMax)) {
return simdjson::NUMBER_OUT_OF_RANGE;
}
return convertIfInRange<To, int64_t>(x, writer);
}
writer.castTo<To>() = x;
return simdjson::SUCCESS;
}

template <TypeKind kind>
Expand Down

0 comments on commit 93b2544

Please sign in to comment.