Fix and rework binary_to_float/list_to_float#2246
Conversation
|
usual caveats, I'm just the messenger;-) PR Review: Add locale-independent float parsingCommit: SummaryReplaces Overall assessment: Good direction — approve with changes. Two correctness bugs must be fixed before merge. 🔴 Must-Fix Issues1.
|
375f10e to
36b9348
Compare
|
Root cause: Test B10 expect_bin_badarg(<<"1,0">>) — OTP currently accepts "," as a decimal separator (binary_to_float(<<"1,0">>) → 1.0). The test expects badarg, losing exactly 512. The commit intentionally rejects commas (per erlang/otp#9061 future direction), but the CI runs on BEAM where commas still work. |
21ca1c2 to
eb4000b
Compare
`binary_to_float(<<"1.0e999">>)` returned inf instead of raising `badarg`. Add `isfinite()` check after `sscanf()` to reject non-finite results, matching Erlang/OTP behavior. Signed-off-by: Davide Bettio <davide@uninstall.it>
Replace sscanf-based float parsing in `binary_to_float`/`list_to_float`
with a proper implementation that validates strict bare float format
and uses locale-independent `strtod`/`strtof`.
Rename `unlocalized_snprintf.{c,h}` to `unlocalized.{c,h}` and add
`unlocalized_strtod()`, `unlocalized_strtof()`, and
`unlocalized_validate_bare_float_format()`. An inline dispatcher
`unlocalized_strto_avm_float()` selects the right variant based on
`AVM_USE_SINGLE_PRECISION`. The three locale strategies (`strtod_l` /
`uselocale` / fallback with separator retry) are shared via a
`prepare_locale_retry_buf()` helper.
Refactor `float_utils` to follow the same pattern: guard
`double_write_to_ascii_buf` and Grisu3 internals behind
`FLOAT_UTILS_ENABLE_DOUBLE_API`, and 32-bit support behind
`FLOAT_UTILS_ENABLE_FLOAT_API`, so no `double` code leaks into a
float-only build and vice versa. Rename `double_format_t` to
`float_format_t` since the enum belongs to the `float_utils` module,
not the `double` type.
The bare float format `[+|-]DIGITS.DIGITS[(e|E)[+|-]DIGITS]` matches
Erlang/OTP's `binary_to_float`/`list_to_float`, except commas are not
accepted as decimal separators (aligning with OTP's future
direction per erlang/otp#9061).
Signed-off-by: Davide Bettio <davide@uninstall.it>
binary_to_float and list_to_float share the same parsing code, so there is no need for two near-identical test modules. Merge them into a single string2float test that covers binary_to_float exhaustively and adds a few basic list_to_float smoke tests. Signed-off-by: Davide Bettio <davide@uninstall.it>
eb4000b to
c1d2e6c
Compare
Merge fixes, features, and optimizations from release-0.7, including: - Add signature-driven code loader (#2229) - Add UART support on generic_unix via POSIX termios NIFs (#2243) - Add erlang node/1 BIF (#2225) - Add erts_internal:cmp_term/2 NIF and fix map type ordering (#2226) - Add short option to float_to_binary/list (#2240) - Add locale-independent float parsing and fix overflow (#2246) - JIT: add RISC-V 64-bit backend (#2231) - JIT: add DWARF debug information support (#1910) - JIT x86: instruction encoding optimizations (#2234) - JIT: remove redundant AND when untagging integers (#2235) - Fix bug in bs_match get_tail handling (#2242) - Fix binary encoding of int:24 and others (#2230) - Fix cancel_timer/1 spec and documentation (#2244) - Resurrect opcodes emitted with no_bs_create_bin (#2245) - Fix flaky tests related to GitHub DNS Resolver (#2232) - Add git guide (#2106)
Fix
binary_to_float/1andlist_to_float/1overflow bug and replacethe locale-dependent sscanf-based parser with strict, locale-
independent float parsing.
binary_to_float(<<"1.0e999">>)returninginfinstead ofraising
badarg, matching Erlang/OTP behavior.sscanfwithunlocalized_strtod()/unlocalized_strtof(),which validate strict bare float format and use a 3-strategy
locale-independent approach (
strtod_l/strtof_l/uselocale/fallback with
prepare_locale_retry_buf()helper).unlocalized_strto_avm_float()inline dispatcher that selectsthe right variant based on
AVM_USE_SINGLE_PRECISION.unlocalized_snprintf.{c,h}tounlocalized.{c,h}and addunlocalized_validate_bare_float_format(),unlocalized_strtod(),and
unlocalized_strtof()sharing the same cached C localeinfrastructure.
UNLOCALIZED_ENABLE_DOUBLE_API/FLOAT_UTILS_ENABLE_DOUBLE_APIand float-only code behindUNLOCALIZED_ENABLE_FLOAT_API/FLOAT_UTILS_ENABLE_FLOAT_API,so no
doublecode leaks into a float-only build and vice versa.double_format_ttofloat_format_tandDoubleFormat*to
FloatFormat*since the enum belongs to thefloat_utilsmodule, not the
doubletype.sscanfwrongly accepted: hex floats,inf,nan, whitespace, missing decimal point, missing digits arounddot, and commas as decimal separator (per binary_to_float doesn't correctly handle scientific notation with no decimal places specified, such as "1e0" erlang/otp#9061).
bin2floatandlist2floattest modules into a singlestring2floattest and expand coverage from 9 to 39 casesincluding overflow, underflow, special values, format violations,
and edge cases.
These changes are made under both the "Apache 2.0" and the "GNU Lesser
General Public License 2.1 or later" license terms (dual license).
SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later