Skip to content

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

Open
lenamonj wants to merge 1 commit into
open-source-parsers:masterfrom
lenamonj:fix-secure-memory-build
Open

fix: make the JSONCPP_USE_SECURE_MEMORY build compile and pass#1709
lenamonj wants to merge 1 commit into
open-source-parsers:masterfrom
lenamonj:fix-secure-memory-build

Conversation

@lenamonj

Copy link
Copy Markdown

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
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

1 participant