Skip to content

fix: make the JSONCPP_USE_SECURE_MEMORY build compile and pass - #1709

Merged
baylesj merged 2 commits into
open-source-parsers:masterfrom
lenamonj:fix-secure-memory-build
Aug 20, 2026
Merged

baylesj merged 2 commits into
open-source-parsers:masterfrom
lenamonj:fix-secure-memory-build

Conversation

@lenamonj

Copy link
Copy Markdown
Contributor

JSONCPP_USE_SECURE_MEMORY=1 does not build. It fails in three separate ways, each hidden behind the previous one, so fixing only the first gets you to the second. No CI job builds this configuration, which is how they accumulated.

Reproduce on master (60de77f), MSVC 19.44 x64:

cmake -S . -B sb -A x64 -DCMAKE_CXX_FLAGS="/DJSONCPP_USE_SECURE_MEMORY=1 /std:c++17"
cmake --build sb --config Debug
include\json\allocator.h(47,5): error C3861: 'RtlSecureZeroMemory': identifier not found

1. The _WIN32 branch calls RtlSecureZeroMemory without including <windows.h>. Removing that branch lets the portable volatile std::fill_n path handle Windows too. The same fill was zeroing n bytes rather than n * sizeof(T); Json::String is SecureAllocator<char> so it is unaffected, but any wider T through the public Json::Allocator<T> alias was leaving most of the allocation un-wiped.

2. jsontestrunner declares a std::string where the surrounding code uses Json::String. Identical types in default builds, different under secure memory, so the runner does not compile. One line.

3. CZString's move-assignment releases a key with releasePrefixedStringValue, but CZString keys come from duplicateStringValue and carry no length prefix. The destructor already uses the matching releaseStringValue. Under the default allocator the mismatch is survivable; under SecureAllocator the suite segfaults. This is the one that only appears after the first two are fixed.

Verification. Before: error C3861. With only 1 and 2 fixed: builds, then jsoncpp_test (SEGFAULT). With all three: secure build compiles and 3/3 ctest suites pass. The default build is unaffected and also 3/3.

Fixes #1399, which reported both the portability problem and that "the unit tests won't build".

Building with JSONCPP_USE_SECURE_MEMORY=1 fails in three separate ways,
each hidden behind the previous one. No CI job builds this configuration,
which is why they have accumulated.

1. allocator.h calls RtlSecureZeroMemory on the _WIN32 branch without
   including <windows.h>, so MSVC fails with error C3861. Removing that
   branch lets the portable volatile std::fill_n path handle Windows.
   The same fill was zeroing n bytes rather than n * sizeof(T), so for
   any T wider than a char, most of the allocation was never wiped.

2. jsontestrunner declares a std::string where the surrounding code uses
   Json::String. The two are the same type only in default builds, so the
   test runner does not compile under secure memory.

3. CZString's move-assignment released a key with
   releasePrefixedStringValue, but CZString keys come from
   duplicateStringValue and carry no length prefix. The destructor
   already uses the matching releaseStringValue. Under the default
   allocator this mismatch is survivable; under SecureAllocator the
   suite segfaults.

Verified on MSVC 19.44, x64, C++17. Before: error C3861. With only the
first two fixed: builds, then jsoncpp_test SEGFAULT. With all three:
secure build compiles and 3/3 ctest suites pass. The default build is
unaffected and also 3/3.

Fixes open-source-parsers#1399
lenamonj added a commit to lenamonj/jeffy-loop that referenced this pull request Jul 30, 2026
Filed JC-1 and JC-7 together with the CZString move-assignment fix as
open-source-parsers/jsoncpp#1709, 4 files +32/-31, closing #1399 which
has been open since March 2022 reporting both the portability problem
and that the unit tests will not build.

Two findings from preparing the PR, both recorded in the receipt. The
CZString hunk looked like scope creep; reverting it proved the secure
build compiles and then segfaults, so it is load-bearing and the layered
failure is now the PR's strongest argument. The under-wipe claim was cut
back: Json::String is SecureAllocator<char> so sizeof(T) is 1 and it is
unreachable there, latent only for wider T via Json::Allocator<T>.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015iiwS6T2sCVr6b1hEztqww
@baylesj

baylesj commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

@greptileai

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown

Greptile Summary

This PR repairs the secure-memory configuration by making memory wiping portable and complete, matching CZString deallocation to its allocation format, and using allocator-compatible string types in the test executables.

  • Removes the undeclared Windows-specific secure-zeroing call and wipes the complete allocation through a volatile byte view.
  • Releases moved CZString keys with the non-prefixed deallocator used by their allocation path.
  • Converts affected test and runner strings and streams to JsonCpp’s allocator-aware aliases.
  • Adds focused CZString move-operation coverage.

Confidence Score: 5/5

The PR appears safe to merge, with no actionable correctness or security failures identified in the changed paths.

The allocator now wipes the full allocated byte range using supported portable operations, CZString cleanup matches its allocation format, and the affected secure-build test interfaces consistently use allocator-aware string types.

Important Files Changed

Filename Overview
include/json/allocator.h Replaces the undeclared Windows-only zeroing call with the portable volatile fill path and corrects the wipe length for arbitrary allocator element sizes.
src/jsontestrunner/main.cpp Uses Json::String for filename extraction so the runner remains allocator-compatible in secure-memory builds.
src/lib_json/json_value.cpp Corrects CZString move-assignment cleanup to use the deallocator matching its non-prefixed key allocation.
src/test_lib_json/main.cpp Converts affected test data, streams, helpers, and containers to allocator-aware JsonCpp string aliases and adds CZString move coverage.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Secure-memory build enabled] --> B[Json::String uses SecureAllocator]
  B --> C[Allocator deallocation]
  C --> D[Volatile wipe of n times sizeof T bytes]
  D --> E[Global delete]
  B --> F[CZString owning key]
  F --> G[Move assignment releases prior key]
  G --> H[releaseStringValue with stored length]
  H --> I[Take source key ownership]
Loading

Reviews (1): Last reviewed commit: "Merge branch 'master' into fix-secure-me..." | Re-trigger Greptile

@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 32423582949

Coverage remained the same at 89.907%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 2740
Covered Lines: 2615
Line Coverage: 95.44%
Relevant Branches: 2640
Covered Branches: 2222
Branch Coverage: 84.17%
Branches in Coverage %: Yes
Coverage Strength: 23828.01 hits per line

💛 - Coveralls

@baylesj

baylesj commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

We probably want to add a GitHub Action for this build configure to ensure that it does not regress. Added an issue:

#1712

@baylesj
baylesj merged commit c6f68ac into open-source-parsers:master Aug 20, 2026
27 checks passed
@lenamonj
lenamonj deleted the fix-secure-memory-build branch September 5, 2026 12:54
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.

JSONCPP_USING_SECURE_MEMORY uses memset_s which isn't portable

3 participants