diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_internal.cc b/cpp/src/arrow/compute/kernels/scalar_cast_internal.cc index 0484e0b259c5..695ea8e1fe9c 100644 --- a/cpp/src/arrow/compute/kernels/scalar_cast_internal.cc +++ b/cpp/src/arrow/compute/kernels/scalar_cast_internal.cc @@ -113,6 +113,7 @@ struct CastPrimitive> { // Cast half float to int template struct CastPrimitive> { + ARROW_DISABLE_UBSAN("float-cast-overflow") static void Exec(const ArraySpan& arr, ArraySpan* out) { using OutT = typename OutType::c_type; const uint16_t* in_values = arr.GetValues(1); diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc b/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc index ba2a8c4b5638..9720ca1a6008 100644 --- a/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc +++ b/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc @@ -17,6 +17,8 @@ // Implementation of casting to integer, floating point, or decimal types +#include + #include "arrow/array/builder_primitive.h" #include "arrow/compute/kernels/common_internal.h" #include "arrow/compute/kernels/scalar_cast_internal.h" @@ -87,12 +89,55 @@ struct WasTruncated { } }; -// InType is a floating point type we are planning to cast to integer template +struct WasOutOfRange { + // Both bounds are zero or a power of two, so they are exact in InT + static constexpr auto kMin = static_cast(std::numeric_limits::min()); + static constexpr auto kMaxPlusOne = + static_cast(std::numeric_limits::max() / 2 + 1) * 2; + + static bool Check(OutT, InT in_val) { + return !(std::trunc(in_val) >= kMin) | !(in_val < kMaxPlusOne); + } + + static bool CheckMaybeNull(OutT out_val, InT in_val, bool is_valid) { + return is_valid && Check(out_val, in_val); + } +}; + +template +struct WasOutOfRange { + using OutT = typename OutType::c_type; + static bool Check(OutT out_val, uint16_t in_val) { + return WasOutOfRange::Check(out_val, + Float16::FromBits(in_val).ToFloat()); + } + + static bool CheckMaybeNull(OutT out_val, uint16_t in_val, bool is_valid) { + return is_valid && Check(out_val, in_val); + } +}; + +// InType is a floating point type we are planning to cast to integer +template