Update to Decimal 3.0, update dependencies, fix Elixir 1.19 warnings - #67
Conversation
- Update decimal dependency to ~> 3.0 (with backwards compat for ~> 1.5 and ~> 2.0) - Update other dependencies in mix.lock - Move preferred_cli_env to def cli (deprecated in Mix 1.19) - Replace single-quoted charlists with ~c sigil in doctests - Fix compile-time type checker warning in conversion test
|
@danielberkompas There is a moderate vulnerability in the |
Decimal.new/1 in 3.x rejects strings exceeding the default max_digits (28). Use Decimal.parse/2 with max_digits: 100 in the BitString implementation of Number.Conversion.to_decimal/1. Also narrows the decimal dep spec to ~> 3.0 since parse/2 with max_digits is a 3.x-only API. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
|
Problem Decimal 3.x made The crash path: Fix Replace Since |
DerTim1
left a comment
There was a problem hiding this comment.
You could use decimal ~> 3.1 to avoid a bug in 3.0.0.
|
@danielberkompas or @DerTim1 Any update on this? Seems like the CI step didn't complete as expected? It'd be great to land this change. My dependency chain is :backpex -> :number -> :decimal 1.5-2.0...and that's starting to cause some issues now that a lot of other packages have switched to decimal ~> 3.0. |
I'm forking the library. hang tight |
Decimal 3.x's Decimal.new/1 caps parsing at 28 significant digits by default and raises on longer float-derived strings (e.g. to_string of a float can yield 35+ digits), which crashed number_to_delimited/2 and number_to_currency/2. Switch the BitString Number.Conversion impl to Decimal.parse/2 with max_digits: 100, which is a 3.x-only API and is why the dep is narrowed to ~> 3.0 (no 1.x/2.x backward compat). Drop the DECIMAL_VERSION-driven dual-lockfile setup (mix-decimal1.lock, lockfile/0) since it now only ever resolves the same decimal version. Ports the fix from danielberkompas/number#67.
- preferred_cli_env in project/0 is deprecated in Mix 1.19; move it
into a def cli/0 with preferred_envs instead.
- Single-quoted charlist literals ('...') are deprecated in favor of
the ~c sigil.
- Elixir's type checker now statically flags
to_float(%{hello: "world"}) as unreachable (it can prove the
BitString-only guard clauses can't match a map) and fails the build
under --warnings-as-errors. Use :erlang.apply/3 to bypass static
analysis so the runtime Protocol.UndefinedError test still exercises
the intended behavior.
Ports the fixes from danielberkompas/number#67.
|
I've forked Number here https://github.com/Ch4s3/number_formatter and released it to hex https://hex.pm/packages/number_formatter/1.0.0 |
|
@Ch4s3 Just FYI, the :backpex maintainers realized they weren't actually using :number any more, and they removed it as a dependency (naymspace/backpex@02dd429). This solved my particular problem, but it's still of course awesome that you forked :number to keep it maintained and up to date! |
|
@eriknaslund we use it, so I'm happy to pick it up and the surface area is small. Backpex looks cool, I'd have lived that 4 years ago! |
Problem
Decimal 3.x made
Decimal.new/1strict about the number of significant digits it accepts (default max: 28). This causesNumber.Delimit.number_to_delimited/2andNumber.Currency.number_to_currency/2to crash withDecimal.Errorwhen given float-derived strings with more than 28 significant digits (e.g."0.02053473047423571351409743977530517"— 35 digits, typical of IEEE 754 double-precision float-to-string conversion).The crash path:
number_to_delimitedconverts a non-integer input to a string viato_string/1, then passes it throughNumber.Conversion.to_decimal/1, which callsDecimal.new/1on the raw string.Fix
Replace
Decimal.new(string)withDecimal.parse(string, max_digits: 100)in theBitStringimplementation ofNumber.Conversion.to_decimal/1. This is the single chokepoint where arbitrary strings become Decimals in the library. 100 digits provides generous headroom beyond any realistic float-derived input while still bounding the parse.Since
Decimal.parse/2with themax_digitsoption is a 3.x-only API, this also narrows the decimal dependency to~> 3.0. If backwards compatibility with decimal 1.x/2.x is desired, a compile-time check forfunction_exported?(Decimal, :parse, 2)could be added — happy to make that change if needed.