Repository navigation
Conversation
get_decimal_point() wrote "1" and the locale's decimal point with sprintf into char buf[3] and returned buf[1]. In a locale whose point is more than one byte, such as ps_AF.UTF-8 (U+066B, 2 bytes in UTF-8), that overflows buf by one byte, and only the first byte of the point is used: to_locale() puts a partial UTF-8 sequence in place of '.', strtod() stops early and json_loads() of a real such as 1.5 fails the assert in jsonp_strtod(). With USE_DTOA off, from_locale() has the same one-byte assumption when printing. get_decimal_point() now returns the whole point as a string. to_locale() grows the buffer when the point is longer than '.' and jsonp_strtod() returns -2 if it cannot, which the lexer reports as out of memory. from_locale() replaces the whole point and shortens the output. The point buffer holds MB_LEN_MAX bytes, the most one character can take. The test loads reals under ps_AF.UTF-8, dumps them, checks the output has no byte of the locale's point, and reloads it in the C locale to compare values. It restores the caller's LC_NUMERIC, and says it skipped when that locale is not installed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pargue
force-pushed
the
fix/multibyte-decimal-point
branch
from
November 2, 2026 19:11
45e5ec4 to
493e968
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Handle a decimal point longer than one byte
get_decimal_point()writes"1"and the locale's decimal point withsprintfintochar buf[3]and returnsbuf[1]. In a locale whose decimal point is more than one byte, such asps_AF.UTF-8(U+066B, 2 bytes in UTF-8):sprintfwrites 4 bytes into the 3-byte buffer (ASan: stack-buffer-overflow inget_decimal_point);to_locale()puts a partial UTF-8 sequence where the.was,strtod()stops early, andjson_loads("[1.5]")fails the assert injsonp_strtod();USE_DTOAoff,from_locale()makes the same one-byte assumption when printing.It only happens when the program has set
LC_NUMERICto such a locale.The change:
get_decimal_point()returns the whole point as a string, in a buffer ofMB_LEN_MAXbytes (the most one character can take).to_locale()grows the buffer when the point is longer than., andjsonp_strtod()returns -2 if it cannot, which the lexer reports as "out of memory" instead of "real number overflow".from_locale()replaces the whole point and shortens the output.Test:
test_multibyte_decimal_pointintest/suites/api/test_number.cloads reals underps_AF.UTF-8(including ones long enough to grow the buffer), dumps them, checks the output holds no byte of the locale's point, and reloads it in the C locale to compare values. It restores the caller'sLC_NUMERIC. When the locale is not installed it prints that it skipped, which is likely on CI; locally it was built withlocaledef -i ps_AF -f UTF-8 <dir>/ps_AF.UTF-8and run withLOCPATH=<dir>. On master it fails under ASan with the stack-buffer-overflow above; with the fix the full suite passes (215 tests) withUSE_DTOAon and off, under ASan/UBSan.Not changed here: as before,
jsonp_strtodconvertssaved_textin place, so a "real number overflow near '...'" message under such a locale shows the locale's point rather than the input's.. Parsing withstrtod_land a C locale where available would avoid the rewrite entirely; that is a larger change than this fix.