Repository navigation
Fix to_bjdata() silently truncating out-of-range _ArrayData_ elements - #5473
Merged
Merged
Conversation
This was referenced Sep 5, 2026
Merged
gregmarr
approved these changes
Sep 8, 2026
write_bjdata_ndarray() validated that each _ArrayData_ element matched the number kind (integer vs. float) named by _ArrayType_, but not its range. An element that did not fit the target C++ type (e.g. 256 for "uint8") was silently wrapped by the static_cast used to write it, or, for "single", silently overflowed to infinity. Range-check each element against the type named by _ArrayType_ before writing it, reusing the existing fallback path that already encodes the annotated object as a plain object for other invalid-annotation cases in this function. Fixes #5403. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
nlohmann
force-pushed
the
issue-5403-bjdata-uint-range
branch
from
September 9, 2026 08:21
d2c2db9 to
9eb08e9
Compare
nlohmann
added a commit
that referenced
this pull request
Oct 4, 2026
- binary_reader: keep emitting "_ArrayType_" from get_ubjson_size_value() (before "_ArraySize_"), now via develop's static bjd_type_name(); drop develop's later emission in get_ubjson_array() - binary_writer: develop's out-of-range check for ND-array elements (#5473, #5730) now also requires that single-precision elements survive the narrowing exactly, which is what this branch adds for #5661 Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The BJData ndarray writer (
write_bjdata_ndarrayininclude/nlohmann/detail/output/binary_writer.hpp) validated the kind of each_ArrayData_element (integer vs. float) against the declared_ArrayType_, but not its range. Each element is written with a narrowing cast, e.g.write_number(static_cast<std::uint8_t>(el.get<std::uint64_t>()), true)for_ArrayType_ = "uint8". An out-of-range element (e.g.256) was silently wrapped by that cast instead of being reported — no error, no fallback.Fix
Each
_ArrayData_element is now range-checked against the C++ type named by_ArrayType_before being cast:uint8/int8/uint16/int16/uint32/int32/uint64/int64, pluschar/bytewhich share theuint8range) are checked with the existingvalue_in_range_of<TargetType>helper, handling both signed and unsigned JSON number storage (so a negative value is correctly rejected for an unsigned target).single(32-bit float) is checked so that a finitedoublewhich would overflow to infinity when narrowed tofloatis rejected.doubleneeds no additional check since it already spans the full range of the internal float representation.When any element is out of range, the function falls back to the same plain-object encoding already used by this function for other invalid-annotation cases (mismatched kind, non-array
_ArraySize_, overflowing dimensions, etc.), so the value round-trips throughfrom_bjdata(to_bjdata(j))instead of being silently corrupted.Tests
Added a new section
"ndarray with out-of-range _ArrayData_ elements stays as object"intests/src/unit-bjdata.cppcovering:uint8element (256) falls back and round-tripsint8element (200) falls back and round-tripsuint16) falls back and round-tripssingle(float) element that overflows to infinity (1e40) falls back and round-tripsuint80/255,int8-128/127,single1.5) still use the compact ndarray encodingRan the full
unit-bjdatasuite offline (compiled againstinclude/with a stubtest_data.hpp): 693935/693936 assertions pass; the one failure and the one skipped test case are pre-existing and unrelated (they require downloaded test data, unavailable in this offline setup).Breaking change?
No breaking changes. This only affects the BJData ndarray fast-path encoding for annotated objects whose
_ArrayData_previously contained values outside the range implied by_ArrayType_; such objects are now encoded as plain objects (as they already are for the other invalid-annotation cases handled by this same function) instead of emitting silently corrupted data.Fixes #5403.
— opened by Claude Code on behalf of @nlohmann