From 43dbe02d5b365e44b8be0fbf4dd5863787249c9e Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 21 Nov 2016 21:53:10 +0100 Subject: [PATCH 01/13] :bug: fixing #359 --- src/json.hpp | 25 ++----------------------- src/json.hpp.re2c | 25 ++----------------------- 2 files changed, 4 insertions(+), 46 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index a302bb02b..b0313f719 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -122,26 +122,6 @@ struct has_mapped_type std::is_integral()))>::value; }; -/*! -@brief helper class to create locales with decimal point - -This struct is used a default locale during the JSON serialization. JSON -requires the decimal point to be `.`, so this function overloads the -`do_decimal_point()` function to return `.`. This function is called by -float-to-string conversions to retrieve the decimal separator between integer -and fractional parts. - -@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 -@since version 2.0.0 -*/ -struct DecimalSeparator : std::numpunct -{ - char do_decimal_point() const - { - return '.'; - } -}; - } /*! @@ -2201,8 +2181,7 @@ class basic_json { std::stringstream ss; // fix locale problems - const static std::locale loc(std::locale(), new DecimalSeparator); - ss.imbue(loc); + ss.imbue(std::locale::classic()); // 6, 15 or 16 digits of precision allows round-trip IEEE 754 // string->float->string, string->double->string or string->long @@ -5829,7 +5808,7 @@ class basic_json o.width(0); // fix locale problems - const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); + const auto old_locale = o.imbue(std::locale::classic()); // set precision // 6, 15 or 16 digits of precision allows round-trip IEEE 754 diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index b829889d5..7c386cf69 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -122,26 +122,6 @@ struct has_mapped_type std::is_integral()))>::value; }; -/*! -@brief helper class to create locales with decimal point - -This struct is used a default locale during the JSON serialization. JSON -requires the decimal point to be `.`, so this function overloads the -`do_decimal_point()` function to return `.`. This function is called by -float-to-string conversions to retrieve the decimal separator between integer -and fractional parts. - -@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 -@since version 2.0.0 -*/ -struct DecimalSeparator : std::numpunct -{ - char do_decimal_point() const - { - return '.'; - } -}; - } /*! @@ -2201,8 +2181,7 @@ class basic_json { std::stringstream ss; // fix locale problems - const static std::locale loc(std::locale(), new DecimalSeparator); - ss.imbue(loc); + ss.imbue(std::locale::classic()); // 6, 15 or 16 digits of precision allows round-trip IEEE 754 // string->float->string, string->double->string or string->long @@ -5829,7 +5808,7 @@ class basic_json o.width(0); // fix locale problems - const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); + const auto old_locale = o.imbue(std::locale::classic()); // set precision // 6, 15 or 16 digits of precision allows round-trip IEEE 754 From abce5c25bbc58962ad7f2143029e2cd2850dcd41 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 21 Nov 2016 23:38:17 +0100 Subject: [PATCH 02/13] :memo: cleaned comments and updated README --- README.md | 2 ++ src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 008c83040..5e899ac21 100644 --- a/README.md +++ b/README.md @@ -499,6 +499,8 @@ I deeply appreciate the help of the following people. - [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion. - [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable. - [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. +- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function. +- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](http://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling. Thanks a lot for helping out! diff --git a/src/json.hpp b/src/json.hpp index b0313f719..e71ffc4a2 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -45,7 +45,7 @@ SOFTWARE. #include // istream, ostream #include // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator #include // numeric_limits -#include // locale, numpunct +#include // locale #include // map #include // addressof, allocator, allocator_traits, unique_ptr #include // accumulate diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 7c386cf69..9eccc144f 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -45,7 +45,7 @@ SOFTWARE. #include // istream, ostream #include // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator #include // numeric_limits -#include // locale, numpunct +#include // locale #include // map #include // addressof, allocator, allocator_traits, unique_ptr #include // accumulate From ed611119d99e0569a0a8d03f7a7aea11b0416497 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 23 Nov 2016 08:47:40 +0100 Subject: [PATCH 03/13] :chart_with_upwards_trend: reducing benchmark variance (#365) --- Makefile | 2 +- benchmarks/benchmarks.cpp | 44 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4c66fbfbc..3fd6d54b1 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ pretty: # benchmarks json_benchmarks: benchmarks/benchmarks.cpp benchmarks/benchpress.hpp benchmarks/cxxopts.hpp src/json.hpp cd benchmarks/files/numbers ; python generate.py - $(CXX) -std=c++11 $(CXXFLAGS) -DNDEBUG -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@ + $(CXX) -std=c++11 -pthread $(CXXFLAGS) -DNDEBUG -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@ ./json_benchmarks diff --git a/benchmarks/benchmarks.cpp b/benchmarks/benchmarks.cpp index ec6b462c8..251481ea1 100644 --- a/benchmarks/benchmarks.cpp +++ b/benchmarks/benchmarks.cpp @@ -3,14 +3,36 @@ #include #include #include +#include +#include + +struct StartUp +{ + StartUp() + { +#ifndef __llvm__ + // pin thread to a single CPU + cpu_set_t cpuset; + pthread_t thread; + thread = pthread_self(); + CPU_ZERO(&cpuset); + CPU_SET(std::thread::hardware_concurrency() - 1, &cpuset); + pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset); +#endif + } +}; +StartUp startup; BENCHMARK("parse jeopardy.json", [](benchpress::context* ctx) { for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->stop_timer(); std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json"); nlohmann::json j; + ctx->start_timer(); j << input_file; + ctx->stop_timer(); } }) @@ -18,9 +40,12 @@ BENCHMARK("parse canada.json", [](benchpress::context* ctx) { for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->stop_timer(); std::ifstream input_file("benchmarks/files/nativejson-benchmark/canada.json"); nlohmann::json j; + ctx->start_timer(); j << input_file; + ctx->stop_timer(); } }) @@ -28,9 +53,12 @@ BENCHMARK("parse citm_catalog.json", [](benchpress::context* ctx) { for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->stop_timer(); std::ifstream input_file("benchmarks/files/nativejson-benchmark/citm_catalog.json"); nlohmann::json j; + ctx->start_timer(); j << input_file; + ctx->stop_timer(); } }) @@ -38,9 +66,12 @@ BENCHMARK("parse twitter.json", [](benchpress::context* ctx) { for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->stop_timer(); std::ifstream input_file("benchmarks/files/nativejson-benchmark/twitter.json"); nlohmann::json j; + ctx->start_timer(); j << input_file; + ctx->stop_timer(); } }) @@ -48,9 +79,12 @@ BENCHMARK("parse numbers/floats.json", [](benchpress::context* ctx) { for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->stop_timer(); std::ifstream input_file("benchmarks/files/numbers/floats.json"); nlohmann::json j; + ctx->start_timer(); j << input_file; + ctx->stop_timer(); } }) @@ -58,9 +92,12 @@ BENCHMARK("parse numbers/signed_ints.json", [](benchpress::context* ctx) { for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->stop_timer(); std::ifstream input_file("benchmarks/files/numbers/signed_ints.json"); nlohmann::json j; + ctx->start_timer(); j << input_file; + ctx->stop_timer(); } }) @@ -68,9 +105,12 @@ BENCHMARK("parse numbers/unsigned_ints.json", [](benchpress::context* ctx) { for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->stop_timer(); std::ifstream input_file("benchmarks/files/numbers/unsigned_ints.json"); nlohmann::json j; + ctx->start_timer(); j << input_file; + ctx->stop_timer(); } }) @@ -84,7 +124,9 @@ BENCHMARK("dump jeopardy.json", [](benchpress::context* ctx) ctx->reset_timer(); for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->start_timer(); output_file << j; + ctx->stop_timer(); } std::remove("jeopardy.dump.json"); @@ -100,7 +142,9 @@ BENCHMARK("dump jeopardy.json with indent", [](benchpress::context* ctx) ctx->reset_timer(); for (size_t i = 0; i < ctx->num_iterations(); ++i) { + ctx->start_timer(); output_file << std::setw(4) << j; + ctx->stop_timer(); } std::remove("jeopardy.dump.json"); From 4bb41d065bb0474582042462cf9c34bdbc1e50e3 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 23 Nov 2016 16:57:01 +0100 Subject: [PATCH 04/13] :bug: parsing erroneous files yields an exception (#366) --- src/json.hpp | 6 ++++++ src/json.hpp.re2c | 6 ++++++ test/src/unit-regression.cpp | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/json.hpp b/src/json.hpp index e71ffc4a2..dbe49c2a2 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7597,6 +7597,12 @@ class basic_json explicit lexer(std::istream& s) : m_stream(&s), m_line_buffer() { + // immediately abort if stream is erroneous + if (s.fail()) + { + throw std::invalid_argument("stream error: " + std::string(strerror(errno))); + } + // fill buffer fill_line_buffer(); diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 9eccc144f..ef9910ce2 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7597,6 +7597,12 @@ class basic_json explicit lexer(std::istream& s) : m_stream(&s), m_line_buffer() { + // immediately abort if stream is erroneous + if (s.fail()) + { + throw std::invalid_argument("stream error: " + std::string(strerror(errno))); + } + // fill buffer fill_line_buffer(); diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 661edc25f..ac6d25df1 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -495,4 +495,10 @@ TEST_CASE("regression tests") json j = json::parse("22e2222"); CHECK(j == json()); } + + SECTION("issue #366 - json::parse on failed stream gets stuck") + { + std::ifstream f("file_not_found.json"); + CHECK_THROWS_AS(json::parse(f), std::invalid_argument); + } } From 25548f85c9fce130230ee9d99201ba2b4f96ce9c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 17:25:05 +0100 Subject: [PATCH 05/13] :construction_worker: trying Coverity with Clang 3.6 (#299) --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f3d9deeab..8a9b10324 100644 --- a/.travis.yml +++ b/.travis.yml @@ -84,22 +84,22 @@ matrix: # Coverity (only for branch coverity_scan) - os: linux - compiler: gcc + compiler: clang before_install: echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-certificates.crt addons: apt: sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-5', 'valgrind'] + packages: ['valgrind'] coverity_scan: project: name: "nlohmann/json" description: "Build submitted via Travis CI" notification_email: niels.lohmann@gmail.com - build_command_prepend: "make clean ; sudo cp $(which g++-5) $(which g++)" + build_command_prepend: "make clean" build_command: "make" branch_pattern: coverity_scan env: - - COMPILER=g++-5 + - LLVM_VERSION=3.6.0 - SPECIAL=coverity # OSX / Clang From c3a610d32aaf3dd1022af1d4c952a9b53ca9480d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 17:45:01 +0100 Subject: [PATCH 06/13] :wrench: ignoring Clion files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index c7e847c4c..bd8c86992 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ doc/html me.nlohmann.json.docset benchmarks/files/numbers/*.json + +.idea +cmake-build-debug + From e3450cac720462ecd6e5b9ae707cbe5023c1e3cc Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 18:24:26 +0100 Subject: [PATCH 07/13] :chart_with_upwards_trend: removing more variance of the benchmarks --- benchmarks/benchmarks.cpp | 203 ++++++++++++++++---------------------- 1 file changed, 85 insertions(+), 118 deletions(-) diff --git a/benchmarks/benchmarks.cpp b/benchmarks/benchmarks.cpp index 251481ea1..efb26cf20 100644 --- a/benchmarks/benchmarks.cpp +++ b/benchmarks/benchmarks.cpp @@ -1,11 +1,14 @@ #define BENCHPRESS_CONFIG_MAIN #include +#include #include #include #include #include +using json = nlohmann::json; + struct StartUp { StartUp() @@ -23,129 +26,93 @@ struct StartUp }; StartUp startup; -BENCHMARK("parse jeopardy.json", [](benchpress::context* ctx) -{ - for (size_t i = 0; i < ctx->num_iterations(); ++i) - { - ctx->stop_timer(); - std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json"); - nlohmann::json j; - ctx->start_timer(); - j << input_file; - ctx->stop_timer(); - } -}) +enum class EMode { input, output_no_indent, output_with_indent }; -BENCHMARK("parse canada.json", [](benchpress::context* ctx) +static void bench(benchpress::context& ctx, + const std::string& in_path, + const EMode mode) { - for (size_t i = 0; i < ctx->num_iterations(); ++i) + // using string streams for benchmarking to factor-out cold-cache disk + // access. + std::stringstream istr; { - ctx->stop_timer(); - std::ifstream input_file("benchmarks/files/nativejson-benchmark/canada.json"); - nlohmann::json j; - ctx->start_timer(); - j << input_file; - ctx->stop_timer(); - } -}) + // read file into string stream + std::ifstream input_file(in_path); + istr << input_file.rdbuf(); + input_file.close(); -BENCHMARK("parse citm_catalog.json", [](benchpress::context* ctx) -{ - for (size_t i = 0; i < ctx->num_iterations(); ++i) - { - ctx->stop_timer(); - std::ifstream input_file("benchmarks/files/nativejson-benchmark/citm_catalog.json"); - nlohmann::json j; - ctx->start_timer(); - j << input_file; - ctx->stop_timer(); - } -}) - -BENCHMARK("parse twitter.json", [](benchpress::context* ctx) -{ - for (size_t i = 0; i < ctx->num_iterations(); ++i) - { - ctx->stop_timer(); - std::ifstream input_file("benchmarks/files/nativejson-benchmark/twitter.json"); - nlohmann::json j; - ctx->start_timer(); - j << input_file; - ctx->stop_timer(); - } -}) - -BENCHMARK("parse numbers/floats.json", [](benchpress::context* ctx) -{ - for (size_t i = 0; i < ctx->num_iterations(); ++i) - { - ctx->stop_timer(); - std::ifstream input_file("benchmarks/files/numbers/floats.json"); - nlohmann::json j; - ctx->start_timer(); - j << input_file; - ctx->stop_timer(); - } -}) - -BENCHMARK("parse numbers/signed_ints.json", [](benchpress::context* ctx) -{ - for (size_t i = 0; i < ctx->num_iterations(); ++i) - { - ctx->stop_timer(); - std::ifstream input_file("benchmarks/files/numbers/signed_ints.json"); - nlohmann::json j; - ctx->start_timer(); - j << input_file; - ctx->stop_timer(); - } -}) - -BENCHMARK("parse numbers/unsigned_ints.json", [](benchpress::context* ctx) -{ - for (size_t i = 0; i < ctx->num_iterations(); ++i) - { - ctx->stop_timer(); - std::ifstream input_file("benchmarks/files/numbers/unsigned_ints.json"); - nlohmann::json j; - ctx->start_timer(); - j << input_file; - ctx->stop_timer(); - } -}) - -BENCHMARK("dump jeopardy.json", [](benchpress::context* ctx) -{ - std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json"); - nlohmann::json j; - j << input_file; - std::ofstream output_file("jeopardy.dump.json"); - - ctx->reset_timer(); - for (size_t i = 0; i < ctx->num_iterations(); ++i) - { - ctx->start_timer(); - output_file << j; - ctx->stop_timer(); + // read the stream once + json j; + j << istr; + // clear flags and rewind + istr.clear(); + istr.seekg(0); } - std::remove("jeopardy.dump.json"); -}) - -BENCHMARK("dump jeopardy.json with indent", [](benchpress::context* ctx) -{ - std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json"); - nlohmann::json j; - j << input_file; - std::ofstream output_file("jeopardy.dump.json"); - - ctx->reset_timer(); - for (size_t i = 0; i < ctx->num_iterations(); ++i) + switch (mode) { - ctx->start_timer(); - output_file << std::setw(4) << j; - ctx->stop_timer(); - } + // benchmarking input + case EMode::input: + { + ctx.reset_timer(); - std::remove("jeopardy.dump.json"); -}) + for (size_t i = 0; i < ctx.num_iterations(); ++i) + { + // clear flags and rewind + istr.clear(); + istr.seekg(0); + json j; + j << istr; + } + + break; + } + + // benchmarking output + case EMode::output_no_indent: + case EMode::output_with_indent: + { + // create JSON value from input + json j; + j << istr; + std::stringstream ostr; + + ctx.reset_timer(); + for (size_t i = 0; i < ctx.num_iterations(); ++i) + { + if (mode == EMode::output_no_indent) + { + ostr << j; + } + else + { + ostr << std::setw(4) << j; + } + + // reset data + ostr.str(std::string()); + } + + break; + } + } +} + +#define BENCHMARK_I(mode, title, in_path) \ + BENCHMARK((title), [](benchpress::context* ctx) \ + { \ + bench(*ctx, (in_path), (mode)); \ + }) + +BENCHMARK_I(EMode::input, "parse jeopardy.json", "benchmarks/files/jeopardy/jeopardy.json"); +BENCHMARK_I(EMode::input, "parse canada.json", "benchmarks/files/nativejson-benchmark/canada.json"); +BENCHMARK_I(EMode::input, "parse citm_catalog.json", "benchmarks/files/nativejson-benchmark/citm_catalog.json"); +BENCHMARK_I(EMode::input, "parse twitter.json", "benchmarks/files/nativejson-benchmark/twitter.json"); +BENCHMARK_I(EMode::input, "parse numbers/floats.json", "benchmarks/files/numbers/floats.json"); +BENCHMARK_I(EMode::input, "parse numbers/signed_ints.json", "benchmarks/files/numbers/signed_ints.json"); +BENCHMARK_I(EMode::input, "parse numbers/unsigned_ints.json", "benchmarks/files/numbers/unsigned_ints.json"); + +BENCHMARK_I(EMode::output_no_indent, "dump jeopardy.json", "benchmarks/files/jeopardy/jeopardy.json"); +BENCHMARK_I(EMode::output_with_indent, "dump jeopardy.json with indent", "benchmarks/files/jeopardy/jeopardy.json"); +BENCHMARK_I(EMode::output_no_indent, "dump numbers/floats.json", "benchmarks/files/numbers/floats.json"); +BENCHMARK_I(EMode::output_no_indent, "dump numbers/signed_ints.json", "benchmarks/files/numbers/signed_ints.json"); From dfc49e7afe905fadae756aa24734629a1afdb0fd Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 21:45:10 +0100 Subject: [PATCH 08/13] :bug: fixed a bug if parser was called with a stream at EOF (#367) --- src/json.hpp | 5 ++++- src/json.hpp.re2c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index e71ffc4a2..915a60f44 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -8743,7 +8743,10 @@ basic_json_parser_66: // append n characters to make sure that there is sufficient // space between m_cursor and m_limit m_line_buffer.append(1, '\x00'); - m_line_buffer.append(n - 1, '\x01'); + if (n > 0) + { + m_line_buffer.append(n - 1, '\x01'); + } } else { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 9eccc144f..9b21c828e 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7892,7 +7892,10 @@ class basic_json // append n characters to make sure that there is sufficient // space between m_cursor and m_limit m_line_buffer.append(1, '\x00'); - m_line_buffer.append(n - 1, '\x01'); + if (n > 0) + { + m_line_buffer.append(n - 1, '\x01'); + } } else { From 8014637ad1a05914fc069213c1f5c93aa9e2da17 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 21:53:41 +0100 Subject: [PATCH 09/13] :white_check_mark: added a test for EOF error (#367) --- test/src/unit-regression.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 661edc25f..414ee71c4 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -495,4 +495,19 @@ TEST_CASE("regression tests") json j = json::parse("22e2222"); CHECK(j == json()); } + + SECTION("issue #367 - calling stream at EOF") + { + std::stringstream ss; + json j; + ss << "123"; + CHECK_NOTHROW(j << ss); + + // see https://github.com/nlohmann/json/issues/367#issuecomment-262841893: + // ss is not at EOF; this yielded an error before the fix + // (threw basic_string::append). No, it should just throw + // a parse error because of the EOF. + CHECK_THROWS_AS(j << ss, std::invalid_argument); + CHECK_THROWS_WITH(j << ss, "parse error - unexpected end of input"); + } } From 1407bbf94cd3a6b927f3e52a946b82eddbf3ff3c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 21:54:05 +0100 Subject: [PATCH 10/13] :lipstick: fixed indentation --- benchmarks/benchmarks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/benchmarks.cpp b/benchmarks/benchmarks.cpp index efb26cf20..745123c92 100644 --- a/benchmarks/benchmarks.cpp +++ b/benchmarks/benchmarks.cpp @@ -58,7 +58,7 @@ static void bench(benchpress::context& ctx, for (size_t i = 0; i < ctx.num_iterations(); ++i) { - // clear flags and rewind + // clear flags and rewind istr.clear(); istr.seekg(0); json j; From 472d0045ba41fd22412c7b697e804c248ce109bf Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 21:56:21 +0100 Subject: [PATCH 11/13] :memo: updating README after fixing #299 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5e899ac21..eca178afe 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) [![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/fsf5FqYe6GoX68W6) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) @@ -501,6 +502,7 @@ I deeply appreciate the help of the following people. - [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. - [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function. - [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](http://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling. +- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan. Thanks a lot for helping out! From c39c36e6adad209db38682f5ebb26096d47d421b Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 22:05:29 +0100 Subject: [PATCH 12/13] :lipstick: fixed indentation --- test/src/unit-regression.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 414ee71c4..cda578abf 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -495,19 +495,19 @@ TEST_CASE("regression tests") json j = json::parse("22e2222"); CHECK(j == json()); } - - SECTION("issue #367 - calling stream at EOF") - { - std::stringstream ss; - json j; - ss << "123"; - CHECK_NOTHROW(j << ss); - // see https://github.com/nlohmann/json/issues/367#issuecomment-262841893: - // ss is not at EOF; this yielded an error before the fix - // (threw basic_string::append). No, it should just throw - // a parse error because of the EOF. - CHECK_THROWS_AS(j << ss, std::invalid_argument); - CHECK_THROWS_WITH(j << ss, "parse error - unexpected end of input"); - } + SECTION("issue #367 - calling stream at EOF") + { + std::stringstream ss; + json j; + ss << "123"; + CHECK_NOTHROW(j << ss); + + // see https://github.com/nlohmann/json/issues/367#issuecomment-262841893: + // ss is not at EOF; this yielded an error before the fix + // (threw basic_string::append). No, it should just throw + // a parse error because of the EOF. + CHECK_THROWS_AS(j << ss, std::invalid_argument); + CHECK_THROWS_WITH(j << ss, "parse error - unexpected end of input"); + } } From f194db9aa684b494678ab9cb08c659f732af7fc6 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 24 Nov 2016 22:07:35 +0100 Subject: [PATCH 13/13] :white_check_mark: added assertion for warning from #368 --- src/json.hpp | 1 + src/json.hpp.re2c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/json.hpp b/src/json.hpp index 915a60f44..81dc5f8fa 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -8736,6 +8736,7 @@ basic_json_parser_66: m_line_buffer.clear(); for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor) { + assert(m_cursor != nullptr); m_line_buffer.append(1, static_cast(*m_cursor)); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 9b21c828e..3b2c75001 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7885,6 +7885,7 @@ class basic_json m_line_buffer.clear(); for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor) { + assert(m_cursor != nullptr); m_line_buffer.append(1, static_cast(*m_cursor)); } }