Skip to content

Commit 8661f9e

Browse files
authored
Fix number parsing failing under non-C locales (#1662)
IStringStream inherits the global locale, so parsing doubles with operator>> fails when the locale uses ',' as the decimal separator (e.g. de_DE). Imbue the stream with std::locale::classic() in both Reader::decodeDouble and OurReader::decodeDouble. The writer already handles this correctly via fixNumericLocale(). Fixes #1565
1 parent 215b025 commit 8661f9e

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

RELEASE_1.9.7.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# jsoncpp 1.9.7 Release Work
2+
3+
Issues to fix before tagging 1.9.7, each in a separate CL.
4+
5+
---
6+
7+
## Done
8+
9+
- [x] **#1656** — Fix uninitialized CMake variable `JSONCPP_VERSION` in `version.in`
10+
→ Change `@JSONCPP_VERSION@` to `@jsoncpp_VERSION@`
11+
12+
---
13+
14+
## To Do
15+
16+
### Security / Memory Safety
17+
18+
- [ ] **#1626** — MemorySanitizer: use-of-uninitialized-value in `Json::Value::resolveReference`
19+
→ Uninitialized value detected by MSan in `json_value.cpp`. Need to identify and zero-initialize the offending member.
20+
21+
- [ ] **#1623** — Use-after-free: `Json::Reader::parse` stores raw pointers into input string
22+
`Reader` stores `begin_`/`end_` pointers that dangle after the input `std::string` goes out of scope. `getFormattedErrorMessages()` then reads freed memory.
23+
→ Fix: copy the input document internally, or clearly document the lifetime requirement (the simpler option given the old Reader API is deprecated).
24+
25+
### Correctness
26+
27+
- [x] **#1565** — Number parsing breaks when user sets a non-C locale (e.g. `de_DE`)
28+
`istringstream`/`ostringstream` used for number parsing/writing inherit the global locale, which may use `,` as decimal separator instead of `.`.
29+
→ Fix: imbue streams with `std::locale::classic()` in `json_reader.cpp` and `json_writer.cpp`.
30+
31+
- [ ] **#1546** — Control characters below 0x20 not rejected during parsing
32+
→ JSON spec requires rejecting unescaped control characters. jsoncpp currently accepts them.
33+
34+
### Build / CMake
35+
36+
- [ ] **#1634**`JSON_DLL_BUILD` compile definition applied globally instead of per-target
37+
`add_compile_definitions` scopes it to all targets; should use `target_compile_definitions` scoped to the shared lib only.
38+
39+
- [x] **#1598** — CMake 3.31 deprecation warning about compatibility with CMake < 3.10
40+
→ Update `cmake_minimum_required` to use `<min>...<max>` version range syntax, e.g. `cmake_minimum_required(VERSION 3.10...3.31)`.
41+
42+
- [x] **#1595** — Linker errors with `string_view` API when jsoncpp built as C++11 but consumer uses C++17
43+
→ Root cause: `JSONCPP_HAS_STRING_VIEW` is not defined when building the library (forced C++11), but consumer with C++17 sees the `string_view` overloads in headers and tries to link them.
44+
→ Fix options: (a) export `JSONCPP_HAS_STRING_VIEW` in the CMake config so consumers see the same value, or (b) drop `CMAKE_CXX_STANDARD` force and use `target_compile_features(cxx_std_11)` instead.
45+
46+
---
47+
48+
## Skipped (not bugs)
49+
50+
- **#1548** — "Memory leak" after parsing large files: confirmed to be normal allocator behavior (OS doesn't immediately reclaim heap). Not a library bug.
51+
- **#1533**`clear()` then adding values fails: `clear()` preserves the value type by design. Confirmed user error.
52+
- **#1547** — Trailing commas/garbage not rejected: existing behavior, controllable via `strictMode()`. Not a regression.

src/lib_json/json_reader.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ bool Reader::decodeDouble(Token& token) {
583583
bool Reader::decodeDouble(Token& token, Value& decoded) {
584584
double value = 0;
585585
IStringStream is(String(token.start_, token.end_));
586+
is.imbue(std::locale::classic());
586587
if (!(is >> value)) {
587588
if (value == std::numeric_limits<double>::max())
588589
value = std::numeric_limits<double>::infinity();
@@ -1617,6 +1618,7 @@ bool OurReader::decodeDouble(Token& token) {
16171618
bool OurReader::decodeDouble(Token& token, Value& decoded) {
16181619
double value = 0;
16191620
IStringStream is(String(token.start_, token.end_));
1621+
is.imbue(std::locale::classic());
16201622
if (!(is >> value)) {
16211623
if (value == std::numeric_limits<double>::max())
16221624
value = std::numeric_limits<double>::infinity();

0 commit comments

Comments
 (0)