Skip to content

Fix negative integer parsing with JSON_NO_INT64 - #1718

Open
fzlzjerry wants to merge 2 commits into
open-source-parsers:masterfrom
fzlzjerry:fix/1341-no-int64-signed-parsing
Open

Fix negative integer parsing with JSON_NO_INT64#1718
fzlzjerry wants to merge 2 commits into
open-source-parsers:masterfrom
fzlzjerry:fix/1341-no-int64-signed-parsing

Conversation

@fzlzjerry

@fzlzjerry fzlzjerry commented Sep 11, 2026

Copy link
Copy Markdown

Fixes #1341.

OurReader::decodeNumber() subtracts a Value::UInt last digit from a LargestInt expression. With JSON_NO_INT64, both have the same width, so the usual arithmetic conversions make the subtraction unsigned. For example, -1 becomes a uintValue containing 4294967295; even -0 gets the wrong stored type.

Keep the last digit signed. The existing quotient/remainder calculation still handles the minimum signed value without negating it directly.

Making the affected configuration testable

Current master first fails to compile with JSON_NO_INT64 on GCC/Clang because the private integerToDouble(Json::UInt64) overload refers to a disabled type. The patch guards that overload, along with 64-bit-only test helpers and API checks. The existing no-int64 floating-point assertions are updated to the current 17-digit formatting.

The reader/writer fixtures that contain 64-bit limits still run. The test driver reads the executable's existing --json-config output and selects explicit floating-point expectations for those three inputs when integer storage is limited to 32 bits. All other expectations, and all default-configuration expectations, stay unchanged; no fixture is skipped. Invalid configuration output fails the test run.

Added regression tests cover negative zero, digit boundaries, signed limits, scalar/array/object contexts, unsigned limits, and the existing out-of-range floating-point fallback. A separate Linux CMake job exercises the complete no-int64 CTest suite so the configuration stays covered. It pins checkout to a full commit, limits permissions to read-only contents, and disables persisted checkout credentials.

There are no public-header changes. This does not add sign-only-token validation; that is covered separately by #1703. The verified reproduction is a Linux build with the library and consumer both compiled with JSON_NO_INT64, rather than a reproduction of the original MSVC 2015 environment.

Validation

  • Pristine master: the default build passes all 3 CTests; the no-int64 build fails at the unguarded overload. With only that prerequisite guard applied, all 8 negative CharReader consumer cases fail while the 8 legacy Reader controls pass. Both readers pass all 16 cases after the fix.
  • GCC 14 and Clang 19 × C++11/17/20 × default/no-int64: all 12 configurations pass all 3 CTests with the repository's normal warning settings. Both integer configurations pass all 133 C++ unit tests.
  • Meson 1.5.1, Clang 19, C++11, shared/static libraries and werror=true: all 3 test suites pass in both configurations.
  • Full no-int64 CTest run passes with AddressSanitizer, UndefinedBehaviorSanitizer and LeakSanitizer enabled.
  • 21 configuration/real-CLI scenarios check configuration errors, expected-file selection, missing variants, and deliberately corrupted expectations.
  • C++11 amalgamated builds and installed-library consumers built with Clang C++17/C++23 pass in both configurations. The default Linux dynamic export set is unchanged (1,905 symbols).
  • clang-format 18 over src, include and example, actionlint, and git diff --check pass.

An additional warnings-as-errors stress run encounters pre-existing GCC C++20 implicit-this capture and Clang C++17/20 signed-size warnings. Those failures were reproduced on pristine master; the unrelated source lines are unchanged.

Copilot AI lite review requested due to automatic review settings September 11, 2026 00:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Sep 11, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes signed negative-integer decoding when JsonCpp is built with JSON_NO_INT64 and makes that configuration continuously testable.

  • Keeps the final digit signed during negative integer reconstruction, preserving signed values and the intValue type.
  • Guards code and test helpers that require 64-bit integer aliases.
  • Adds boundary and container-context regression coverage.
  • Selects configuration-specific corpus expectations through validated --json-config output.
  • Adds a least-privilege CMake CI job for the no-int64 configuration.

Confidence Score: 5/5

The PR appears safe to merge; no outstanding correctness, security, or repository-rule issue remains.

The signed reconstruction now preserves negative integer values and types under JSON_NO_INT64, while out-of-range values retain their floating-point fallback. The previous workflow-security finding was manually resolved after the checkout action was pinned and the job was hardened.

Important Files Changed

Filename Overview
src/lib_json/json_reader.cpp Preserves signed arithmetic while reconstructing negative integers, including the minimum configured signed value.
src/lib_json/json_value.cpp Excludes the unavailable UInt64-specific conversion overload when 64-bit integer support is disabled.
src/test_lib_json/main.cpp Makes unit tests configuration-aware and adds comprehensive negative-integer and numeric-boundary regressions.
test/runjsontests.py Validates the executable’s integer configuration and selects matching expected corpus output.
.github/workflows/cmake.yml Adds a hardened CI job that builds and runs the complete no-int64 CTest suite.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A["JSON numeric token"] --> B["OurReader::decodeNumber"]
    B --> C{"Within configured integer range?"}
    C -->|Negative| D["Signed LargestInt reconstruction"]
    C -->|Non-negative| E["Signed or unsigned Value"]
    C -->|Out of range| F["Floating-point fallback"]
    D --> G["Json::Value tree"]
    E --> G
    F --> G
    G --> H["Unit and corpus round-trip tests"]
Loading

Reviews (2): Last reviewed commit: "Pin checkout and limit permissions in th..." | Re-trigger Greptile

Comment thread .github/workflows/cmake.yml Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OurReader::DecodeNumber leads to bad value type

2 participants