pjfanning opened a new pull request, #98:
URL: https://github.com/apache/poi-xmlbeans/pull/98

   Follow-up to #97. That PR hardened the paths that *consume* an oversized 
decimal; this one stops one being created from a document in the first place.
   
   ### The gap
   
   `maxNumberOfCharsForNumbers` is documented as bounding the size of numbers 
read out of a document, but it only checked the length of the lexical value. An 
exponent is a handful of characters denoting arbitrarily many digits:
   
   ```
   parse <xml-fragment>1E+2000000000</xml-fragment> as XmlDecimal, default 
options
     -> stored, scale=-2000000000 precision=1
   ```
   
   13 characters, under any limit, producing a `BigDecimal` that is trivial to 
hold and catastrophic to expand. No option is needed to get there: 
`Factory.parse` doesn't validate on set, so `validateLexical` — the check that 
rejects an exponent — never runs. `setLoadAllowDecimalExponent(true)` reaches 
it by the documented route.
   
   ### Why the check is safe
   
   Exponent notation isn't part of the `xsd:decimal` lexical space at all; it 
belongs to `float`/`double`. XSD leaves the value space unbounded and only 
requires that a minimally conforming processor support at least 18 digits (Part 
2 §3.2.3), so an implementation limit well above that is conformant either way.
   
   The consequence that matters here: for conformant input the digit count is 
bounded by the length of the lexical value, so a bound on digits can never 
reject something the existing length check accepts. It fires only for exponent 
forms that were never valid `xsd:decimal` — which is why 
`testParseAsBigDecimalAcceptsPlainValues` can assert the plain forms are 
untouched.
   
   ### The change
   
   Applied in `MathUtil.parseAsBigDecimal`, the single point that both 
`JavaDecimalHolder.set_text` and `JavaDecimalHolderEx.set_text` go through, 
along with `validateLexical`'s exponent branch and `Validator`. The bound is 
the length of the value written out without an exponent, which is the form 
`xsd:decimal` allows and therefore the form the limit is meant to bound:
   
   ```java
   return scale <= 0
       ? (long) precision - scale                        // integer digits
       : Math.max(precision, (long) scale + 1) + 1;      // digits either side 
of the point
   ```
   
   Both directions are covered — `1E-2000000000` would otherwise make 
`printDecimal` allocate a two-billion-character `StringBuilder`.
   
   A raised limit still raises the bound: `1E+2000` is rejected at the default 
1024 and accepted at `maxChars(4096)`.
   
   ### Still open
   
   `setBigDecimalValue` remains unbounded, so a value like this can still be 
constructed programmatically. That's why #97's guards in `value_hash_code` and 
`to_BigInteger` stay: they now defend a path that a document can no longer 
reach, rather than the one it could.
   
   ### Tests
   
   Two in `TestMathUtil` (the bound applies to denoted digits, in both exponent 
directions and under raised and lowered limits; plain lexical forms are 
unaffected) and two in `MaxNumberOfCharsTest` (a document is rejected with and 
without the exponent option, and an exponent within the limit still parses).
   
   Full suite: 3086 tests, 0 failures.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to