Skip to content

render: normalizeLocaleNumber strips group separators without validation — "1.5" becomes 15 #539

Description

@Yaraslaut

Part of the sweep tracked in #518. Finding F21.

Summary

render/locale_format.hpp:71-74 strips every occurrence of groupSeparator unconditionally, before the decimal check and with no check that groups are three digits or that the separator appears before the decimal point.

Verification status

Reproduced. Revision: master @ 4017228d.

normalize("1.5",     dec=",", grp=".")  = "15"     <-- de-DE form, US-style decimal typed
normalize("1.50",    dec=",", grp=".")  = "150"
normalize("1.2.3.4", dec=",", grp=".")  = "1234"
normalize("1,5",     dec=".", grp=",")  = "15"     <-- en-US form, EU-style decimal typed
normalize("1.5",     dec=".", grp=".")  = "15"     <-- separators equal, no diagnostic
normalize("-5" with U+2212 MINUS)       = NULLOPT

Not verified: I did not check whether the QML mirror in src/qt/forms/qml/DynamicForm.qml behaves identically. If it does, the two edges are consistently wrong rather than inconsistently, which is a smaller problem but still a wrong value.

Why this is a defect and not a design choice

A German user typing 1.5 into a price field submits 15. This is the single most common real-world locale entry mistake, and the function converts it into a valid-looking value rather than rejecting it — so nothing downstream can catch it. The user is charged ten times with no diagnostic anywhere.

Suggested fix

Validate group placement before stripping: a group separator must be preceded by 1-3 digits, followed by exactly three digits, and must not appear after the decimal separator. "1.5" then correctly returns std::nullopt and the caller can tell the user to fix the entry.

Two smaller fixes while there:

  • assert(decimalSeparator != groupSeparator) — today the decimal is silently eaten.
  • A negativeSign parameter, so a locale using U+2212 MINUS can round-trip.

What would change the verdict

  • Close it if the function is documented as accepting only already-canonical input — but its whole purpose is to normalise user-typed text at the control edge.
  • tests/test_render_locale_format.cpp has 18 cases and none of them is normalize("1.5", ",", "."). Add it, plus the equal-separators case.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: utilSubsystem: utilbugSomething isn't workingtriage: rescopeReal problem, wrong framing; rewrite before building

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions