Story: Hotfix: the macOS parser refuses the smallest subnormal
Table of Contents
This page documents a story in Sprint 26. It captures the goal, current status, acceptance criteria, and the tasks that compose it.
1. Goal
The macOS test phase fails one assertion:
projects/ores.platform/tests/numeric_floating_point_tests.cpp:93: FAILED: parsed.has_value() for: false
The case formats each of a set of doubles with @c std::to_chars and reads
each back with ores::platform::numeric::parse_double. On Apple platforms
libc++ formats the smallest denormal as 5e-324, and the conversion the shim
used – boost::lexical_cast through a stream – reports the range error the C
library raises for a subnormal result as a stream failure, so the parse
answered nullopt for a value a double holds. Linux and Windows report the
same range error without failing the extraction, which is why only macOS saw
it.
The header promised a parser that refuses "a value outside the range of a
double". A subnormal is inside that range, and the shim refused it by
accident on one platform; 1e-400, which really is outside it, was accepted
by accident on the others.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent sprint | Sprint 26 |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-09-30 |
3. Acceptance
parse_double("5e-324")returns the denormal, notnullopt, so the round trip passes on macOS.- A value that rounds to zero or to infinity is refused, which is what the header always claimed.
- The parse does not follow the program's locale: with a comma locale in force, an English number still parses and a comma one is still refused.
- The conversion does not go through a stream, so libc++'s treatment of the range error cannot decide the answer.
- The platform suite and the full suite pass.
4. Tasks
| Task | State | Start | End | Description |
|---|---|---|---|---|
| Implement Hotfix: the macOS parser refuses the smallest subnormal | DONE | 2026-09-30 | 2026-09-30 | Replace the stream conversion with a hand-written grammar check and a C-locale conversion, add the subnormal and underflow cases to the suite, and prove the locale independence on Linux. |
5. Decisions
- The grammar is checked in the shim rather than left to the conversion, so
the accepted syntax depends on neither the program's locale nor the C
library's extensions: hexadecimal input,
infandnanare not numbers. - The conversion runs in a C locale of its own –
strtod_l,_strtod_lon Windows, with the macOS header behind__has_include– rather than in a stream. It is the stream, not the C library, that decides a subnormal is a failure on libc++. - A result that rounds to zero is refused even though it is finite: the type cannot tell it from a real zero, and the header calls that outside the range. The old parser accepted it, and no caller depended on that.
- The two hotfixes of this evening are separate branches. This one shares no file with the exported-type one.
6. Out of scope
- libc++'s missing floating-point @c from_chars, which the shim exists to stand in for. Nothing here changes when Apple implements it; the shim can then be deleted.