From 838d46ef91f2bef6cb7b080ba5620052bb9ffbea Mon Sep 17 00:00:00 2001 From: SAY-5 Date: Tue, 21 Apr 2026 16:07:31 -0700 Subject: [PATCH] GH-49817: [C++] Reject decimal strings that exceed the target precision DecimalFromString and SimpleDecimalFromString fed the digit string into ShiftAndAdd, which multiplies-and-adds into a fixed-size uint64_t array sized to the target decimal's bit width. ShiftAndAdd carries high bits only through out_size limbs and silently drops the remaining carry. The parser then returned Status::OK with a corrupted (mod 2^kBitWidth) value; callers that ignored the parsed-precision out-parameter had no way to notice. Check parsed_precision against kMaxPrecision before the ShiftAndAdd call and return Status::Invalid with a descriptive message when the input exceeds the decimal's capacity. Closes GH-49817. Signed-off-by: SAY-5 --- cpp/src/arrow/util/decimal.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cpp/src/arrow/util/decimal.cc b/cpp/src/arrow/util/decimal.cc index d80164f45c0e..d2f8b9b08d20 100644 --- a/cpp/src/arrow/util/decimal.cc +++ b/cpp/src/arrow/util/decimal.cc @@ -879,6 +879,16 @@ Status DecimalFromString(const char* type_name, std::string_view s, Decimal* out } int32_t parsed_precision = static_cast(significant_digits); + // Reject precisions that exceed the target decimal's bit width. ShiftAndAdd + // only carries through the limbs of the output array and silently drops + // the overflow; callers that ignore the out-parameter would get a corrupted + // (mod 2^kBitWidth) value with Status::OK. See GH-49817. + if (parsed_precision > Decimal::kMaxPrecision) { + return Status::Invalid("The string '", s, "' has precision ", parsed_precision, + " which exceeds the ", type_name, " maximum of ", + Decimal::kMaxPrecision); + } + int32_t parsed_scale = 0; if (dec.has_exponent) { auto adjusted_exponent = dec.exponent; @@ -943,6 +953,14 @@ Status SimpleDecimalFromString(const char* type_name, std::string_view s, } int32_t parsed_precision = static_cast(significant_digits); + // Reject precisions that exceed the target decimal's max; ShiftAndAdd into + // a single uint64_t would silently wrap on overflow (GH-49817). + if (parsed_precision > DecimalClass::kMaxPrecision) { + return Status::Invalid("The string '", s, "' has precision ", parsed_precision, + " which exceeds the ", type_name, " maximum of ", + DecimalClass::kMaxPrecision); + } + int32_t parsed_scale = 0; if (dec.has_exponent) { auto adjusted_exponent = dec.exponent;