-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Possible Bug] - Display panics for large numbers #108
Comments
Ok: edge case comes from subtracting the length of the "decimal" string from the scale, counting how many digits should come before the decimal point: Line 1957 in 2633d23
Interesting, I wrote this unit test
and got So... that's a bad sign. |
It boils down to we don't support exponential syntax? In which case, anything close to i64 min or max (or even the 4GB of i32 min/max) will cause problems. I don't know what heuristic to use for formatting decimals in exponential-form vs standard-form. Definitely a bug that needs fixed, but I'm not too worried about it as it's been there for 6 years. It's on the todo list |
Another issue here which isn't related to the edge case, it's not obvious that display will allocate so much memory for large numbers. EG - try those examples just below the limit. Display does huge allocations.
The to_string call here allocates 9223372036854775805 bytes of memory Doesn't seem necessary for displaying. Would be better to have some limit where you display in exponential form. edit: I see now that you came across the same problem here - #108 (comment) |
**Description** Add a second path to the `Display` impl so that numbers that have a large scale relative to length of their integer representation are formatted differently. Specifically, I switched it to use exponential number format like: ``` 1.23456789E38 ``` instead of ``` 123456789000000000000000000000000000000 ``` **Motivation** If you extrapolate from the example above, and also looking at issue #108, you could see that with large exponents you run the risk of large allocations, since the resulting bytestring is proportional in size to the exponent. Any software using the `bigdecimal` crate and converting unprotected uer input into the `BigDecimal` type runs the risk of allocating way too much and potentially crashing, if they happen to use either the `Debug` or `Display` impls. This change is useful because it bounds the output and prevents unexpected large allocations when formatting the `BigDecimal` type **Testing Done** `cargo test && ./scripts/bigdecimal-property-tests test` **Backwards Compatibility Criteria** I believe that this does not constitue a backwards incompatible change because the `BigDecimal::from_str` method already supports exponential format numbers as input.
**Description** Add a second path to the `Display` impl so that numbers that have a large scale relative to length of their integer representation are formatted differently. Specifically, I switched it to use exponential number format like: ``` 1.23456789E38 ``` instead of ``` 123456789000000000000000000000000000000 ``` **Motivation** If you extrapolate from the example above, and also looking at issue #108, you could see that with large exponents you run the risk of large allocations, since the resulting bytestring is proportional in size to the exponent. Any software using the `bigdecimal` crate and converting unprotected uer input into the `BigDecimal` type runs the risk of allocating way too much and potentially crashing, if they happen to use either the `Debug` or `Display` impls. This change is useful because it bounds the output and prevents unexpected large allocations when formatting the `BigDecimal` type **Testing Done** `cargo test && ./scripts/bigdecimal-property-tests test` **Backwards Compatibility Criteria** I believe that this does not constitue a backwards incompatible change because the `BigDecimal::from_str` method already supports exponential format numbers as input.
We're running into the same issue in production when converting a large BigDecimal to a string. Design-wise, the |
Does the branch in MR #121 fix the issue? |
It did not. This line had a potential out of bounds error if the exponent was near the i64 boundary, and had to be shifted forward or backwards past the boundaries when displaying in scientific notation: Line 233 in dbf3b48
Casting the length and |
I casted a bunch of i64's to i128's before doing formatting stuff, and added some tests where the exponent is near the i64 boundary: Lines 563 to 572 in 72818b7
Those test round-tripping, so everything rendered in .to_string() is able to be parsed (which wasn't true before). |
Where did these issues come up? I know Python limits Decimal exponents to 10^18 (about 60 bits) and Java uses 32-bit a scale so I thought 64 bits would be enough for anybody. But I guess not? Obviously these were bugs needing to be fixed, but I'm curious where they come up? |
Is was while importing a user-submitted CSV. It comes in as text, then BigDecimal parses the exponential number successfully (signals that the text was a number). When we serialize the value we get the error. Our temp fix is to manually check for overflows. |
Should be fixed in 0.4.3! |
Is this intentional? I think it'd be an improvement to avoid panics in display, and simply use a different display format for numbers that can't be displayed with the standard implementation.
EG: the following test will panic
Will panic with "attempt to subtract with overflow"
Same for example for
The text was updated successfully, but these errors were encountered: