Skip to content

Resolve the TODO(niels) in get_ubjson_string - #5355

Open
nlohmann wants to merge 1 commit into
developfrom
claude/todo-243-ubjson-noop-todo
Open

Resolve the TODO(niels) in get_ubjson_string#5355
nlohmann wants to merge 1 commit into
developfrom
claude/todo-243-ubjson-noop-todo

Conversation

@nlohmann

@nlohmann nlohmann commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary

binary_reader::get_ubjson_string carried a decade-old open question:

get();  // TODO(niels): may we ignore N here?

The answer is no, and the surrounding code already implements it correctly — it was just never written down or covered by a test.

Two reasons:

  1. The byte read at that point must be a string length type specification (U, i, I, l, L). A no-op is not valid there, and a bare N in that position is genuinely malformed input that the reader correctly rejects with parse_error.113.
  2. No-ops at positions where a value may start are already consumed before this function is reached: the array and object loops and parse_ubjson_internal go through get_ignore_noop(). The only caller that passes get_char = true for an object key is the sized (optimized) object path, where UBJSON does not permit no-ops at all.

So the get() is right as it stands. This PR replaces the TODO with a comment saying why, and pins the behavior with regression tests.

Changes

  • include/nlohmann/detail/input/binary_reader.hpp — TODO replaced by an explanatory comment. No behavior change; this is the only remaining TODO in the parsing headers.
  • tests/src/unit-ubjson.cpp — new SECTION("no-op markers") under parsing values, 9 assertions:
    • accepted: N i11; N N N i11; [N i1][1]; [i1 N][1]; {N U1"a" i1}{"a":1}; {U1"a" N i1}{"a":1}; {U1"a" i1 N}{"a":1}
    • rejected with parse_error.113 ("expected length type specification"): S N U1"a" (no-op after the S marker) and {#i1 N U1"a" i1} (no-op as the key length of a sized object)
  • single_include/nlohmann/json.hpp — regenerated via make amalgamate.

All of the above was verified against develop before writing the tests, and the full UBJSON test case passes locally (691 256 assertions).

Breaking changes to the public API

None. The change is a comment plus tests; parser behavior, signatures, and ABI are untouched.


This pull request was prepared by Claude Code.

@nlohmann nlohmann added this to the Release 3.13.0 milestone Aug 3, 2026
@nlohmann nlohmann added aspect: binary formats BSON, CBOR, MessagePack, UBJSON review needed It would be great if someone could review the proposed changes. labels Aug 3, 2026
The comment asked whether the no-op marker 'N' may be ignored when a
string is read. It may not: at that point the next byte must be a string
length type specification, and 'N' is not one. No-ops at positions where
a value may start are already consumed by the callers through
get_ignore_noop(), so nothing is lost by not skipping them here.

Replace the TODO with a comment stating that, and add regression tests
pinning both directions: a no-op is accepted at top level (also
repeated), before and after an array element, and before an object key,
between key and value, and before the closing brace of an object of
unknown size; it is rejected where a length type specification is
expected, i.e. after the 'S' marker of a string value and as the key
length of an object of known size.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
@nlohmann
nlohmann force-pushed the claude/todo-243-ubjson-noop-todo branch from 86b3d6c to 2b23d1b Compare August 4, 2026 06:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

aspect: binary formats BSON, CBOR, MessagePack, UBJSON M review needed It would be great if someone could review the proposed changes. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant