Potential loss of precision when parsing long and integer types
Hi
I noticed a potential issue in how XML numeric types are parsed. In particular, this section of code:
if (name === 'int' || name === 'integer' || name === 'short' || name === 'long') {
value = parseInt(text, 10);
}
While this works fine for short and int (which are within JavaScript's safe integer range), it can lead to loss of precision for long and integer types.
In XML Schema:
long is typically a 64-bit signed integer, with values up to ±9.22e18
integer is unbounded, and can be arbitrarily large
JavaScript’s Number type cannot safely represent integers beyond 2^53 - 1 (Number.MAX_SAFE_INTEGER). Using parseInt here may result in inaccurate values for large numbers.
For example:
parseInt("9223372036854775807", 10) // returns 9223372036854776000
which is incorrect
Maybe, consider using BigInt for parsing long and integer values:
if (name === 'long' || name === 'integer') {
value = BigInt(text);
}
xs:integer (unlimited)
xs:long (64 bit)
xs:unsignedLong (0 … 2⁶⁴ − 1)
xs:negativeInteger, xs:positiveInteger, xs:nonNegativeInteger, xs:nonPositiveInteger (all subset of xs:integer)
xs:decimal
This would ensure large values are parsed accurately.
Let me know what you think — happy to help with a PR if this approach sounds good.
Thanks again!
Speaking as a user and an occasional contributor...
@Gigiz PR is always a good idea with tests to illustrate the context and the problem. Also please tell the maintainers how you came across this issue, if possible. To me it makes sense to address any kind of overflow issues. I also think "unbounded", even if the spec allows, should be somehow reasonably bounded to avoid any kind of possible buffer overflow attacks, but the bound perhaps can be somehow configurable? Is Number.MAX_SAFE_INTEGER) reasonable here to cover the unbounded case?
Well, it may use BigInt for cases when value is type of long. But I think this will require some code refactoring. There are maybe issues with strict comparisons in some places cause BigInt('1') != 1
I agree that under some conditions you may hit this issue. But it seems like it was not seen in the wild yet.
I am happy to review a PR if @Gigiz is willing to help with this and try to implement. But this cand be a bit challenging.