From d490bd6f8d02a4e5d44efb41a816bbe005b42b41 Mon Sep 17 00:00:00 2001 From: Advit Arora Date: Thu, 8 Oct 2026 17:19:34 -0700 Subject: [PATCH 1/4] GH-46557: [C++][R] Check overflow in float to int casts that allow truncation --- .../compute/kernels/scalar_cast_numeric.cc | 85 ++++++++++++++----- .../arrow/compute/kernels/scalar_cast_test.cc | 36 ++++++++ r/R/expression.R | 2 +- 3 files changed, 99 insertions(+), 24 deletions(-) diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc b/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc index ba2a8c4b5638..d63befe01d14 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,47 @@ 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