From acd87e2336d1ac745cbf8975edabb751314f3789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20B=C4=9Blohl=C3=A1vek?= Date: Tue, 4 Aug 2026 16:14:35 +0200 Subject: [PATCH 01/16] CI: Add clang 21&22 to Ubuntu CLang build matrix (#5347) * Add clang 21 to ubuntu build matrix (CI) Signed-off-by: Petr Belohlavek * Add clang 22 to ubuntu build matrix (CI) Signed-off-by: Petr Belohlavek * Register Clang 22.1.8 to quality_assurance.md Signed-off-by: Petr Belohlavek --------- Signed-off-by: Petr Belohlavek --- .github/workflows/ubuntu.yml | 2 +- docs/mkdocs/docs/community/quality_assurance.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 798885a8c..1d7396bf8 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -212,7 +212,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', 'latest'] + compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', '21', '22', 'latest'] container: silkeh/clang:${{ matrix.compiler }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/docs/mkdocs/docs/community/quality_assurance.md b/docs/mkdocs/docs/community/quality_assurance.md index 200a129ef..4196f3532 100644 --- a/docs/mkdocs/docs/community/quality_assurance.md +++ b/docs/mkdocs/docs/community/quality_assurance.md @@ -66,6 +66,7 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa | Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub | | Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | + | Clang 22.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub | | CUDA 11.8.0 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub | | CUDA 12.1.1 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub | | CUDA 12.6.3 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub | From dca9d49a335b6b13b6de70559dbcd3dc148add54 Mon Sep 17 00:00:00 2001 From: Angadi56 Date: Wed, 5 Aug 2026 17:13:36 +0530 Subject: [PATCH 02/16] reject out-of-range code points in UTF-32 wide-string input (#5348) * reject out-of-range code points in UTF-32 wide-string input Signed-off-by: Angadi Yashaswini * remove useless cast to char_traits::int_type Signed-off-by: Angadi Yashaswini --------- Signed-off-by: Angadi Yashaswini --- include/nlohmann/detail/input/input_adapters.hpp | 8 ++++++-- single_include/nlohmann/json.hpp | 8 ++++++-- tests/src/unit-wstring.cpp | 10 ++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 2c3561cbc..ba8df07a6 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -345,8 +345,12 @@ struct wide_string_input_helper } else { - // unknown character - utf8_bytes[0] = static_cast::int_type>(wc); + // A code point above U+10FFFF has no UTF-8 encoding. Passing the + // unit through would narrow it to int, where 0xFFFFFFFF becomes + // char_traits::eof() and would end the input silently, so + // emit a byte that is never valid UTF-8 and let the decoder + // reject it. + utf8_bytes[0] = 0xFF; utf8_bytes_filled = 1; } } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 958ac5fc9..a42a22d23 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -7348,8 +7348,12 @@ struct wide_string_input_helper } else { - // unknown character - utf8_bytes[0] = static_cast::int_type>(wc); + // A code point above U+10FFFF has no UTF-8 encoding. Passing the + // unit through would narrow it to int, where 0xFFFFFFFF becomes + // char_traits::eof() and would end the input silently, so + // emit a byte that is never valid UTF-8 and let the decoder + // reject it. + utf8_bytes[0] = 0xFF; utf8_bytes_filled = 1; } } diff --git a/tests/src/unit-wstring.cpp b/tests/src/unit-wstring.cpp index ffbe70e7e..a38df3aaa 100644 --- a/tests/src/unit-wstring.cpp +++ b/tests/src/unit-wstring.cpp @@ -125,6 +125,16 @@ TEST_CASE("wide strings") std::u32string const w = U"\"\x110000"; json _; CHECK_THROWS_AS(_ = json::parse(w), json::parse_error&); + + // a code unit above U+10FFFF must not be narrowed onto the EOF + // sentinel: 0xFFFFFFFF would otherwise end the document silently and + // let everything following it pass the strict end-of-input check + std::u32string const trailing{U'[', U'1', U']', static_cast(0xFFFFFFFF), U'x'}; + CHECK_THROWS_WITH_AS(_ = json::parse(trailing), "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '1]\xFF'; expected end of input", json::parse_error&); + CHECK(!json::accept(trailing)); + + // the same unit inside a string is reported as an ill-formed byte + CHECK_THROWS_WITH_AS(_ = json::parse(std::u32string{U'"', static_cast(0xFFFFFFFF), U'"'}), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\xFF'", json::parse_error&); } } } From b890b4cba3c3b7e0a5a454b5160721361d11fec3 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 5 Aug 2026 13:44:05 +0200 Subject: [PATCH 03/16] CI: build the MinGW Clang matrix without debug info (#5360) Linking test-regression2_cpp20 intermittently fails with unit-regression2.cpp.obj:(.debug_info+0x16): relocation truncated to fit: IMAGE_REL_AMD64_SECREL against `.debug_line' The failure moves between matrix entries from run to run, and the same commit can pass and fail on consecutive runs, so it is the size of the debug sections rather than any one Clang version. The jobs only build and run the tests, so override CMAKE_CXX_FLAGS_DEBUG to drop the default -g. Everything else about the Debug build is unchanged: no optimization flag is added and NDEBUG stays undefined, so JSON_ASSERT remains active. Signed-off-by: Niels Lohmann --- .github/workflows/windows.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b7c640ce8..ff3089b1d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -153,10 +153,16 @@ jobs: with: platform: x64 version: 12.2.0 # https://github.com/egor-tensin/setup-mingw/issues/14 + # CMAKE_CXX_FLAGS_DEBUG is overridden to drop the default -g: linking + # test-regression2_cpp20 intermittently fails with "relocation truncated + # to fit: IMAGE_REL_AMD64_SECREL against `.debug_line'" because the + # MinGW linker cannot relocate the debug sections this test produces. + # The tests are only built and run here, so the debug info is not used. - name: Run CMake run: cmake -S . -B build ^ -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" ^ -DCMAKE_CXX_FLAGS="--target=x86_64-w64-mingw32 -stdlib=libstdc++ -pthread" ^ + -DCMAKE_CXX_FLAGS_DEBUG="-g0" ^ -DCMAKE_EXE_LINKER_FLAGS="-lwinpthread" ^ -G"MinGW Makefiles" ^ -DCMAKE_BUILD_TYPE=Debug ^ From 9a091d2b8290a7e5f631dfb9b34c35b7ab777d22 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 5 Aug 2026 13:44:15 +0200 Subject: [PATCH 04/16] Do not write BJData ndarrays whose size overflows std::size_t (#5362) * Do not write BJData ndarrays whose size overflows std::size_t write_bjdata_ndarray() multiplied the _ArraySize_ dimensions into a std::size_t without checking for overflow. A product that wraps around to a value that happens to match the size of _ArrayData_ passed the length check, and the writer emitted an ndarray header announcing an element count that cannot be represented: {"_ArrayType_":"uint8","_ArraySize_":[9223372036854775808,2],"_ArrayData_":[]} was encoded as 5b 24 55 23 5b 4d 00 00 00 00 00 00 00 80 69 02 5d, an ndarray of 2^64 elements followed by no data. Reading that back throws out_of_range.408 ("excessive ndarray size caused overflow"), so to_bjdata produced output that from_bjdata rejects. This is reachable by parsing untrusted JSON and re-encoding it as BJData. Mirror the overflow check the binary reader already performs, and also reject a single dimension that does not fit into std::size_t, which the previous cast silently truncated where std::size_t is narrower than 64 bits. Such objects now fall back to a plain object encoding, which is what the surrounding type and length validation already does for annotations it cannot represent, and they round-trip unchanged. Signed-off-by: Niels Lohmann * Document when to_bjdata converts a JData annotation to an ND-array The BJData page described the 1-D vector case as the only situation in which an object carrying _ArrayType_/_ArraySize_/_ArrayData_ is not written as a compact ND-array. The writer has always had several other fallbacks -- an unknown _ArrayType_, a dimension that is not a non-negative integer, an _ArrayData_ whose length does not match the product of the dimensions, and elements that are not numbers of the annotated kind -- all of which cause the value to be serialized as a regular JSON object instead. Spell out the conditions, including the size-overflow check added in the preceding commit, so the documented behavior matches the implementation. Signed-off-by: Niels Lohmann --------- Signed-off-by: Niels Lohmann --- .../docs/features/binary_formats/bjdata.md | 16 +++++++++++--- .../nlohmann/detail/output/binary_writer.hpp | 18 +++++++++++++++- single_include/nlohmann/json.hpp | 18 +++++++++++++++- tests/src/unit-bjdata.cpp | 21 +++++++++++++++++++ 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/docs/mkdocs/docs/features/binary_formats/bjdata.md b/docs/mkdocs/docs/features/binary_formats/bjdata.md index b1b98dfe2..faff64f16 100644 --- a/docs/mkdocs/docs/features/binary_formats/bjdata.md +++ b/docs/mkdocs/docs/features/binary_formats/bjdata.md @@ -116,9 +116,19 @@ The library uses the following mapping from JSON values types to BJData types ac ``` Likewise, when a JSON object in the above form is serialized using - [`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array. The - only exception is, that when the 1-dimensional vector stored in `"_ArraySize_"` contains a single integer or two - integers with one being 1, a regular 1-D optimized array is generated. + [`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array. When + the 1-dimensional vector stored in `"_ArraySize_"` contains a single integer or two integers with one being 1, a + regular 1-D optimized array is generated instead. + + An object is only converted if the annotation actually describes a packed array; otherwise it is serialized as a + regular JSON object. This requires all of the following: + + - `"_ArrayType_"` is one of `uint8`, `int8`, `uint16`, `int16`, `uint32`, `int32`, `uint64`, `int64`, `single`, + `double`, `char`, or `byte`, + - every entry of `"_ArraySize_"` is a non-negative integer, and their product is representable as a `std::size_t`, + - `"_ArrayData_"` holds exactly that many elements, and + - every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"` (a floating-point number for + `single` and `double`, an integer otherwise). The current version of this library does not yet support automatic detection of and conversion from a nested JSON array input to a BJData ND-array. diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 9a8b53df7..35b5efa8a 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -1670,7 +1670,23 @@ class binary_writer { return true; } - len *= static_cast(el.template get()); + + // a dimension that does not fit into std::size_t, or a product that + // overflows it, would wrap around and could match the size of + // _ArrayData_ by accident; the resulting header announces an + // element count that no reader can honor (the binary reader rejects + // it with out_of_range.408), so encode as a plain object instead + const auto dim = el.template get(); + if (!value_in_range_of(dim)) + { + return true; + } + const auto dim_size = static_cast(dim); + if (dim_size != 0 && len > (std::numeric_limits::max)() / dim_size) + { + return true; + } + len *= dim_size; } key = "_ArrayData_"; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index a42a22d23..cca1b3666 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -18577,7 +18577,23 @@ class binary_writer { return true; } - len *= static_cast(el.template get()); + + // a dimension that does not fit into std::size_t, or a product that + // overflows it, would wrap around and could match the size of + // _ArrayData_ by accident; the resulting header announces an + // element count that no reader can honor (the binary reader rejects + // it with out_of_range.408), so encode as a plain object instead + const auto dim = el.template get(); + if (!value_in_range_of(dim)) + { + return true; + } + const auto dim_size = static_cast(dim); + if (dim_size != 0 && len > (std::numeric_limits::max)() / dim_size) + { + return true; + } + len *= dim_size; } key = "_ArrayData_"; diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index d00e1fa67..d5f9c3acd 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -2730,6 +2730,27 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(json::to_bjdata(j_type), true, true) == j_type); CHECK(json::from_bjdata(json::to_bjdata(j_size), true, true) == j_size); } + + SECTION("ndarray whose dimensions overflow stays as object") + { + // the product of the dimensions wraps around std::size_t to 0 + // and so matches the size of the empty _ArrayData_; writing this + // as an ndarray would announce an element count no reader can + // honor, so it has to stay a plain object + json j_overflow = json({{"_ArrayData_", json::array()}, {"_ArraySize_", {9223372036854775808ull, 2}}, {"_ArrayType_", "uint8"}}); + CHECK(json::from_bjdata(json::to_bjdata(j_overflow), true, true) == j_overflow); + + // a single dimension that does not fit into std::size_t is + // rejected for the same reason (only observable where + // std::size_t is narrower than 64 bit) + json j_huge = json({{"_ArrayData_", json::array()}, {"_ArraySize_", {18446744073709551615ull}}, {"_ArrayType_", "uint8"}}); + CHECK(json::from_bjdata(json::to_bjdata(j_huge), true, true) == j_huge); + + // a well-formed ndarray is still encoded as one + json j_ok = json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "uint8"}}); + CHECK(json::to_bjdata(j_ok) == std::vector({'[', '$', 'U', '#', '[', 'i', 2, 'i', 3, ']', 1, 2, 3, 4, 5, 6})); + CHECK(json::from_bjdata(json::to_bjdata(j_ok), true, true) == j_ok); + } } } From d5647e6a3be71adbcaac444f8cd1acae109c4046 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 5 Aug 2026 14:47:40 +0200 Subject: [PATCH 05/16] Resolve the TODO(niels) in get_ubjson_string (#5355) 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 --- .../nlohmann/detail/input/binary_reader.hpp | 6 ++- single_include/nlohmann/json.hpp | 6 ++- tests/src/unit-ubjson.cpp | 38 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 397683744..f5d209b88 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -1988,7 +1988,11 @@ class binary_reader { if (get_char) { - get(); // TODO(niels): may we ignore N here? + // no get_ignore_noop() here: the byte read next must be a string + // length type specification, and a no-op ('N') is not valid in + // that position. No-ops at positions where a value may appear are + // already consumed by the callers via get_ignore_noop(). + get(); } if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index cca1b3666..c1b178038 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -12586,7 +12586,11 @@ class binary_reader { if (get_char) { - get(); // TODO(niels): may we ignore N here? + // no get_ignore_noop() here: the byte read next must be a string + // length type specification, and a no-op ('N') is not valid in + // that position. No-ops at positions where a value may appear are + // already consumed by the callers via get_ignore_noop(). + get(); } if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) diff --git a/tests/src/unit-ubjson.cpp b/tests/src/unit-ubjson.cpp index d5668833d..e1e327563 100644 --- a/tests/src/unit-ubjson.cpp +++ b/tests/src/unit-ubjson.cpp @@ -1713,6 +1713,44 @@ TEST_CASE("UBJSON") CHECK(json::to_ubjson(json::from_ubjson(s_L)) == s_i); } + SECTION("no-op markers") + { + // A no-op ('N') is valid wherever a value may start; it is consumed + // by get_ignore_noop() before the value is read. It is not valid + // where a string length type specification is expected. + + SECTION("accepted where a value may start") + { + // at top level, also repeated + CHECK(json::from_ubjson(std::vector({'N', 'i', 1})) == json(1)); + CHECK(json::from_ubjson(std::vector({'N', 'N', 'N', 'i', 1})) == json(1)); + + // inside an array of unknown size, before and after an element + CHECK(json::from_ubjson(std::vector({'[', 'N', 'i', 1, ']'})) == json({1})); + CHECK(json::from_ubjson(std::vector({'[', 'i', 1, 'N', ']'})) == json({1})); + + // inside an object of unknown size: before a key, between key + // and value, and before the closing '}' + CHECK(json::from_ubjson(std::vector({'{', 'N', 'U', 1, 'a', 'i', 1, '}'})) == json({{"a", 1}})); + CHECK(json::from_ubjson(std::vector({'{', 'U', 1, 'a', 'N', 'i', 1, '}'})) == json({{"a", 1}})); + CHECK(json::from_ubjson(std::vector({'{', 'U', 1, 'a', 'i', 1, 'N', '}'})) == json({{"a", 1}})); + } + + SECTION("rejected where a length type specification is expected") + { + json _; + + // after the 'S' marker of a string value + std::vector const v_S = {'S', 'N', 'U', 1, 'a'}; + CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v_S), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x4E", json::parse_error&); + + // as the key length of an object with a known size, where + // no-ops are not permitted in the first place + std::vector const v_key = {'{', '#', 'i', 1, 'N', 'U', 1, 'a', 'i', 1}; + CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v_key), "[json.exception.parse_error.113] parse error at byte 5: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x4E", json::parse_error&); + } + } + SECTION("number") { SECTION("float") From bacdabd176955be6b5157b7e26075ba9965584b2 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 5 Aug 2026 16:01:23 +0200 Subject: [PATCH 06/16] Fix start_pos() for strings containing escape sequences (#5361) The diagnostic position of a string value was derived by subtracting the parsed value's length from the end position. Escape sequences make the source token longer than the value it parses to, so the reported start position landed inside the string, one byte off per escape sequence: input: {"a":"\n\n\n\n\n\n"} start_pos() == 11, so the reported range covered n\n\n\n" instead of the documented "\n\n\n\n\n\n" This contradicts the documented behavior of start_pos(), which is the position of the opening quote, and it also corrupted the "(bytes N-M)" part of JSON_DIAGNOSTICS exception messages. Strings with multi-byte UTF-8 but no escapes were unaffected, which is why this went unnoticed. Record the offset of the token in the lexer when it starts scanning and use that, instead of reconstructing it from the parsed value. Booleans, null and numbers already reported correct positions and are unchanged. The new lexer member and accessor are compiled only when JSON_DIAGNOSTIC_POSITIONS is enabled, which is already part of the ABI tag, so the default build is unaffected. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/input/json_sax.hpp | 12 +++++--- include/nlohmann/detail/input/lexer.hpp | 20 ++++++++++++++ single_include/nlohmann/json.hpp | 32 +++++++++++++++++++--- tests/src/unit-diagnostic-positions.cpp | 30 ++++++++++++++++++++ 4 files changed, 86 insertions(+), 8 deletions(-) diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 4c5f24a7b..8a98ee728 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -370,8 +370,10 @@ class json_sax_dom_parser case value_t::string: { - // include the length of the quotes, which is 2 - v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + // escape sequences make the token longer than the value it + // parses to, so the start position cannot be derived from + // the value; use the offset the lexer recorded instead + v.start_position = m_lexer_ref->get_token_start_position(); break; } @@ -769,8 +771,10 @@ class json_sax_dom_callback_parser case value_t::string: { - // include the length of the quotes, which is 2 - v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + // escape sequences make the token longer than the value it + // parses to, so the start position cannot be derived from + // the value; use the offset the lexer recorded instead + v.start_position = m_lexer_ref->get_token_start_position(); break; } diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 6318994e6..641d93fa4 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -1357,6 +1357,11 @@ scan_number_done: token_buffer.clear(); decimal_point_position = std::string::npos; +#if JSON_DIAGNOSTIC_POSITIONS + // the first character of the token has already been read, hence the -1 + token_start_position = position.chars_read_total - 1; +#endif + note_token_start(std::integral_constant {}); } @@ -1519,6 +1524,15 @@ scan_number_done: return position; } +#if JSON_DIAGNOSTIC_POSITIONS + /// return the offset of the first character of the last read token; unlike + /// the token's parsed value, this accounts for escape sequences + constexpr std::size_t get_token_start_position() const noexcept + { + return token_start_position; + } +#endif + /// seekable adapter: rebuild the last read token from the input on demand const std::vector& collect_token_chars(std::vector& out, std::true_type /*lazy*/) const { @@ -1719,6 +1733,12 @@ scan_number_done: /// the last read token on error for seekable adapters (see collect_token_chars) std::size_t token_string_start = 0; +#if JSON_DIAGNOSTIC_POSITIONS + /// start offset of the current token within the input, used to report + /// diagnostic positions (see reset()) + std::size_t token_start_position = 0; +#endif + /// buffer for variable-length tokens (numbers, strings) string_t token_buffer {}; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index c1b178038..fa6199da1 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -9075,6 +9075,11 @@ scan_number_done: token_buffer.clear(); decimal_point_position = std::string::npos; +#if JSON_DIAGNOSTIC_POSITIONS + // the first character of the token has already been read, hence the -1 + token_start_position = position.chars_read_total - 1; +#endif + note_token_start(std::integral_constant {}); } @@ -9237,6 +9242,15 @@ scan_number_done: return position; } +#if JSON_DIAGNOSTIC_POSITIONS + /// return the offset of the first character of the last read token; unlike + /// the token's parsed value, this accounts for escape sequences + constexpr std::size_t get_token_start_position() const noexcept + { + return token_start_position; + } +#endif + /// seekable adapter: rebuild the last read token from the input on demand const std::vector& collect_token_chars(std::vector& out, std::true_type /*lazy*/) const { @@ -9437,6 +9451,12 @@ scan_number_done: /// the last read token on error for seekable adapters (see collect_token_chars) std::size_t token_string_start = 0; +#if JSON_DIAGNOSTIC_POSITIONS + /// start offset of the current token within the input, used to report + /// diagnostic positions (see reset()) + std::size_t token_start_position = 0; +#endif + /// buffer for variable-length tokens (numbers, strings) string_t token_buffer {}; @@ -9813,8 +9833,10 @@ class json_sax_dom_parser case value_t::string: { - // include the length of the quotes, which is 2 - v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + // escape sequences make the token longer than the value it + // parses to, so the start position cannot be derived from + // the value; use the offset the lexer recorded instead + v.start_position = m_lexer_ref->get_token_start_position(); break; } @@ -10212,8 +10234,10 @@ class json_sax_dom_callback_parser case value_t::string: { - // include the length of the quotes, which is 2 - v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + // escape sequences make the token longer than the value it + // parses to, so the start position cannot be derived from + // the value; use the offset the lexer recorded instead + v.start_position = m_lexer_ref->get_token_start_position(); break; } diff --git a/tests/src/unit-diagnostic-positions.cpp b/tests/src/unit-diagnostic-positions.cpp index 59c21dc59..ad9527540 100644 --- a/tests/src/unit-diagnostic-positions.cpp +++ b/tests/src/unit-diagnostic-positions.cpp @@ -38,6 +38,36 @@ TEST_CASE("Better diagnostics with positions") "[json.exception.type_error.302] type must be number, but is string", json::type_error); } + SECTION("positions of strings containing escape sequences") + { + // escape sequences make the token longer than the string it parses to, + // so the positions must not be derived from the parsed value's length + const auto check = [](const std::string & text, const std::string & token) + { + CAPTURE(text) + CAPTURE(token) + const json j = json::parse(text); + const json& v = j.at("a"); + CHECK(text.substr(v.start_pos(), v.end_pos() - v.start_pos()) == token); + }; + + check(R"({"a":"plain"})", R"("plain")"); + check(R"({"a":"tab\there"})", R"("tab\there")"); + check(R"({"a":"\n\n\n\n\n\n"})", R"("\n\n\n\n\n\n")"); + check(R"({"a":"\""})", R"("\"")"); + check(R"({"a":"\\"})", R"("\\")"); + check(R"({"a":"é"})", R"("é")"); + check(R"({"a":"🌞"})", R"("🌞")"); + check("{\"a\":\"\xc3\xa9\"}", "\"\xc3\xa9\""); // multi-byte UTF-8, no escapes + + // a string at the root, where an escape would otherwise push the + // reported start position past the opening quote + const std::string root = R"("a\tb")"; + const json j = json::parse(root); + CHECK(j.start_pos() == 0); + CHECK(j.end_pos() == root.size()); + } + SECTION("JSON patch add to primitive parent (#4292)") { // the JSON Patch "add" target /foo/bar/baz has a string parent From c1c19a7bcd4cd04c59696a352f4e8a6cfe4105fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 08:30:00 +0200 Subject: [PATCH 07/16] :arrow_up: Bump lukka/get-cmake from 4.4.0 to 4.4.1 (#5364) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.4.0 to 4.4.1. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3...4a7d025fc60f00db0c7b44ebf783d19b52444830) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.4.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ubuntu.yml | 32 ++++++++++++++++---------------- .github/workflows/windows.yml | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 1d7396bf8..7cfbffffa 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -25,7 +25,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -47,7 +47,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -70,7 +70,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -89,7 +89,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -108,7 +108,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -184,7 +184,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: CXX=g++-${{ matrix.compiler }} cmake -S . -B build -DJSON_CI=On - name: Build @@ -202,7 +202,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -219,7 +219,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Set env FORCE_STDCPPFS_FLAG for clang 7 / 8 / 9 / 10 run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV" if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }} @@ -239,7 +239,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -259,7 +259,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build with libc++ @@ -286,7 +286,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -306,7 +306,7 @@ jobs: # import-std support. Its opt-in token is CMake-version-specific, so pin # CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt. - name: Get pinned CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 with: cmakeVersion: 4.3.4 # Clang: the std library module is provided by libc++ (the image's libstdc++ @@ -332,7 +332,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -347,7 +347,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -359,7 +359,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -379,7 +379,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Run CMake run: cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -GNinja - name: Build diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ff3089b1d..01092bdd4 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -88,7 +88,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Get latest CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 - name: Set extra CXX_FLAGS for latest std_version # /wd5285 silences C5285 emitted by the bundled third-party doctest.h, which # specializes std::tuple (newly diagnosed by the VS2026 v145 toolset) @@ -199,7 +199,7 @@ jobs: # import-std support. Its opt-in token is CMake-version-specific, so pin # CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt. - name: Get pinned CMake and ninja - uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0 + uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 with: cmakeVersion: 4.3.4 - name: Run CMake (Debug) From 1c136a66c4f5b826d82cd5dbb1161c466d943b3e Mon Sep 17 00:00:00 2001 From: Dmitry <45711841+darkdi@users.noreply.github.com> Date: Thu, 6 Aug 2026 09:30:15 +0300 Subject: [PATCH 08/16] Move the CBOR doc block to the function it describes (#5363) The block documenting get_char and tag_handler sat above get_cbor_negative_integer(), which takes neither, so Doxygen attached it there and parse_cbor_internal() was left undocumented. Comment placement only. Signed-off-by: Dmitry <45711841+darkdi@users.noreply.github.com> --- include/nlohmann/detail/input/binary_reader.hpp | 17 ++++++++--------- single_include/nlohmann/json.hpp | 17 ++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index f5d209b88..e3574d778 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -465,15 +465,6 @@ class binary_reader // CBOR // ////////// - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true) or whether the last read character should - be considered instead (false) - @param[in] tag_handler how CBOR tags should be treated - - @return whether a valid CBOR value was passed to the SAX parser - */ - template bool get_cbor_negative_integer() { @@ -492,6 +483,14 @@ class binary_reader return sax->number_integer(static_cast(-1) - static_cast(number)); } + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated + + @return whether a valid CBOR value was passed to the SAX parser + */ bool parse_cbor_internal(const bool get_char, const cbor_tag_handler_t tag_handler) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index fa6199da1..724865e11 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11087,15 +11087,6 @@ class binary_reader // CBOR // ////////// - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true) or whether the last read character should - be considered instead (false) - @param[in] tag_handler how CBOR tags should be treated - - @return whether a valid CBOR value was passed to the SAX parser - */ - template bool get_cbor_negative_integer() { @@ -11114,6 +11105,14 @@ class binary_reader return sax->number_integer(static_cast(-1) - static_cast(number)); } + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated + + @return whether a valid CBOR value was passed to the SAX parser + */ bool parse_cbor_internal(const bool get_char, const cbor_tag_handler_t tag_handler) { From 23518f54fec80cdc8ab603a24b14a65232bdfcda Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 7 Aug 2026 19:29:58 +0200 Subject: [PATCH 09/16] Add an Ecosystem page for third-party projects built on nlohmann::json (#5369) --- README.md | 6 ++++ docs/mkdocs/docs/community/ecosystem.md | 40 +++++++++++++++++++++++++ docs/mkdocs/docs/community/index.md | 1 + docs/mkdocs/mkdocs.yml | 1 + 4 files changed, 48 insertions(+) create mode 100644 docs/mkdocs/docs/community/ecosystem.md diff --git a/README.md b/README.md index d4d2394a2..4b4236bb6 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ - [Specializing enum conversion](#specializing-enum-conversion) - [Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData)](#binary-formats-bson-cbor-messagepack-ubjson-and-bjdata) - [Customers](#customers) +- [Ecosystem](#ecosystem) - [Supported compilers](#supported-compilers) - [Integration](#integration) - [CMake](#cmake) @@ -1186,6 +1187,11 @@ The library is used in multiple projects, applications, operating systems, etc. [![logos of customers using the library](docs/mkdocs/docs/images/customers.png)](https://json.nlohmann.me/home/customers/) +## Ecosystem + +Beyond projects that use the library, there are third-party projects that build on top of it - schema validators, +language bindings, format converters, and the like. See the curated [Ecosystem](https://json.nlohmann.me/community/ecosystem/) page. + ## Supported compilers Though it's 2026 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: diff --git a/docs/mkdocs/docs/community/ecosystem.md b/docs/mkdocs/docs/community/ecosystem.md new file mode 100644 index 000000000..801111e7d --- /dev/null +++ b/docs/mkdocs/docs/community/ecosystem.md @@ -0,0 +1,40 @@ +# Ecosystem + +The projects below build on top of `nlohmann::json` rather than merely using it - schema validators, language +bindings, format converters, and similar building blocks. The list is not exhaustive, and is curated rather than +automatically generated. If you maintain or know of a project that belongs here, +[please let me know](mailto:mail@nlohmann.me). + +For products, applications, and organizations that use the library, see [Customers](../home/customers.md) instead. + +## Schema validation + +- [**json-schema-validator**](https://github.com/pboettch/json-schema-validator), a JSON Schema (draft 7) validator + with human-readable error messages + +## Serialization and reflection + +- [**nlohmann_json_reflect**](https://github.com/1261385937/nlohmann_json_reflect), a reflection extension for + (de)serializing nested containers-in-structs-in-containers + +## Encodings + +- [**base-encode-decode**](https://github.com/saxonnicholls/base-encode-decode), a header-only Base64/32/16/8/4/2 + (and DNA/RNA) encoding library, with an adapter that serializes binary data through `nlohmann::json` + +## Language bindings and interop + +- [**pybind11_json**](https://github.com/pybind/pybind11_json), a bidirectional type caster between + `nlohmann::json` and Python objects for [pybind11](https://github.com/pybind/pybind11) bindings +- [**nanobind_json**](https://github.com/ianhbell/nanobind_json), the same idea for + [nanobind](https://github.com/wjakob/nanobind) bindings +- [**nlohmann_json_qt**](https://github.com/dpurgin/nlohmann_json_qt), deserialization helpers for Qt types + (`QString`, `QUrl`, `QDateTime`, `QVector`, ...) from `nlohmann::json` +- [**vulkan2json**](https://github.com/Fadis/vulkan2json), serialization and deserialization of Vulkan API structs + +## Format converters + +- [**tojson**](https://github.com/mircodz/tojson), a header-only converter between YAML/XML documents and + `nlohmann::json` +- [**json2xml**](https://github.com/testillano/json2xml), a header-only converter from `nlohmann::json` to XML for + simple configuration documents diff --git a/docs/mkdocs/docs/community/index.md b/docs/mkdocs/docs/community/index.md index caef17be3..50baeab25 100644 --- a/docs/mkdocs/docs/community/index.md +++ b/docs/mkdocs/docs/community/index.md @@ -1,5 +1,6 @@ # Community +- [Ecosystem](ecosystem.md) - third-party projects built on top of this library - [Code of Conduct](code_of_conduct.md) - the rules and norms of this project - [Contribution Guidelines](contribution_guidelines.md) - guidelines how to contribute to this project - [Governance](governance.md) - the governance model of this project diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index fe786f7d5..2e1337f47 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -308,6 +308,7 @@ nav: - 'NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH': api/macros/nlohmann_json_version_major.md - Community: - community/index.md + - community/ecosystem.md - "Code of Conduct": community/code_of_conduct.md - community/contribution_guidelines.md - community/quality_assurance.md From 21af527e756435701f23e01aa8ea8dab6e050c90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 19:30:42 +0200 Subject: [PATCH 10/16] :arrow_up: Bump the codeql-action group with 4 updates (#5365) --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/flawfinder.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/semgrep.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index be556daad..d3c0ddaa8 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,14 +38,14 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 with: languages: c-cpp # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 diff --git a/.github/workflows/flawfinder.yml b/.github/workflows/flawfinder.yml index 18e172c62..da11b781e 100644 --- a/.github/workflows/flawfinder.yml +++ b/.github/workflows/flawfinder.yml @@ -43,6 +43,6 @@ jobs: output: 'flawfinder_results.sarif' - name: Upload analysis results to GitHub Security tab - uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 with: sarif_file: ${{github.workspace}}/flawfinder_results.sarif diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 728049618..cdccbf848 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -76,6 +76,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 with: sarif_file: results.sarif diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index 07ca19276..9b748a374 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -61,7 +61,7 @@ jobs: # Upload SARIF file generated in previous step - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 with: sarif_file: semgrep.sarif if: always() From 6285225fd068df42d043721f3bef65fca48c59fb Mon Sep 17 00:00:00 2001 From: ljcjclljc <169005916+ljcjclljc@users.noreply.github.com> Date: Wed, 12 Aug 2026 15:21:19 +0800 Subject: [PATCH 11/16] Fix integer comparison bug (#5211) * Fix integer comparison bug Signed-off-by: ljccjlljc <939159710@qq.com> * commit Signed-off-by: ljccjlljc <939159710@qq.com> * Remove generated CI artifacts and update amalgamation Signed-off-by: ljccjlljc <939159710@qq.com> * Silence cpplint braces warning in comparison macro Signed-off-by: ljccjlljc <939159710@qq.com> * Update amalgamation after cpplint fix Signed-off-by: ljccjlljc <939159710@qq.com> * Add mixed signed and unsigned comparison regression test Signed-off-by: ljccjlljc <939159710@qq.com> * Clarify mixed signed and unsigned comparison handling Signed-off-by: ljccjlljc <939159710@qq.com> * Expand mixed signed and unsigned comparison tests Signed-off-by: ljccjlljc <939159710@qq.com> --------- Signed-off-by: ljccjlljc <939159710@qq.com> --- include/nlohmann/json.hpp | 16 +++++-- single_include/nlohmann/json.hpp | 16 +++++-- tests/src/unit-comparison.cpp | 71 ++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 6 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index a460bb29f..235e6b737 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -3652,6 +3652,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // note parentheses around operands are necessary; see // https://github.com/nlohmann/json/issues/1530 + // Mixed signed/unsigned integer comparisons check whether the signed value + // is negative before casting. If it is, the comparison is performed with + // the fixed values -1 and 1, which preserves the ordering relationship + // because any negative signed value is smaller than any unsigned value. + // Otherwise, the non-negative signed value is cast to unsigned before the + // comparison to avoid wraparound. #define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \ const auto lhs_type = lhs.type(); \ const auto rhs_type = rhs.type(); \ @@ -3710,12 +3716,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } \ else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \ { \ - return static_cast(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \ + return (rhs.m_data.m_value.number_integer < 0) \ + ? (number_integer_t(1) op number_integer_t(-1)) \ + : (lhs.m_data.m_value.number_unsigned op static_cast(rhs.m_data.m_value.number_integer)); \ } \ else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \ { \ - return lhs.m_data.m_value.number_integer op static_cast(rhs.m_data.m_value.number_unsigned); \ - } \ + return (lhs.m_data.m_value.number_integer < 0) \ + ? (number_integer_t(-1) op number_integer_t(1)) \ + : (static_cast(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \ + } \ else if(compares_unordered(lhs, rhs))\ {\ return (unordered_result);\ diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 724865e11..fff350ee4 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -24988,6 +24988,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // note parentheses around operands are necessary; see // https://github.com/nlohmann/json/issues/1530 + // Mixed signed/unsigned integer comparisons check whether the signed value + // is negative before casting. If it is, the comparison is performed with + // the fixed values -1 and 1, which preserves the ordering relationship + // because any negative signed value is smaller than any unsigned value. + // Otherwise, the non-negative signed value is cast to unsigned before the + // comparison to avoid wraparound. #define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \ const auto lhs_type = lhs.type(); \ const auto rhs_type = rhs.type(); \ @@ -25046,12 +25052,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } \ else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \ { \ - return static_cast(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \ + return (rhs.m_data.m_value.number_integer < 0) \ + ? (number_integer_t(1) op number_integer_t(-1)) \ + : (lhs.m_data.m_value.number_unsigned op static_cast(rhs.m_data.m_value.number_integer)); \ } \ else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \ { \ - return lhs.m_data.m_value.number_integer op static_cast(rhs.m_data.m_value.number_unsigned); \ - } \ + return (lhs.m_data.m_value.number_integer < 0) \ + ? (number_integer_t(-1) op number_integer_t(1)) \ + : (static_cast(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \ + } \ else if(compares_unordered(lhs, rhs))\ {\ return (unordered_result);\ diff --git a/tests/src/unit-comparison.cpp b/tests/src/unit-comparison.cpp index d9df1a3a6..31fbdc57a 100644 --- a/tests/src/unit-comparison.cpp +++ b/tests/src/unit-comparison.cpp @@ -15,6 +15,8 @@ #include "doctest_compatibility.h" +#include + #define JSON_TESTS_PRIVATE #include using nlohmann::json; @@ -255,6 +257,75 @@ TEST_CASE("lexicographical comparison operators") {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21 }; + SECTION("signed/unsigned mixed comparison above INT64_MAX") + { + const json above_int64_max = static_cast((std::numeric_limits::max)()) + 1ULL; + const json max_uint64 = (std::numeric_limits::max)(); + const json negative_one = -1; + const json one = 1; + const json max_int64 = (std::numeric_limits::max)(); + + CHECK_FALSE(above_int64_max == negative_one); + CHECK(above_int64_max != negative_one); + CHECK(negative_one < above_int64_max); + CHECK(negative_one <= above_int64_max); + CHECK_FALSE(negative_one > above_int64_max); + CHECK_FALSE(negative_one >= above_int64_max); + CHECK_FALSE(above_int64_max < negative_one); + CHECK_FALSE(above_int64_max <= negative_one); + CHECK(above_int64_max > negative_one); + CHECK(above_int64_max >= negative_one); + CHECK(negative_one != above_int64_max); + CHECK_FALSE(negative_one == above_int64_max); + + CHECK_FALSE(max_uint64 == negative_one); + CHECK(max_uint64 != negative_one); + CHECK(negative_one < max_uint64); + CHECK(negative_one <= max_uint64); + CHECK_FALSE(negative_one > max_uint64); + CHECK_FALSE(negative_one >= max_uint64); + CHECK_FALSE(max_uint64 < negative_one); + CHECK_FALSE(max_uint64 <= negative_one); + CHECK(max_uint64 > negative_one); + CHECK(max_uint64 >= negative_one); + CHECK(negative_one != max_uint64); + CHECK_FALSE(negative_one == max_uint64); + + CHECK_FALSE(one == above_int64_max); + CHECK(one != above_int64_max); + CHECK(one < above_int64_max); + CHECK(one <= above_int64_max); + CHECK_FALSE(one > above_int64_max); + CHECK_FALSE(one >= above_int64_max); + CHECK_FALSE(above_int64_max < one); + CHECK_FALSE(above_int64_max <= one); + CHECK(above_int64_max > one); + CHECK(above_int64_max >= one); + + CHECK_FALSE(max_int64 == above_int64_max); + CHECK(max_int64 != above_int64_max); + CHECK(max_int64 < above_int64_max); + CHECK(max_int64 <= above_int64_max); + CHECK_FALSE(max_int64 > above_int64_max); + CHECK_FALSE(max_int64 >= above_int64_max); + CHECK_FALSE(above_int64_max < max_int64); + CHECK_FALSE(above_int64_max <= max_int64); + CHECK(above_int64_max > max_int64); + CHECK(above_int64_max >= max_int64); + +#if JSON_HAS_THREE_WAY_COMPARISON + // JSON_HAS_CPP_20 (do not remove; see note at top of file) + CHECK((negative_one <=> above_int64_max) == std::partial_ordering::less); // *NOPAD* + CHECK((above_int64_max <=> negative_one) == std::partial_ordering::greater); // *NOPAD* + CHECK((negative_one <=> max_uint64) == std::partial_ordering::less); // *NOPAD* + CHECK((max_uint64 <=> negative_one) == std::partial_ordering::greater); // *NOPAD* + CHECK((one <=> above_int64_max) == std::partial_ordering::less); // *NOPAD* + CHECK((above_int64_max <=> one) == std::partial_ordering::greater); // *NOPAD* + CHECK((max_int64 <=> above_int64_max) == std::partial_ordering::less); // *NOPAD* + CHECK((above_int64_max <=> max_int64) == std::partial_ordering::greater); // *NOPAD* +#endif + } + SECTION("compares unordered") { std::vector> expected = From e6978ba50c37ba611e76fa46096023882ec500e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 09:21:41 +0200 Subject: [PATCH 12/16] :arrow_up: Bump the codeql-action group with 4 updates (#5372) Bumps the codeql-action group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action). Updates `github/codeql-action/init` from 4.37.4 to 4.37.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43) Updates `github/codeql-action/autobuild` from 4.37.4 to 4.37.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43) Updates `github/codeql-action/analyze` from 4.37.4 to 4.37.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43) Updates `github/codeql-action/upload-sarif` from 4.37.4 to 4.37.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql-action - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql-action - dependency-name: github/codeql-action/analyze dependency-version: 4.37.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql-action - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql-action ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/flawfinder.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/semgrep.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d3c0ddaa8..251382eb4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,14 +38,14 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/init@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 with: languages: c-cpp # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/autobuild@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/analyze@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 diff --git a/.github/workflows/flawfinder.yml b/.github/workflows/flawfinder.yml index da11b781e..0f91aba3b 100644 --- a/.github/workflows/flawfinder.yml +++ b/.github/workflows/flawfinder.yml @@ -43,6 +43,6 @@ jobs: output: 'flawfinder_results.sarif' - name: Upload analysis results to GitHub Security tab - uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 with: sarif_file: ${{github.workspace}}/flawfinder_results.sarif diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index cdccbf848..c162dce73 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -76,6 +76,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 with: sarif_file: results.sarif diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index 9b748a374..f6a327271 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -61,7 +61,7 @@ jobs: # Upload SARIF file generated in previous step - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 with: sarif_file: semgrep.sarif if: always() From 146ba55453f4a694c2b82470edbfd7c293c6173b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 09:21:46 +0200 Subject: [PATCH 13/16] :arrow_up: Bump step-security/harden-runner from 2.20.0 to 2.20.1 (#5375) Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.20.0 to 2.20.1. - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](https://github.com/step-security/harden-runner/compare/bf7454d06d71f1098171f2acdf0cd4708d7b5920...b09bb98e06d4d774595224525879c09bc6e98c40) --- updated-dependencies: - dependency-name: step-security/harden-runner dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/check_amalgamation.yml | 4 ++-- .github/workflows/cifuzz.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/comment_check_amalgamation.yml | 2 +- .github/workflows/dependency-review.yml | 2 +- .github/workflows/flawfinder.yml | 2 +- .github/workflows/labeler.yml | 2 +- .github/workflows/publish_documentation.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/semgrep.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/ubuntu.yml | 10 +++++----- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/check_amalgamation.yml b/.github/workflows/check_amalgamation.yml index b3f2bb023..60a3f8240 100644 --- a/.github/workflows/check_amalgamation.yml +++ b/.github/workflows/check_amalgamation.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit @@ -34,7 +34,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index a14be2111..da3df626f 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 251382eb4..8c474323f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/comment_check_amalgamation.yml b/.github/workflows/comment_check_amalgamation.yml index 9dada803c..87e1b7b58 100644 --- a/.github/workflows/comment_check_amalgamation.yml +++ b/.github/workflows/comment_check_amalgamation.yml @@ -19,7 +19,7 @@ jobs: pull-requests: write steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 892e5d429..2c6300252 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/flawfinder.yml b/.github/workflows/flawfinder.yml index 0f91aba3b..c89e6d96b 100644 --- a/.github/workflows/flawfinder.yml +++ b/.github/workflows/flawfinder.yml @@ -27,7 +27,7 @@ jobs: security-events: write steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index c8382168f..2222b77f2 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/publish_documentation.yml b/.github/workflows/publish_documentation.yml index e717d15c3..d0066885e 100644 --- a/.github/workflows/publish_documentation.yml +++ b/.github/workflows/publish_documentation.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index c162dce73..283fc2a5c 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index f6a327271..eacfe30da 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 1dbf6a571..fd9cbb80f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 7cfbffffa..99e76991f 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit @@ -60,7 +60,7 @@ jobs: target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind] steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit @@ -118,7 +118,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit @@ -369,7 +369,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit @@ -392,7 +392,7 @@ jobs: target: [ci_test_examples, ci_test_build_documentation] steps: - name: Harden Runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 with: egress-policy: audit From cdf52ae9bef77a0844e02e42df6d2df83a55c4b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 21:18:24 +0200 Subject: [PATCH 14/16] :arrow_up: Bump lukka/get-cmake from 4.4.1 to 4.4.2 (#5373) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.4.1 to 4.4.2. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/4a7d025fc60f00db0c7b44ebf783d19b52444830...fffaaafeea488556c2c12dad60690008bc1caacb) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.4.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ubuntu.yml | 32 ++++++++++++++++---------------- .github/workflows/windows.yml | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 99e76991f..2ef56a80b 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -25,7 +25,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -47,7 +47,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -70,7 +70,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -89,7 +89,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -108,7 +108,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -184,7 +184,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: CXX=g++-${{ matrix.compiler }} cmake -S . -B build -DJSON_CI=On - name: Build @@ -202,7 +202,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -219,7 +219,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Set env FORCE_STDCPPFS_FLAG for clang 7 / 8 / 9 / 10 run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV" if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }} @@ -239,7 +239,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -259,7 +259,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build with libc++ @@ -286,7 +286,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -306,7 +306,7 @@ jobs: # import-std support. Its opt-in token is CMake-version-specific, so pin # CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt. - name: Get pinned CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 with: cmakeVersion: 4.3.4 # Clang: the std library module is provided by libc++ (the image's libstdc++ @@ -332,7 +332,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -347,7 +347,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -359,7 +359,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build @@ -379,7 +379,7 @@ jobs: with: persist-credentials: false - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Run CMake run: cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -GNinja - name: Build diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 01092bdd4..068c5a0f1 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -88,7 +88,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Get latest CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 - name: Set extra CXX_FLAGS for latest std_version # /wd5285 silences C5285 emitted by the bundled third-party doctest.h, which # specializes std::tuple (newly diagnosed by the VS2026 v145 toolset) @@ -199,7 +199,7 @@ jobs: # import-std support. Its opt-in token is CMake-version-specific, so pin # CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt. - name: Get pinned CMake and ninja - uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1 + uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2 with: cmakeVersion: 4.3.4 - name: Run CMake (Debug) From ce87157d4e9a84d158867fbb33eb5e335a2ef938 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:47:20 +0200 Subject: [PATCH 15/16] :arrow_up: Bump the codeql-action group across 1 directory with 4 updates (#5379) Bumps the codeql-action group with 4 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action). Updates `github/codeql-action/init` from 4.37.5 to 4.37.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3) Updates `github/codeql-action/autobuild` from 4.37.5 to 4.37.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3) Updates `github/codeql-action/analyze` from 4.37.5 to 4.37.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3) Updates `github/codeql-action/upload-sarif` from 4.37.5 to 4.37.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3) --- updated-dependencies: - dependency-name: github/codeql-action/analyze dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql-action - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql-action - dependency-name: github/codeql-action/init dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql-action - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql-action ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/flawfinder.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/semgrep.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8c474323f..c21a3cd24 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,14 +38,14 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 + uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: languages: c-cpp # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 + uses: github/codeql-action/autobuild@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 + uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 diff --git a/.github/workflows/flawfinder.yml b/.github/workflows/flawfinder.yml index c89e6d96b..5477195d8 100644 --- a/.github/workflows/flawfinder.yml +++ b/.github/workflows/flawfinder.yml @@ -43,6 +43,6 @@ jobs: output: 'flawfinder_results.sarif' - name: Upload analysis results to GitHub Security tab - uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 + uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: sarif_file: ${{github.workspace}}/flawfinder_results.sarif diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 283fc2a5c..63ca0b90d 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -76,6 +76,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 + uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: sarif_file: results.sarif diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index eacfe30da..812e4a0d7 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -61,7 +61,7 @@ jobs: # Upload SARIF file generated in previous step - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 + uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: sarif_file: semgrep.sarif if: always() From b5378e8debf203dd2d0b3af1d6d0afe3e533fd2a Mon Sep 17 00:00:00 2001 From: Sahil_Kamate Date: Wed, 19 Aug 2026 23:49:47 +0530 Subject: [PATCH 16/16] Fix CBOR tag handlers not recognizing tags 0-5 and 21-23 (#5331) * Fix CBOR tag handlers not recognizing tags 0-5 and 21-23 The tagged-item switch in binary_reader::parse_cbor_internal() only handled head bytes 0xC6-0xD4 and 0xD8-0xDB. Bytes 0xC0-0xC5 (tags 0-5: date/time, epoch, bignum, decimal, bigfloat) and 0xD5-0xD7 (tags 21-23: base64url, base64, base16 conversion hints) fell through to the default case and were reported as invalid bytes, even under cbor_tag_handler_t::ignore and ::store, despite being valid CBOR major-type-6 tags per RFC 8949. Add the missing case labels so the full 0xC0-0xDB range is handled uniformly. Extend the "Tagged values" test in unit-cbor.cpp to cover 0xC0-0xD7, and update the CBOR docs to state the corrected tag range. Fixes #5315 Signed-off-by: sahilkamate03 <45514385+sahilkamate03@users.noreply.github.com> * Fix stale CBOR tag docs and add store-mode binary-payload test The "Incomplete mapping" warning still listed tags 0-5 (date/time, bignum, decimal fraction, bigfloat) and 21-23 (expected conversions) as unsupported, even though they now parse correctly under cbor_tag_handler_t::ignore/store, same as 0xC6..0xD4/0xD8..0xDB. Remove those five bullets and cross-reference the "Tagged items" warning below, matching the equivalent docs fix landed independently in PR #5367. Also add a cbor_tag_handler_t::store test that wraps a binary payload (not just a string) for every byte in 0xC0..0xD7, confirming these tags are unwrapped the same way as 0xC6..0xD4 rather than mistaken for the 0xD8..0xDB binary-subtype marker syntax, per review feedback on #5331. Signed-off-by: sahilkamate03 <45514385+sahilkamate03@users.noreply.github.com> --------- Signed-off-by: sahilkamate03 <45514385+sahilkamate03@users.noreply.github.com> --- docs/mkdocs/docs/features/binary_formats/cbor.md | 9 +++------ include/nlohmann/detail/input/binary_reader.hpp | 11 ++++++++++- single_include/nlohmann/json.hpp | 11 ++++++++++- tests/src/unit-cbor.cpp | 15 +++++++++++++-- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/docs/mkdocs/docs/features/binary_formats/cbor.md b/docs/mkdocs/docs/features/binary_formats/cbor.md index 5952bce39..670a23455 100644 --- a/docs/mkdocs/docs/features/binary_formats/cbor.md +++ b/docs/mkdocs/docs/features/binary_formats/cbor.md @@ -160,14 +160,11 @@ The library maps CBOR types to JSON value types as follows: The mapping is **incomplete** in the sense that not all CBOR types can be converted to a JSON value. The following CBOR types are not supported and will yield parse errors: - - date/time (0xC0..0xC1) - - bignum (0xC2..0xC3) - - decimal fraction (0xC4) - - bigfloat (0xC5) - - expected conversions (0xD5..0xD7) - simple values (0xE0..0xF3, 0xF8) - undefined (0xF7) + Tagged items (0xC0..0xDB) are not interpreted either; see the note on tagged items below. + !!! warning "Negative integer overflow" CBOR negative integers (major type 1) are decoded as `-1 - n`. If the encoded magnitude `n` is too large for the @@ -181,7 +178,7 @@ The library maps CBOR types to JSON value types as follows: !!! warning "Tagged items" - Tagged items will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`. They can be stored by passing `cbor_tag_handler_t::store` to function `from_cbor`. + Tagged items (0xC0..0xDB) will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`, in which case the tag is skipped and the enclosed data item is parsed on its own. They can be stored by passing `cbor_tag_handler_t::store` to function `from_cbor`. Note that no tag is ever interpreted: for instance, a text string tagged with tag 0 (date/time) stays a string. ??? example diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index e3574d778..557d7669c 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -773,7 +773,13 @@ class binary_reader case 0xBF: // map (indefinite length) return get_cbor_object(detail::unknown_size(), tag_handler); - case 0xC6: // tagged item + case 0xC0: // tagged item + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: case 0xC7: case 0xC8: case 0xC9: @@ -788,6 +794,9 @@ class binary_reader case 0xD2: case 0xD3: case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: case 0xD8: // tagged item (1 byte follows) case 0xD9: // tagged item (2 bytes follow) case 0xDA: // tagged item (4 bytes follow) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index fff350ee4..0ea563fb9 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11395,7 +11395,13 @@ class binary_reader case 0xBF: // map (indefinite length) return get_cbor_object(detail::unknown_size(), tag_handler); - case 0xC6: // tagged item + case 0xC0: // tagged item + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: case 0xC7: case 0xC8: case 0xC9: @@ -11410,6 +11416,9 @@ class binary_reader case 0xD2: case 0xD3: case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: case 0xD8: // tagged item (1 byte follows) case 0xD9: // tagged item (2 bytes follow) case 0xDA: // tagged item (4 bytes follow) diff --git a/tests/src/unit-cbor.cpp b/tests/src/unit-cbor.cpp index 1b4b95dbf..2a6bd41d7 100644 --- a/tests/src/unit-cbor.cpp +++ b/tests/src/unit-cbor.cpp @@ -2565,11 +2565,16 @@ TEST_CASE("Tagged values") const json j = "s"; auto v = json::to_cbor(j); - SECTION("0xC6..0xD4") + const json j_bin_payload = json::binary(std::vector {0x01, 0x02, 0x03}); + auto v_bin_payload = json::to_cbor(j_bin_payload); + + SECTION("0xC0..0xD7") { for (const auto b : std::vector { - 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4 + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, + 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, + 0xD5, 0xD6, 0xD7 }) { CAPTURE(b); @@ -2589,6 +2594,12 @@ TEST_CASE("Tagged values") auto j_tagged_stored = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::store); CHECK(j_tagged_stored == j); + + auto v_binary_tagged = v_bin_payload; + v_binary_tagged.insert(v_binary_tagged.begin(), b); + auto j_binary_tagged_stored = json::from_cbor(v_binary_tagged, true, true, json::cbor_tag_handler_t::store); + CHECK(j_binary_tagged_stored == j_bin_payload); + CHECK(!j_binary_tagged_stored.get_binary().has_subtype()); } }