diff --git a/src/json.hpp b/src/json.hpp index 0675a939..5a35b16d 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7890,7 +7890,7 @@ class basic_json }; if ((m_limit - m_cursor) < 5) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yybm[0 + yych] & 32) @@ -8024,7 +8024,7 @@ basic_json_parser_6: ++m_cursor; if (m_limit <= m_cursor) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yybm[0 + yych] & 32) @@ -8094,7 +8094,7 @@ basic_json_parser_15: m_marker = ++m_cursor; if ((m_limit - m_cursor) < 3) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yybm[0 + yych] & 64) @@ -8187,7 +8187,7 @@ basic_json_parser_31: ++m_cursor; if (m_limit <= m_cursor) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; basic_json_parser_32: @@ -8224,7 +8224,7 @@ basic_json_parser_36: ++m_cursor; if (m_limit <= m_cursor) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yych <= 'e') @@ -8368,7 +8368,7 @@ basic_json_parser_43: ++m_cursor; if (m_limit <= m_cursor) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yych <= '@') @@ -8404,7 +8404,7 @@ basic_json_parser_44: m_marker = ++m_cursor; if ((m_limit - m_cursor) < 3) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yych <= 'D') @@ -8445,7 +8445,7 @@ basic_json_parser_47: ++m_cursor; if (m_limit <= m_cursor) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yych <= '/') @@ -8487,7 +8487,7 @@ basic_json_parser_54: ++m_cursor; if (m_limit <= m_cursor) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yych <= '@') @@ -8541,7 +8541,7 @@ basic_json_parser_60: ++m_cursor; if (m_limit <= m_cursor) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yych <= '@') @@ -8582,7 +8582,7 @@ basic_json_parser_63: ++m_cursor; if (m_limit <= m_cursor) { - fill_line_buffer(); // LCOV_EXCL_LINE; + fill_line_buffer(); } yych = *m_cursor; if (yych <= '@') diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index f56c5d3f..a5b8a14f 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7854,7 +7854,7 @@ class basic_json re2c:define:YYCURSOR = m_cursor; re2c:define:YYLIMIT = m_limit; re2c:define:YYMARKER = m_marker; - re2c:define:YYFILL = "fill_line_buffer(); // LCOV_EXCL_LINE"; + re2c:define:YYFILL = "fill_line_buffer()"; re2c:yyfill:parameter = 0; re2c:indent:string = " "; re2c:indent:top = 1; diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index dcf8aa35..9ad162c1 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -28,13 +28,14 @@ SOFTWARE. #include "catch.hpp" +#define private public #include "json.hpp" using nlohmann::json; // special test case to check if memory is leaked if constructor throws template -struct my_allocator : std::allocator +struct bad_allocator : std::allocator { template void construct(T*, Args&& ...) @@ -48,16 +49,186 @@ TEST_CASE("bad_alloc") SECTION("bad_alloc") { // create JSON type using the throwing allocator - using my_json = nlohmann::basic_json; + bad_allocator>; // creating an object should throw - CHECK_THROWS_AS(my_json j(my_json::value_t::object), std::bad_alloc); + CHECK_THROWS_AS(bad_json j(bad_json::value_t::object), std::bad_alloc); + } +} + +bool next_construct_fails = false; +bool next_destroy_fails = false; +bool next_deallocate_fails = false; + +template +struct my_allocator : std::allocator +{ + template + void construct(T* p, Args&& ... args) + { + if (next_construct_fails) + { + next_construct_fails = false; + throw std::bad_alloc(); + } + else + { + ::new(reinterpret_cast(p)) T(std::forward(args)...); + } + } + + void deallocate(T* p, std::size_t n) + { + if (next_deallocate_fails) + { + next_deallocate_fails = false; + throw std::bad_alloc(); + } + else + { + std::allocator::deallocate(p, n); + } + } + + void destroy(T* p) + { + if (next_destroy_fails) + { + next_destroy_fails = false; + throw std::bad_alloc(); + } + else + { + p->~T(); + } + } +}; + +TEST_CASE("controlled bad_alloc") +{ + // create JSON type using the throwing allocator + using my_json = nlohmann::basic_json; + + SECTION("class json_value") + { + SECTION("json_value(value_t)") + { + SECTION("object") + { + next_construct_fails = false; + auto t = my_json::value_t::object; + CHECK_NOTHROW(my_json::json_value j(t)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc); + next_construct_fails = false; + } + SECTION("array") + { + next_construct_fails = false; + auto t = my_json::value_t::array; + CHECK_NOTHROW(my_json::json_value j(t)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc); + next_construct_fails = false; + } + SECTION("string") + { + next_construct_fails = false; + auto t = my_json::value_t::string; + CHECK_NOTHROW(my_json::json_value j(t)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc); + next_construct_fails = false; + } + } + + SECTION("json_value(const string_t&)") + { + next_construct_fails = false; + my_json::string_t v("foo"); + CHECK_NOTHROW(my_json::json_value j(v)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc); + next_construct_fails = false; + } + + /* + SECTION("json_value(const object_t&)") + { + next_construct_fails = false; + my_json::object_t v {{"foo", "bar"}}; + CHECK_NOTHROW(my_json::json_value j(v)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc); + next_construct_fails = false; + } + */ + /* + SECTION("json_value(const array_t&)") + { + next_construct_fails = false; + my_json::array_t v = {"foo", "bar", "baz"}; + CHECK_NOTHROW(my_json::json_value j(v)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc); + next_construct_fails = false; + } + */ + } + + SECTION("class basic_json") + { + SECTION("basic_json(const CompatibleObjectType&)") + { + next_construct_fails = false; + std::map v {{"foo", "bar"}}; + CHECK_NOTHROW(my_json j(v)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json j(v), std::bad_alloc); + next_construct_fails = false; + } + + SECTION("basic_json(const CompatibleArrayType&)") + { + next_construct_fails = false; + std::vector v {"foo", "bar", "baz"}; + CHECK_NOTHROW(my_json j(v)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json j(v), std::bad_alloc); + next_construct_fails = false; + } + + SECTION("basic_json(const typename string_t::value_type*)") + { + next_construct_fails = false; + CHECK_NOTHROW(my_json v("foo")); + next_construct_fails = true; + CHECK_THROWS_AS(my_json v("foo"), std::bad_alloc); + next_construct_fails = false; + } + + SECTION("basic_json(const typename string_t::value_type*)") + { + next_construct_fails = false; + std::string s("foo"); + CHECK_NOTHROW(my_json v(s)); + next_construct_fails = true; + CHECK_THROWS_AS(my_json v(s), std::bad_alloc); + next_construct_fails = false; + } } } diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 5cae3071..32a6ac8f 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -447,6 +447,10 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\\u").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\\u0").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\\u01").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\\u012").parse(), std::invalid_argument); CHECK_THROWS_WITH(json::parser("\"").parse(), "parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\\"").parse(), @@ -459,6 +463,14 @@ TEST_CASE("parser class") "parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\\u012\"").parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\\u").parse(), + "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\\u0").parse(), + "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\\u01").parse(), + "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\\u012").parse(), + "parse error - unexpected '\"'"); // invalid escapes for (int c = 1; c < 128; ++c)