From b025d66eb5ef117ee051fa8623305e42d369a425 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 14 Jan 2019 16:57:17 -0200 Subject: [PATCH 01/11] Add instructions about using nlohmann/json with the conda package manager --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7f041680..eed744bb 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,8 @@ If you are using [CocoaPods](https://cocoapods.org), you can use the library by If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please files issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues). +If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues). + ## Examples Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). From 9225cf2f572df13027e67bda5b188ae6d2702605 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 15 Jan 2019 14:39:06 +0100 Subject: [PATCH 02/11] allow push_back() and pop_back() calls on json_pointer Putting pop_back() to public and creating a trivial push_back() method allows users of nlohmann::json_pointer to manipulate an existing json-pointer by adding or removing keys at the end. This is useful for traversing a JSON-instance and keeping track of its "absolute path" at any moment. In my case for a schema-validator error-handler. --- include/nlohmann/detail/json_pointer.hpp | 11 ++++- single_include/nlohmann/json.hpp | 11 ++++- test/src/unit-json_pointer.cpp | 54 ++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 3521b889..033625bc 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -97,7 +97,6 @@ class json_pointer return res; } - private: /*! @brief remove and return last reference pointer @throw out_of_range.405 if JSON pointer has no parent @@ -114,6 +113,16 @@ class json_pointer return last; } + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ + void push_back(const std::string& tok) + { + reference_tokens.push_back(tok); + } + + private: /// return whether pointer points to the root document bool is_root() const noexcept { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 70b6c8a8..e3b54c88 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11885,7 +11885,6 @@ class json_pointer return res; } - private: /*! @brief remove and return last reference pointer @throw out_of_range.405 if JSON pointer has no parent @@ -11902,6 +11901,16 @@ class json_pointer return last; } + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ + void push_back(const std::string& tok) + { + reference_tokens.push_back(tok); + } + + private: /// return whether pointer points to the root document bool is_root() const noexcept { diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index ac9cd71e..1bcd3938 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -459,4 +459,58 @@ TEST_CASE("JSON pointers") CHECK(j.is_object()); } } + + SECTION("push and pop") + { + const json j = + { + {"", "Hello"}, + {"pi", 3.141}, + {"happy", true}, + {"name", "Niels"}, + {"nothing", nullptr}, + { + "answer", { + {"everything", 42} + } + }, + {"list", {1, 0, 2}}, + { + "object", { + {"currency", "USD"}, + {"value", 42.99}, + {"", "empty string"}, + {"/", "slash"}, + {"~", "tilde"}, + {"~1", "tilde1"} + } + } + }; + + // empty json_pointer returns the root JSON-object + auto ptr = ""_json_pointer; + CHECK(j[ptr] == j); + + // simple field access + ptr.push_back("pi"); + CHECK(j[ptr] == j["pi"]); + + ptr.pop_back(); + CHECK(j[ptr] == j); + + // object and children access + ptr.push_back("answer"); + ptr.push_back("everything"); + CHECK(j[ptr] == j["answer"]["everything"]); + + ptr.pop_back(); + ptr.pop_back(); + CHECK(j[ptr] == j); + + // push key which has to be encoded + ptr.push_back("object"); + ptr.push_back("/"); + CHECK(j[ptr] == j["object"]["/"]); + CHECK(ptr.to_string() == "/object/~1"); + } } From d0c0d161102c8a11a14978e72b695d36a2a5917a Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 15 Jan 2019 15:21:02 +0100 Subject: [PATCH 03/11] :rotating_light: fixed unused variable warning Since 6503e83e749e18e0749b1c65ab940a89967ed910 "Improve dump_integer performance by implementing a more efficient int2ascii" an unused variable and thus a warning existed. --- include/nlohmann/detail/output/serializer.hpp | 1 - single_include/nlohmann/json.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index cdf74f78..4f7e1ede 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -630,7 +630,6 @@ class serializer // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu // See: https://www.youtube.com/watch?v=o4-CwDo2zpg - const auto buffer_end = buffer_ptr; while (abs_value >= 100) { const auto digits_index = static_cast((abs_value % 100)); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 70b6c8a8..ef4b0cd0 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11520,7 +11520,6 @@ class serializer // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu // See: https://www.youtube.com/watch?v=o4-CwDo2zpg - const auto buffer_end = buffer_ptr; while (abs_value >= 100) { const auto digits_index = static_cast((abs_value % 100)); From 899bd94b43a223baaaddca3caec8feb4dc3861b1 Mon Sep 17 00:00:00 2001 From: scinart Date: Fri, 18 Jan 2019 20:27:49 -0500 Subject: [PATCH 04/11] flush buffer in serializer::dump_escaped case UTF8_REJECT serializer use fixed buffer. Whenever it is nearly full, it is flushed to `output_adapter_t o` But the code forgets to flush when there is a invalid utf8 code point So there will be buffer overflow. --- include/nlohmann/detail/output/serializer.hpp | 10 +++ single_include/nlohmann/json.hpp | 10 +++ test/Makefile | 1 + test/src/unit-invalid_utf8.cpp | 68 +++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 test/src/unit-invalid_utf8.cpp diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 4f7e1ede..b7a0e70c 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -454,6 +454,16 @@ class serializer string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBF'); string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBD'); } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + bytes_after_last_accept = bytes; } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index ef4b0cd0..308969f3 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11344,6 +11344,16 @@ class serializer string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBF'); string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBD'); } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + bytes_after_last_accept = bytes; } diff --git a/test/Makefile b/test/Makefile index 4f00cbc7..e4fc39dc 100644 --- a/test/Makefile +++ b/test/Makefile @@ -30,6 +30,7 @@ SOURCES = src/unit.cpp \ src/unit-items.cpp \ src/unit-iterators1.cpp \ src/unit-iterators2.cpp \ + src/unit-invalid-utf8.cpp \ src/unit-merge_patch.cpp \ src/unit-json_patch.cpp \ src/unit-json_pointer.cpp \ diff --git a/test/src/unit-invalid_utf8.cpp b/test/src/unit-invalid_utf8.cpp new file mode 100644 index 00000000..36f1ada0 --- /dev/null +++ b/test/src/unit-invalid_utf8.cpp @@ -0,0 +1,68 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.5.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "catch.hpp" +#include +using nlohmann::json; + +#include +#include + +TEST_CASE("INVALID-UTF8") +{ + SECTION("a bunch of -1, ensure_ascii=true") + { + json dump_test; + std::vector data(300, -1); + std::vector vec_string(300, "\\ufffd"); + std::string s{data.data(), data.size()}; + dump_test["1"] = s; + std::ostringstream os; + os << "{\"1\":\""; + std::copy( vec_string.begin(), vec_string.end(), std::ostream_iterator(os)); + os << "\"}"; + s = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); + CHECK(s == os.str()); + } + SECTION("a bunch of -2, ensure_ascii=false") + { + json dump_test; + std::vector data(500, -2); + std::vector vec_string(500, "\xEF\xBF\xBD"); + std::string s{data.data(), data.size()}; + dump_test["1"] = s; + std::ostringstream os; + os << "{\"1\":\""; + std::copy( vec_string.begin(), vec_string.end(), std::ostream_iterator(os)); + os << "\"}"; + s = dump_test.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace); + CHECK(s == os.str()); + } + +} From 83e84446d6f6a7d63dea824b6610b39f1eb37903 Mon Sep 17 00:00:00 2001 From: scinart Date: Fri, 18 Jan 2019 20:55:01 -0500 Subject: [PATCH 05/11] fix typo --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index e4fc39dc..6bade2ca 100644 --- a/test/Makefile +++ b/test/Makefile @@ -30,7 +30,7 @@ SOURCES = src/unit.cpp \ src/unit-items.cpp \ src/unit-iterators1.cpp \ src/unit-iterators2.cpp \ - src/unit-invalid-utf8.cpp \ + src/unit-invalid_utf8.cpp \ src/unit-merge_patch.cpp \ src/unit-json_patch.cpp \ src/unit-json_pointer.cpp \ From d359fd3a8d193eb22e2225540b84ef9a00bd3532 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 19 Jan 2019 17:32:23 +0100 Subject: [PATCH 06/11] :construction: trying nodiscard attribute #1433 --- include/nlohmann/detail/macro_scope.hpp | 9 +++++++++ include/nlohmann/detail/macro_unscope.hpp | 1 + include/nlohmann/json.hpp | 13 +++++++++++++ single_include/nlohmann/json.hpp | 23 +++++++++++++++++++++++ test/src/unit-cbor.cpp | 2 +- test/src/unit-readme.cpp | 2 +- test/src/unit-ubjson.cpp | 2 +- 7 files changed, 49 insertions(+), 3 deletions(-) diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 26db6671..fdd1aa12 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -37,6 +37,15 @@ #define JSON_DEPRECATED #endif +// allow for portable nodiscard warnings +#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard) + #define JSON_NODISCARD [[nodiscard]] +#elif defined(__has_cpp_attribute) && __has_cpp_attribute(gnu::warn_unused_result) + #define JSON_NODISCARD [[gnu::warn_unused_result]] +#else + #define JSON_NODISCARD +#endif + // allow to disable exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index 4c5aa915..592debf7 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -16,6 +16,7 @@ #undef JSON_LIKELY #undef JSON_UNLIKELY #undef JSON_DEPRECATED +#undef JSON_NODISCARD #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 3b3da50f..d13f8a9e 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -317,6 +317,7 @@ class basic_json @since 2.1.0 */ + JSON_NODISCARD static basic_json meta() { basic_json result; @@ -1489,6 +1490,7 @@ class basic_json @since version 1.0.0 */ + JSON_NODISCARD static basic_json array(initializer_list_t init = {}) { return basic_json(init, false, value_t::array); @@ -1532,6 +1534,7 @@ class basic_json @since version 1.0.0 */ + JSON_NODISCARD static basic_json object(initializer_list_t init = {}) { return basic_json(init, false, value_t::object); @@ -6051,6 +6054,7 @@ class basic_json @since version 2.0.3 (contiguous containers) */ + JSON_NODISCARD static basic_json parse(detail::input_adapter&& i, const parser_callback_t cb = nullptr, const bool allow_exceptions = true) @@ -6826,6 +6830,7 @@ class basic_json @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ + JSON_NODISCARD static basic_json from_cbor(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -6841,6 +6846,7 @@ class basic_json */ template::value, int> = 0> + JSON_NODISCARD static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true, const bool allow_exceptions = true) @@ -6933,6 +6939,7 @@ class basic_json @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ + JSON_NODISCARD static basic_json from_msgpack(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -6948,6 +6955,7 @@ class basic_json */ template::value, int> = 0> + JSON_NODISCARD static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true, const bool allow_exceptions = true) @@ -7019,6 +7027,7 @@ class basic_json @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 */ + JSON_NODISCARD static basic_json from_ubjson(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -7034,6 +7043,7 @@ class basic_json */ template::value, int> = 0> + JSON_NODISCARD static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true, const bool allow_exceptions = true) @@ -7104,6 +7114,7 @@ class basic_json @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the related UBJSON format */ + JSON_NODISCARD static basic_json from_bson(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -7119,6 +7130,7 @@ class basic_json */ template::value, int> = 0> + JSON_NODISCARD static basic_json from_bson(A1 && a1, A2 && a2, const bool strict = true, const bool allow_exceptions = true) @@ -7710,6 +7722,7 @@ class basic_json @since version 2.0.0 */ + JSON_NODISCARD static basic_json diff(const basic_json& source, const basic_json& target, const std::string& path = "") { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index e63c14d5..6570f8d1 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -152,6 +152,15 @@ using json = basic_json<>; #define JSON_DEPRECATED #endif +// allow for portable nodiscard warnings +#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard) + #define JSON_NODISCARD [[nodiscard]] +#elif defined(__has_cpp_attribute) && __has_cpp_attribute(gnu::warn_unused_result) + #define JSON_NODISCARD [[gnu::warn_unused_result]] +#else + #define JSON_NODISCARD +#endif + // allow to disable exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception @@ -12793,6 +12802,7 @@ class basic_json @since 2.1.0 */ + JSON_NODISCARD static basic_json meta() { basic_json result; @@ -13965,6 +13975,7 @@ class basic_json @since version 1.0.0 */ + JSON_NODISCARD static basic_json array(initializer_list_t init = {}) { return basic_json(init, false, value_t::array); @@ -14008,6 +14019,7 @@ class basic_json @since version 1.0.0 */ + JSON_NODISCARD static basic_json object(initializer_list_t init = {}) { return basic_json(init, false, value_t::object); @@ -18527,6 +18539,7 @@ class basic_json @since version 2.0.3 (contiguous containers) */ + JSON_NODISCARD static basic_json parse(detail::input_adapter&& i, const parser_callback_t cb = nullptr, const bool allow_exceptions = true) @@ -19302,6 +19315,7 @@ class basic_json @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ + JSON_NODISCARD static basic_json from_cbor(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -19317,6 +19331,7 @@ class basic_json */ template::value, int> = 0> + JSON_NODISCARD static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true, const bool allow_exceptions = true) @@ -19409,6 +19424,7 @@ class basic_json @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ + JSON_NODISCARD static basic_json from_msgpack(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -19424,6 +19440,7 @@ class basic_json */ template::value, int> = 0> + JSON_NODISCARD static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true, const bool allow_exceptions = true) @@ -19495,6 +19512,7 @@ class basic_json @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 */ + JSON_NODISCARD static basic_json from_ubjson(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -19510,6 +19528,7 @@ class basic_json */ template::value, int> = 0> + JSON_NODISCARD static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true, const bool allow_exceptions = true) @@ -19580,6 +19599,7 @@ class basic_json @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the related UBJSON format */ + JSON_NODISCARD static basic_json from_bson(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -19595,6 +19615,7 @@ class basic_json */ template::value, int> = 0> + JSON_NODISCARD static basic_json from_bson(A1 && a1, A2 && a2, const bool strict = true, const bool allow_exceptions = true) @@ -20186,6 +20207,7 @@ class basic_json @since version 2.0.0 */ + JSON_NODISCARD static basic_json diff(const basic_json& source, const basic_json& target, const std::string& path = "") { @@ -20505,6 +20527,7 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef JSON_LIKELY #undef JSON_UNLIKELY #undef JSON_DEPRECATED +#undef JSON_NODISCARD #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index e96f4cd0..c74da4f4 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1962,7 +1962,7 @@ TEST_CASE("all CBOR first bytes", "[!throws]") try { - json::from_cbor(std::vector(1, byte)); + auto res = json::from_cbor(std::vector(1, byte)); } catch (const json::parse_error& e) { diff --git a/test/src/unit-readme.cpp b/test/src/unit-readme.cpp index 280a834e..34cb7d15 100644 --- a/test/src/unit-readme.cpp +++ b/test/src/unit-readme.cpp @@ -305,7 +305,7 @@ TEST_CASE("README", "[hide]") // } // calculate a JSON patch from two JSON values - json::diff(j_result, j_original); + auto res = json::diff(j_result, j_original); // [ // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, // { "op":"remove","path":"/hello" }, diff --git a/test/src/unit-ubjson.cpp b/test/src/unit-ubjson.cpp index 6279a5d3..d6e04c3d 100644 --- a/test/src/unit-ubjson.cpp +++ b/test/src/unit-ubjson.cpp @@ -2128,7 +2128,7 @@ TEST_CASE("all UBJSON first bytes", "[!throws]") try { - json::from_ubjson(std::vector(1, byte)); + auto res = json::from_ubjson(std::vector(1, byte)); } catch (const json::parse_error& e) { From 20db020c1fa2e8945f4c9c6c6033e275be9299fa Mon Sep 17 00:00:00 2001 From: scinart Date: Sat, 19 Jan 2019 11:36:50 -0500 Subject: [PATCH 07/11] move newly-added tests in unit-regression.cpp --- test/Makefile | 1 - test/src/unit-invalid_utf8.cpp | 68 ---------------------------------- test/src/unit-regression.cpp | 61 ++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 69 deletions(-) delete mode 100644 test/src/unit-invalid_utf8.cpp diff --git a/test/Makefile b/test/Makefile index 6bade2ca..4f00cbc7 100644 --- a/test/Makefile +++ b/test/Makefile @@ -30,7 +30,6 @@ SOURCES = src/unit.cpp \ src/unit-items.cpp \ src/unit-iterators1.cpp \ src/unit-iterators2.cpp \ - src/unit-invalid_utf8.cpp \ src/unit-merge_patch.cpp \ src/unit-json_patch.cpp \ src/unit-json_pointer.cpp \ diff --git a/test/src/unit-invalid_utf8.cpp b/test/src/unit-invalid_utf8.cpp deleted file mode 100644 index 36f1ada0..00000000 --- a/test/src/unit-invalid_utf8.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.5.0 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -SPDX-License-Identifier: MIT -Copyright (c) 2013-2018 Niels Lohmann . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "catch.hpp" -#include -using nlohmann::json; - -#include -#include - -TEST_CASE("INVALID-UTF8") -{ - SECTION("a bunch of -1, ensure_ascii=true") - { - json dump_test; - std::vector data(300, -1); - std::vector vec_string(300, "\\ufffd"); - std::string s{data.data(), data.size()}; - dump_test["1"] = s; - std::ostringstream os; - os << "{\"1\":\""; - std::copy( vec_string.begin(), vec_string.end(), std::ostream_iterator(os)); - os << "\"}"; - s = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); - CHECK(s == os.str()); - } - SECTION("a bunch of -2, ensure_ascii=false") - { - json dump_test; - std::vector data(500, -2); - std::vector vec_string(500, "\xEF\xBF\xBD"); - std::string s{data.data(), data.size()}; - dump_test["1"] = s; - std::ostringstream os; - os << "{\"1\":\""; - std::copy( vec_string.begin(), vec_string.end(), std::ostream_iterator(os)); - os << "\"}"; - s = dump_test.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace); - CHECK(s == os.str()); - } - -} diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index e739e3c3..a2d61550 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1708,6 +1708,67 @@ TEST_CASE("regression tests") const auto data = j.get(); CHECK(expected == data); } + + SECTION("issue #1445 - buffer overflow in dumping invalid utf-8 strings") + { + SECTION("a bunch of -1, ensure_ascii=true") + { + json dump_test; + std::vector data(300, -1); + std::vector vec_string(300, "\\ufffd"); + std::string s{data.data(), data.size()}; + dump_test["1"] = s; + std::ostringstream os; + os << "{\"1\":\""; + std::copy( vec_string.begin(), vec_string.end(), std::ostream_iterator(os)); + os << "\"}"; + s = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); + CHECK(s == os.str()); + } + SECTION("a bunch of -2, ensure_ascii=false") + { + json dump_test; + std::vector data(500, -2); + std::vector vec_string(500, "\xEF\xBF\xBD"); + std::string s{data.data(), data.size()}; + dump_test["1"] = s; + std::ostringstream os; + os << "{\"1\":\""; + std::copy( vec_string.begin(), vec_string.end(), std::ostream_iterator(os)); + os << "\"}"; + s = dump_test.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace); + CHECK(s == os.str()); + } + SECTION("test case in issue #1445") + { + nlohmann::json dump_test; + const int data[] = { + 109, 108, 103, 125, -122, -53, 115, + 18, 3, 0, 102, 19, 1, 15, + -110, 13, -3, -1, -81, 32, 2, + 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -80, 2, + 0, 0, 96, -118, 46, -116, 46, + 109, -84, -87, 108, 14, 109, -24, + -83, 13, -18, -51, -83, -52, -115, + 14, 6, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 64, 3, 0, 0, 0, 35, -74, + -73, 55, 57, -128, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 33, 0, 0, 0, -96, + -54, -28, -26 + }; + std::string s; + for (int i=0; i(data[i]); + } + dump_test["1"] = s; + dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); + } + } } TEST_CASE("regression tests, exceptions dependent", "[!throws]") From e36593e9608d0437035b631df6b667cd8fa19dbd Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 20 Jan 2019 11:12:20 +0100 Subject: [PATCH 08/11] :hammer: trying code from https://godbolt.org/z/-tLO1K --- include/nlohmann/detail/macro_scope.hpp | 12 ++++++++---- single_include/nlohmann/json.hpp | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index fdd1aa12..b1bd1484 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -38,10 +38,14 @@ #endif // allow for portable nodiscard warnings -#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard) - #define JSON_NODISCARD [[nodiscard]] -#elif defined(__has_cpp_attribute) && __has_cpp_attribute(gnu::warn_unused_result) - #define JSON_NODISCARD [[gnu::warn_unused_result]] +#if defined(__has_cpp_attribute) + #if __has_cpp_attribute(nodiscard) + #define JSON_NODISCARD [[nodiscard]] + #elif __has_cpp_attribute(gnu::warn_unused_result) + #define JSON_NODISCARD [[gnu::warn_unused_result]] + #else + #define JSON_NODISCARD + #endif #else #define JSON_NODISCARD #endif diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 6570f8d1..70412a18 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -153,10 +153,14 @@ using json = basic_json<>; #endif // allow for portable nodiscard warnings -#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard) - #define JSON_NODISCARD [[nodiscard]] -#elif defined(__has_cpp_attribute) && __has_cpp_attribute(gnu::warn_unused_result) - #define JSON_NODISCARD [[gnu::warn_unused_result]] +#if defined(__has_cpp_attribute) + #if __has_cpp_attribute(nodiscard) + #define JSON_NODISCARD [[nodiscard]] + #elif __has_cpp_attribute(gnu::warn_unused_result) + #define JSON_NODISCARD [[gnu::warn_unused_result]] + #else + #define JSON_NODISCARD + #endif #else #define JSON_NODISCARD #endif From 6de4df23e4acc02c5543d61ae274cc35713c0a12 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 20 Jan 2019 12:26:01 +0100 Subject: [PATCH 09/11] :bug: fixed integer overflow in dump function #1447 Closes #1447. --- include/nlohmann/detail/output/serializer.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- test/src/unit-regression.cpp | 11 +++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index b7a0e70c..9994372d 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -620,7 +620,7 @@ class serializer if (is_negative) { *buffer_ptr = '-'; - abs_value = static_cast(0 - x); + abs_value = static_cast(-1 - x) + 1; // account one more byte for the minus sign n_chars = 1 + count_digits(abs_value); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index b946b760..9ea8bed3 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11510,7 +11510,7 @@ class serializer if (is_negative) { *buffer_ptr = '-'; - abs_value = static_cast(0 - x); + abs_value = static_cast(-1 - x) + 1; // account one more byte for the minus sign n_chars = 1 + count_digits(abs_value); diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index a2d61550..975b9239 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1742,7 +1742,8 @@ TEST_CASE("regression tests") SECTION("test case in issue #1445") { nlohmann::json dump_test; - const int data[] = { + const int data[] = + { 109, 108, 103, 125, -122, -53, 115, 18, 3, 0, 102, 19, 1, 15, -110, 13, -3, -1, -81, 32, 2, @@ -1761,7 +1762,7 @@ TEST_CASE("regression tests") -54, -28, -26 }; std::string s; - for (int i=0; i(data[i]); } @@ -1769,6 +1770,12 @@ TEST_CASE("regression tests") dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); } } + + SECTION("issue #1447 - Integer Overflow (OSS-Fuzz 12506)") + { + json j = json::parse("[-9223372036854775808]"); + CHECK(j.dump() == "[-9223372036854775808]"); + } } TEST_CASE("regression tests, exceptions dependent", "[!throws]") From dc21cbb7515f289184ced9ce5bb952f8e1002ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Plch?= Date: Tue, 22 Jan 2019 10:13:12 +0100 Subject: [PATCH 10/11] remove extra semicolon in example of NLOHMANN_JSON_SERIALIZE_ENUM --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eed744bb..b91b43ec 100644 --- a/README.md +++ b/README.md @@ -917,7 +917,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, { {TS_STOPPED, "stopped"}, {TS_RUNNING, "running"}, {TS_COMPLETED, "completed"}, -}); +}) ``` The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serilization code. From cca6d0dbaeb79119efea24b143d11dd7fa2b74da Mon Sep 17 00:00:00 2001 From: Mark Beckwith Date: Thu, 24 Jan 2019 10:49:45 -0600 Subject: [PATCH 11/11] docs: README type Just another small typo I found in the README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eed744bb..b183094f 100644 --- a/README.md +++ b/README.md @@ -749,7 +749,7 @@ Likewise, when calling `get()` or `get_to(your_type&)`, the `from_jso Some important things: * Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). -* Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. +* Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. * When using `get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) * In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.