Skip to content

trap out-of-range exponents in the Dfp string constructor - #341

Merged
aherbert merged 1 commit into
apache:masterfrom
insaf021:dfp-string-exponent-trap
Oct 28, 2026
Merged

aherbert merged 1 commit into
apache:masterfrom
insaf021:dfp-string-exponent-trap

Conversation

@insaf021

Copy link
Copy Markdown
Contributor

Observed on master with a 20 digit DfpField:

field.newDfp("1e999999")               -> 1.0000000000000000000e999999  (finite, FLAG_OVERFLOW set)
field.newDfp("1e999999").multiply(one) -> Infinity
field.newDfp("1e2147483648")           -> finite tiny value, lessThan(one) is true
field.newDfp("1e2147483648").toString() never returns:

    "main" prio=5 RUNNABLE
        at org.apache.commons.math4.legacy.core.dfp.Dfp.dfp2sci(Dfp.java:2143)
        at org.apache.commons.math4.legacy.core.dfp.Dfp.toString(Dfp.java:2072)

The string constructor discards the flag returned by round(). Every arithmetic operation passes that flag through dotrap, which turns an exponent above MAX_EXP into infinity and one below the gradual underflow range into zero, so a parsed value can break an invariant the rest of the class relies on and disagree with any operation applied to it. The exponent digits are also accumulated in an int with no bound, so "1e2147483648" wraps negative; dfp2sci then computes e == Integer.MIN_VALUE, ae = -e stays negative and while (p > ae) spins forever once p reaches 0.

The fix stays in the constructor: stop accumulating exponent digits once the value is past anything representable, store a zero mantissa with a zero exponent as add does, and hand the round() flag to dotrap, copying the trapped result back the way the double constructor already does. Values inside the representable range, including gradual underflow, are unchanged.

Two existing tests ("Next After #14" in DfpTest and DfpDecTest) parsed 9.99...e131078, which is beyond the largest finite value 9.99...e131071 and only came out finite because of this bug; the literal is corrected to e131071 and the test still exercises the overflow on nextAfter. The new DfpTest case fails on master at its first assertion. mvn -pl commons-math-legacy-core install passes on JDK 21 (checkstyle, SpotBugs, PMD, 291 tests), and the Dfp based tests in commons-math-legacy pass against the patched module.

Dfp(DfpField, String) discarded the flag returned by round(), so an
exponent above MAX_EXP or below the gradual underflow range produced a
finite value that every arithmetic operation would have trapped to
infinity or zero. The exponent digits were also accumulated in an int
without a bound, so "1e2147483648" wrapped negative and toString() on
the result looped forever in dfp2sci.

Stop accumulating exponent digits once they are past any representable
magnitude, store a zero mantissa with a zero exponent, and route the
round() flag through dotrap as the arithmetic operations do.

The "Next After apache#14" literal 9.99e131078 in DfpTest and DfpDecTest is
beyond the largest finite value and only parsed as finite because of
this bug; it is corrected to e131071.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 87.22%. Comparing base (f554608) to head (5567ce9).
⚠️ Report is 393 commits behind head on master.

Files with missing lines Patch % Lines
.../org/apache/commons/math4/legacy/core/dfp/Dfp.java 90.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master     #341      +/-   ##
============================================
+ Coverage     86.54%   87.22%   +0.68%     
+ Complexity     9787       91    -9696     
============================================
  Files           532      499      -33     
  Lines         35516    33527    -1989     
  Branches       6194     5850     -344     
============================================
- Hits          30738    29245    -1493     
+ Misses         3518     3163     -355     
+ Partials       1260     1119     -141     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@aherbert
aherbert merged commit 30356b2 into apache:master Oct 28, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants