mirror of
https://github.com/nlohmann/json.git
synced 2026-07-25 11:54:55 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ea2d28ef9 | ||
|
|
ac6b505923 | ||
|
|
7374730aed | ||
|
|
ebb3abba41 |
@@ -15,14 +15,6 @@ guidance.
|
|||||||
|
|
||||||
For vulnerabilities in third-party dependencies or modules, please report them directly to the respective maintainers.
|
For vulnerabilities in third-party dependencies or modules, please report them directly to the respective maintainers.
|
||||||
|
|
||||||
## Unofficial packages
|
|
||||||
|
|
||||||
This project does not publish an official npm package. The npm package
|
|
||||||
[`nlohmann-json`](https://www.npmjs.com/package/nlohmann-json) (or similarly named packages) is not maintained or
|
|
||||||
endorsed by this project. See the
|
|
||||||
[package managers documentation](https://json.nlohmann.me/integration/package_managers/#npm) for supported
|
|
||||||
integration options.
|
|
||||||
|
|
||||||
## Additional Resources
|
## Additional Resources
|
||||||
|
|
||||||
- Explore security-related topics and contribute to tools and projects through
|
- Explore security-related topics and contribute to tools and projects through
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
|
uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||||
with:
|
with:
|
||||||
languages: c-cpp
|
languages: c-cpp
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# 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)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
|
uses: github/codeql-action/autobuild@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
|
uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||||
|
|||||||
@@ -43,6 +43,6 @@ jobs:
|
|||||||
output: 'flawfinder_results.sarif'
|
output: 'flawfinder_results.sarif'
|
||||||
|
|
||||||
- name: Upload analysis results to GitHub Security tab
|
- name: Upload analysis results to GitHub Security tab
|
||||||
uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
|
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||||
with:
|
with:
|
||||||
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
||||||
|
|||||||
@@ -76,6 +76,6 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
|
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
|
|
||||||
# Upload SARIF file generated in previous step
|
# Upload SARIF file generated in previous step
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
|
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
|
||||||
with:
|
with:
|
||||||
sarif_file: semgrep.sarif
|
sarif_file: semgrep.sarif
|
||||||
if: always()
|
if: always()
|
||||||
|
|||||||
@@ -930,12 +930,6 @@ If you are using [CocoaPods](https://cocoapods.org), you can use the library by
|
|||||||
to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues
|
to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues
|
||||||
[here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).
|
[here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).
|
||||||
|
|
||||||
## npm
|
|
||||||
|
|
||||||
This project does not publish an official [npm](https://www.npmjs.com) package. The npm package
|
|
||||||
[`nlohmann-json`](https://www.npmjs.com/package/nlohmann-json) (or similarly named packages) is not maintained or
|
|
||||||
endorsed by this project. Use one of the package managers listed above, or integrate the single header directly.
|
|
||||||
|
|
||||||
## ESP-IDF and PlatformIO
|
## ESP-IDF and PlatformIO
|
||||||
|
|
||||||
There is no official package published to the [ESP-IDF Component Registry](https://components.espressif.com) or the
|
There is no official package published to the [ESP-IDF Component Registry](https://components.espressif.com) or the
|
||||||
|
|||||||
@@ -163,39 +163,12 @@ class binary_reader
|
|||||||
// BSON //
|
// BSON //
|
||||||
//////////
|
//////////
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief Validate a BSON document's declared size against the bytes read.
|
|
||||||
|
|
||||||
A BSON document starts with an int32 that counts its own total length in
|
|
||||||
bytes, including that prefix and the trailing 0x00. The reader is driven
|
|
||||||
by the terminator rather than the declared length, so without this check a
|
|
||||||
nested document could declare a length that disagrees with where its
|
|
||||||
terminator actually falls and quietly hand the bytes in between to the
|
|
||||||
enclosing document. A well-formed document is at least 5 bytes (the prefix
|
|
||||||
plus the terminator); the equality also rejects those impossible sizes,
|
|
||||||
since at least 5 bytes are always consumed.
|
|
||||||
|
|
||||||
@param[in] document_start value of chars_read before the size prefix
|
|
||||||
@param[in] document_size the declared document size
|
|
||||||
@return whether the declared size matches the number of bytes read
|
|
||||||
*/
|
|
||||||
bool check_bson_document_size(const std::size_t document_start, const std::int32_t document_size)
|
|
||||||
{
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast<std::size_t>(document_size) != chars_read - document_start))
|
|
||||||
{
|
|
||||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
|
|
||||||
exception_message(input_format_t::bson, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"), nullptr));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief Reads in a BSON-object and passes it to the SAX-parser.
|
@brief Reads in a BSON-object and passes it to the SAX-parser.
|
||||||
@return whether a valid BSON-value was passed to the SAX parser
|
@return whether a valid BSON-value was passed to the SAX parser
|
||||||
*/
|
*/
|
||||||
bool parse_bson_internal()
|
bool parse_bson_internal()
|
||||||
{
|
{
|
||||||
const std::size_t document_start = chars_read;
|
|
||||||
std::int32_t document_size{};
|
std::int32_t document_size{};
|
||||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
||||||
|
|
||||||
@@ -209,11 +182,6 @@ class binary_reader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!check_bson_document_size(document_start, document_size)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +397,6 @@ class binary_reader
|
|||||||
*/
|
*/
|
||||||
bool parse_bson_array()
|
bool parse_bson_array()
|
||||||
{
|
{
|
||||||
const std::size_t document_start = chars_read;
|
|
||||||
std::int32_t document_size{};
|
std::int32_t document_size{};
|
||||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
||||||
|
|
||||||
@@ -443,11 +410,6 @@ class binary_reader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!check_bson_document_size(document_start, document_size)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sax->end_array();
|
return sax->end_array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@
|
|||||||
#include <iterator> // back_inserter
|
#include <iterator> // back_inserter
|
||||||
#include <memory> // shared_ptr, make_shared
|
#include <memory> // shared_ptr, make_shared
|
||||||
#include <string> // basic_string
|
#include <string> // basic_string
|
||||||
|
#include <utility> // move
|
||||||
#include <vector> // vector
|
#include <vector> // vector
|
||||||
|
|
||||||
#ifndef JSON_NO_IO
|
#ifndef JSON_NO_IO
|
||||||
@@ -118,6 +119,72 @@ class output_string_adapter : public output_adapter_protocol<CharType>
|
|||||||
StringType& str;
|
StringType& str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief non-virtual output sink writing into a std::vector
|
||||||
|
///
|
||||||
|
/// Unlike output_vector_adapter, this sink is not part of the virtual
|
||||||
|
/// output_adapter_protocol hierarchy: it is passed to binary_writer by value as
|
||||||
|
/// a template parameter, so write_character()/write_characters() are ordinary
|
||||||
|
/// (inlinable) calls with no vtable lookup and no shared_ptr. It is used for the
|
||||||
|
/// common `to_cbor`/`to_msgpack`/... into a std::vector.
|
||||||
|
template<typename CharType, typename AllocatorType = std::allocator<CharType>>
|
||||||
|
class output_vector_sink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit output_vector_sink(std::vector<CharType, AllocatorType>& vec) noexcept
|
||||||
|
: v(vec)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void write_character(CharType c)
|
||||||
|
{
|
||||||
|
v.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no JSON_HEDLEY_NON_NULL here: binary_writer legitimately passes a null
|
||||||
|
// pointer with length 0 for empty strings/binary values. Appending an empty
|
||||||
|
// range is a no-op; the type-erased path tolerates this via the (unattributed)
|
||||||
|
// virtual base, and the concrete sink must do the same.
|
||||||
|
void write_characters(const CharType* s, std::size_t length)
|
||||||
|
{
|
||||||
|
v.insert(v.end(), s, s + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<CharType, AllocatorType>& v;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief output sink forwarding to a type-erased output adapter
|
||||||
|
///
|
||||||
|
/// Wraps the polymorphic output_adapter_t so the same binary_writer template can
|
||||||
|
/// also target arbitrary adapters (output streams, strings, user-provided
|
||||||
|
/// adapters) via the `output_adapter`-based overloads. Each write still goes
|
||||||
|
/// through one virtual call, exactly as before; only the concrete sinks above
|
||||||
|
/// avoid it.
|
||||||
|
template<typename CharType>
|
||||||
|
class output_adapter_sink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit output_adapter_sink(output_adapter_t<CharType> adapter)
|
||||||
|
: oa(std::move(adapter))
|
||||||
|
{
|
||||||
|
JSON_ASSERT(oa);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_character(CharType c)
|
||||||
|
{
|
||||||
|
oa->write_character(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no JSON_HEDLEY_NON_NULL: forwards (null, 0) for empty payloads, exactly as
|
||||||
|
// the type-erased path already did before this sink existed
|
||||||
|
void write_characters(const CharType* s, std::size_t length)
|
||||||
|
{
|
||||||
|
oa->write_characters(s, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
output_adapter_t<CharType> oa = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename CharType, typename StringType = std::basic_string<CharType>>
|
template<typename CharType, typename StringType = std::basic_string<CharType>>
|
||||||
class output_adapter
|
class output_adapter
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
friend ::nlohmann::detail::serializer<basic_json>;
|
friend ::nlohmann::detail::serializer<basic_json>;
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
friend class ::nlohmann::detail::iter_impl;
|
friend class ::nlohmann::detail::iter_impl;
|
||||||
template<typename BasicJsonType, typename CharType>
|
template<typename BasicJsonType, typename CharType, typename OutputSinkType>
|
||||||
friend class ::nlohmann::detail::binary_writer;
|
friend class ::nlohmann::detail::binary_writer;
|
||||||
template<typename BasicJsonType, typename InputType, typename SAX>
|
template<typename BasicJsonType, typename InputType, typename SAX>
|
||||||
friend class ::nlohmann::detail::binary_reader;
|
friend class ::nlohmann::detail::binary_reader;
|
||||||
@@ -4327,7 +4327,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static std::vector<std::uint8_t> to_cbor(const basic_json& j)
|
static std::vector<std::uint8_t> to_cbor(const basic_json& j)
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> result;
|
std::vector<std::uint8_t> result;
|
||||||
to_cbor(j, result);
|
result.reserve(detail::binary_reserve_hint(j));
|
||||||
|
detail::binary_writer<basic_json, std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
|
||||||
|
detail::output_vector_sink<std::uint8_t>(result)).write_cbor(j);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4350,7 +4352,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
|
static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> result;
|
std::vector<std::uint8_t> result;
|
||||||
to_msgpack(j, result);
|
result.reserve(detail::binary_reserve_hint(j));
|
||||||
|
detail::binary_writer<basic_json, std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
|
||||||
|
detail::output_vector_sink<std::uint8_t>(result)).write_msgpack(j);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4375,7 +4379,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
const bool use_type = false)
|
const bool use_type = false)
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> result;
|
std::vector<std::uint8_t> result;
|
||||||
to_ubjson(j, result, use_size, use_type);
|
result.reserve(detail::binary_reserve_hint(j));
|
||||||
|
detail::binary_writer<basic_json, std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
|
||||||
|
detail::output_vector_sink<std::uint8_t>(result)).write_ubjson(j, use_size, use_type);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4403,7 +4409,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
const bjdata_version_t version = bjdata_version_t::draft2)
|
const bjdata_version_t version = bjdata_version_t::draft2)
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> result;
|
std::vector<std::uint8_t> result;
|
||||||
to_bjdata(j, result, use_size, use_type, version);
|
result.reserve(detail::binary_reserve_hint(j));
|
||||||
|
detail::binary_writer<basic_json, std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
|
||||||
|
detail::output_vector_sink<std::uint8_t>(result)).write_ubjson(j, use_size, use_type, true, true, version);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4430,7 +4438,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static std::vector<std::uint8_t> to_bson(const basic_json& j)
|
static std::vector<std::uint8_t> to_bson(const basic_json& j)
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> result;
|
std::vector<std::uint8_t> result;
|
||||||
to_bson(j, result);
|
result.reserve(detail::binary_reserve_hint(j));
|
||||||
|
detail::binary_writer<basic_json, std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
|
||||||
|
detail::output_vector_sink<std::uint8_t>(result)).write_bson(j);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+353
-200
File diff suppressed because it is too large
Load Diff
@@ -854,62 +854,6 @@ TEST_CASE("Unsupported BSON input")
|
|||||||
CHECK(!json::sax_parse(bson, &scp, json::input_format_t::bson));
|
CHECK(!json::sax_parse(bson, &scp, json::input_format_t::bson));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("BSON document size mismatch")
|
|
||||||
{
|
|
||||||
json _;
|
|
||||||
|
|
||||||
SECTION("top-level document declaring more bytes than it contains")
|
|
||||||
{
|
|
||||||
// empty object, but the length prefix claims 6 bytes instead of 5
|
|
||||||
std::vector<std::uint8_t> const input = {0x06, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(input), "[json.exception.parse_error.112] parse error at byte 5: syntax error while parsing BSON document: document size 6 does not match the number of bytes read (5)", json::parse_error&);
|
|
||||||
CHECK(json::from_bson(input, true, false).is_discarded());
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("top-level document with a negative size")
|
|
||||||
{
|
|
||||||
std::vector<std::uint8_t> const input = {0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(input), "[json.exception.parse_error.112] parse error at byte 5: syntax error while parsing BSON document: document size -1 does not match the number of bytes read (5)", json::parse_error&);
|
|
||||||
CHECK(json::from_bson(input, true, false).is_discarded());
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("embedded document whose size disagrees with its terminator")
|
|
||||||
{
|
|
||||||
// the embedded document "d" declares 0x7FFFFFFF bytes but its 0x00
|
|
||||||
// terminator falls right after {"a":null}; the length prefix would
|
|
||||||
// otherwise let the following "h" element be read as a member of the
|
|
||||||
// enclosing document instead of "d"
|
|
||||||
std::vector<std::uint8_t> const input =
|
|
||||||
{
|
|
||||||
0x00, 0x00, 0x00, 0x00, // outer size
|
|
||||||
0x03, 'd', 0x00, // entry: embedded document "d"
|
|
||||||
0xFF, 0xFF, 0xFF, 0x7F, // embedded size 0x7FFFFFFF
|
|
||||||
0x0A, 'a', 0x00, // entry: null "a"
|
|
||||||
0x00, // embedded end marker
|
|
||||||
0x08, 'h', 0x00, 0x01, // entry: bool "h" = true
|
|
||||||
0x00 // outer end marker
|
|
||||||
};
|
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(input), "[json.exception.parse_error.112] parse error at byte 15: syntax error while parsing BSON document: document size 2147483647 does not match the number of bytes read (8)", json::parse_error&);
|
|
||||||
CHECK(json::from_bson(input, true, false).is_discarded());
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("embedded array whose size disagrees with its terminator")
|
|
||||||
{
|
|
||||||
// array [42] is 12 bytes, but the length prefix claims 13
|
|
||||||
std::vector<std::uint8_t> const input =
|
|
||||||
{
|
|
||||||
0x00, 0x00, 0x00, 0x00, // outer size
|
|
||||||
0x04, 'a', 0x00, // entry: array "a"
|
|
||||||
0x0D, 0x00, 0x00, 0x00, // array size 13 (real is 12)
|
|
||||||
0x10, '0', 0x00, 0x2A, 0x00, 0x00, 0x00, // entry: int32 "0" = 42
|
|
||||||
0x00, // array end marker
|
|
||||||
0x00 // outer end marker
|
|
||||||
};
|
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(input), "[json.exception.parse_error.112] parse error at byte 19: syntax error while parsing BSON document: document size 13 does not match the number of bytes read (12)", json::parse_error&);
|
|
||||||
CHECK(json::from_bson(input, true, false).is_discarded());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("BSON numerical data")
|
TEST_CASE("BSON numerical data")
|
||||||
{
|
{
|
||||||
SECTION("number")
|
SECTION("number")
|
||||||
|
|||||||
Reference in New Issue
Block a user