Replace std::equal with an explicitly-bounded loop in the move prefix check

The three-iterator std::equal(first1, last1, first2) form has no
explicit end iterator for the second range, which a static analyzer
(Flawfinder, CWE-126) flags as a potential over-read even though the
preceding size comparison already guarantees the second range is long
enough. Rather than argue the point, make the bound visible in the code
itself via an explicit loop -- every access to ptr.reference_tokens is
now guarded by the same index the loop condition bounds against
from_size.

(The C++14 four-iterator std::equal(first1, last1, first2, last2) form
was tried first as a more minimal fix, but this codebase targets C++11
and that overload is not safely usable under -std=c++11 with all
supported standard library implementations.)

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-06 17:35:51 +02:00
parent f3f7a16dfc
commit 95c1df59ef
2 changed files with 30 additions and 6 deletions
+15 -3
View File
@@ -5028,9 +5028,21 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// reference tokens (already unescaped by json_pointer's
// parser) rather than the raw pointer strings, since a
// token may itself contain an escaped '/' or '~' that
// would defeat a naive string-prefix comparison.
if (JSON_HEDLEY_UNLIKELY(from_ptr.reference_tokens.size() < ptr.reference_tokens.size()
&& std::equal(from_ptr.reference_tokens.begin(), from_ptr.reference_tokens.end(), ptr.reference_tokens.begin())))
// would defeat a naive string-prefix comparison. This is
// written as an explicit, manually-bounded loop (rather
// than std::equal(first1, last1, first2), whose second
// range has no explicit end iterator) so every access to
// ptr.reference_tokens is visibly guarded by the same
// index the loop condition already bounds against
// from_size -- from_size < ptr.reference_tokens.size()
// is checked once, up front, before the loop runs at all.
const auto from_size = from_ptr.reference_tokens.size();
bool from_is_proper_prefix_of_path = from_size < ptr.reference_tokens.size();
for (std::size_t i = 0; from_is_proper_prefix_of_path && i < from_size; ++i)
{
from_is_proper_prefix_of_path = from_ptr.reference_tokens[i] == ptr.reference_tokens[i];
}
if (JSON_HEDLEY_UNLIKELY(from_is_proper_prefix_of_path))
{
JSON_THROW(out_of_range::create(414, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result));
}