Skip to content

GH-49817: [C++] Reject decimal strings that exceed the target precision#49832

Open
SAY-5 wants to merge 1 commit intoapache:mainfrom
SAY-5:fix/decimal-fromstring-precision-overflow-49817
Open

GH-49817: [C++] Reject decimal strings that exceed the target precision#49832
SAY-5 wants to merge 1 commit intoapache:mainfrom
SAY-5:fix/decimal-fromstring-precision-overflow-49817

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 21, 2026

Rationale for this change

arrow::Decimal128::FromString and Decimal256::FromString (and the SimpleDecimalFromString path used by Decimal32/Decimal64) silently truncate when the input string's precision exceeds the target decimal's maximum. The digit string is fed into ShiftAndAdd, which multiplies and adds into a fixed-size uint64_t array sized to the target's bit width; high bits that don't fit are silently dropped. The parsed-precision out-parameter does reflect the real precision, but callers who don't validate it against kMaxPrecision get a corrupted (value mod 2^kBitWidth) with Status::OK.

What changes are included in this PR?

Check parsed_precision against Decimal::kMaxPrecision before ShiftAndAdd in both DecimalFromString (128 / 256) and SimpleDecimalFromString (32 / 64), returning Status::Invalid with a descriptive message when the input exceeds the target.

Are these changes tested?

Covered by the existing FromString test matrix for the valid-range cases. Over-precision inputs previously returned OK; the new behaviour is a Status::Invalid so regression tests that exercise precision > kMaxPrecision paths should be added — happy to follow up with those in a second commit or separate PR.

Are there any user-facing changes?

Yes: Decimal*::FromString now rejects strings with more than kMaxPrecision significant digits. Callers that relied on the silently-wrapped value (unusual) will see the new error and should clamp / validate precision upstream.

Closes #49817.

Signed-off-by: SAY-5 SAY-5@users.noreply.github.com

…recision

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 apacheGH-49817.

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

⚠️ GitHub issue #49817 has been automatically assigned in GitHub to PR creator.

Copy link
Copy Markdown
Member

@raulcd raulcd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reporting issue contains some tests and reproducers. Can we add tests?

@SAY-5 as per our guidelines, can you share whether the fix was AI generated and summarise what was AI-generated?
https://arrow.apache.org/docs/dev/developers/overview.html#ai-generated-code

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

arrow::Decimal128::FromString silently truncates when the input string has more than 38 significant digits

2 participants