From fc9b528ec9e48a1e02c861b527fe508aec5a4107 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Mar 2017 18:07:21 +0100 Subject: [PATCH] :hammer: changed an exception --- src/json.hpp | 15 +++---- src/json.hpp.re2c | 12 +++--- test/src/fuzzer-parse_json.cpp | 4 +- test/src/unit-cbor.cpp | 46 +++++++++----------- test/src/unit-msgpack.cpp | 30 +++++++------- test/src/unit-regression.cpp | 76 +++++++++++++++++++++++++--------- 6 files changed, 106 insertions(+), 77 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 68bb3cd70..ffe64d1a4 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7374,10 +7374,11 @@ class basic_json template static T get_from_vector(const std::vector& vec, const size_t current_index) { - if (current_index + sizeof(T) + 1 > vec.size()) - { - JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); - } + check_length(vec.size(), sizeof(T), current_index + 1); + //if (current_index + sizeof(T) + 1 > vec.size()) + //{ + // JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); + //} T result; auto* ptr = reinterpret_cast(&result); @@ -7926,19 +7927,19 @@ class basic_json // simple case: requested length is greater than the vector's length if (len > size or offset > size) { - JSON_THROW(std::out_of_range("len out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } // second case: adding offset would result in overflow if ((size > (std::numeric_limits::max() - offset))) { - JSON_THROW(std::out_of_range("len+offset out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } // last case: reading past the end of the vector if (len + offset > size) { - JSON_THROW(std::out_of_range("len+offset out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 60a1042cf..300a6219b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7374,10 +7374,8 @@ class basic_json template static T get_from_vector(const std::vector& vec, const size_t current_index) { - if (current_index + sizeof(T) + 1 > vec.size()) - { - JSON_THROW(parse_error(110, current_index + 1, "cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); - } + // check if we can read sizeof(T) bytes starting the next index + check_length(vec.size(), sizeof(T), current_index + 1); T result; auto* ptr = reinterpret_cast(&result); @@ -7926,19 +7924,19 @@ class basic_json // simple case: requested length is greater than the vector's length if (len > size or offset > size) { - JSON_THROW(std::out_of_range("len out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } // second case: adding offset would result in overflow if ((size > (std::numeric_limits::max() - offset))) { - JSON_THROW(std::out_of_range("len+offset out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } // last case: reading past the end of the vector if (len + offset > size) { - JSON_THROW(std::out_of_range("len+offset out of range")); + JSON_THROW(parse_error(110, offset + 1, "cannot read " + std::to_string(len) + " bytes from vector")); } } diff --git a/test/src/fuzzer-parse_json.cpp b/test/src/fuzzer-parse_json.cpp index bd2e5e391..ff5850665 100644 --- a/test/src/fuzzer-parse_json.cpp +++ b/test/src/fuzzer-parse_json.cpp @@ -49,13 +49,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // serializations must match assert(s1 == s2); } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parsing a JSON serialization must not fail assert(false); } } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes } diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 5667196a6..32464ae71 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1162,35 +1162,35 @@ TEST_CASE("CBOR") CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x18})), - "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x19})), - "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x19, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); } SECTION("unsupported bytes") @@ -1341,21 +1341,13 @@ TEST_CASE("CBOR regressions", "[!throws]") // deserializations must match CHECK(j1 == j2); } - catch (const std::invalid_argument&) + catch (const json::parse_error&) { // parsing a CBOR serialization must not fail CHECK(false); } } - catch (const std::invalid_argument&) - { - // parse errors are ok, because input may be random bytes - } - catch (const std::out_of_range&) - { - // parse errors are ok, because input may be random bytes - } - catch (const std::domain_error&) + catch (const json::parse_error&) { // parse errors are ok, because input may be random bytes } @@ -1365,7 +1357,9 @@ TEST_CASE("CBOR regressions", "[!throws]") SECTION("improve code coverage") { // exotic edge case - CHECK_THROWS_AS(json::check_length(0xffffffffffffffffull, 0xfffffffffffffff0ull, 0xff), std::out_of_range); + CHECK_THROWS_AS(json::check_length(0xffffffffffffffffull, 0xfffffffffffffff0ull, 0xff), json::parse_error); + CHECK_THROWS_WITH(json::check_length(0xffffffffffffffffull, 0xfffffffffffffff0ull, 0xff), + "[json.exception.parse_error.110] parse error at 256: cannot read 18446744073709551600 bytes from vector"); } } diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 04428dfff..de1a7bca4 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1038,35 +1038,35 @@ TEST_CASE("MessagePack") CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcc})), - "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcd})), - "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcd, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 2 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 4 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 1: cannot read 8 bytes from vector"); + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); } SECTION("unsupported bytes") diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 2d7990676..324ab769d 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -613,37 +613,51 @@ TEST_CASE("regression tests") { // original test case std::vector vec {0x65, 0xf5, 0x0a, 0x48, 0x21}; - CHECK_THROWS_AS(json::from_cbor(vec), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec), + "[json.exception.parse_error.110] parse error at 2: cannot read 5 bytes from vector"); } SECTION("issue #407 - Heap-buffer-overflow (OSS-Fuzz issue 343)") { // original test case: incomplete float64 std::vector vec1 {0xcb, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_msgpack(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(vec1), + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); // related test case: incomplete float32 std::vector vec2 {0xca, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_msgpack(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(vec2), + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); // related test case: incomplete Half-Precision Float (CBOR) std::vector vec3 {0xf9, 0x8f}; - CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec3), + "[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector"); // related test case: incomplete Single-Precision Float (CBOR) std::vector vec4 {0xfa, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_cbor(vec4), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec4), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec4), + "[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector"); // related test case: incomplete Double-Precision Float (CBOR) std::vector vec5 {0xfb, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_cbor(vec5), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec5), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec5), + "[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector"); } SECTION("issue #408 - Heap-buffer-overflow (OSS-Fuzz issue 344)") { // original test case std::vector vec1 {0x87}; - CHECK_THROWS_AS(json::from_msgpack(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(vec1), + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); // more test cases for MessagePack for (auto b : @@ -655,7 +669,7 @@ TEST_CASE("regression tests") }) { std::vector vec(1, static_cast(b)); - CHECK_THROWS_AS(json::from_msgpack(vec), std::out_of_range); + CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error); } // more test cases for CBOR @@ -670,28 +684,38 @@ TEST_CASE("regression tests") }) { std::vector vec(1, static_cast(b)); - CHECK_THROWS_AS(json::from_cbor(vec), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); } // special case: empty input std::vector vec2; - CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range); - CHECK_THROWS_AS(json::from_msgpack(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec2), + "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); + CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_msgpack(vec2), + "[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector"); } SECTION("issue #411 - Heap-buffer-overflow (OSS-Fuzz issue 366)") { // original test case: empty UTF-8 string (indefinite length) std::vector vec1 {0x7f}; - CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec1), + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); // related test case: empty array (indefinite length) std::vector vec2 {0x9f}; - CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec2), + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); // related test case: empty map (indefinite length) std::vector vec3 {0xbf}; - CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec3), + "[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector"); } SECTION("issue #412 - Heap-buffer-overflow (OSS-Fuzz issue 367)") @@ -717,19 +741,27 @@ TEST_CASE("regression tests") 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60 }; - CHECK_THROWS_AS(json::from_cbor(vec), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec), + "[json.exception.parse_error.110] parse error at 137: cannot read 1 bytes from vector"); // related test case: nonempty UTF-8 string (indefinite length) std::vector vec1 {0x7f, 0x61, 0x61}; - CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec1), + "[json.exception.parse_error.110] parse error at 4: cannot read 1 bytes from vector"); // related test case: nonempty array (indefinite length) std::vector vec2 {0x9f, 0x01}; - CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec2), + "[json.exception.parse_error.110] parse error at 3: cannot read 1 bytes from vector"); // related test case: nonempty map (indefinite length) std::vector vec3 {0xbf, 0x61, 0x61, 0x01}; - CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec3), + "[json.exception.parse_error.110] parse error at 5: cannot read 1 bytes from vector"); } SECTION("issue #414 - compare with literal 0)") @@ -762,7 +794,9 @@ TEST_CASE("regression tests") 0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfa }; - CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec1), + "[json.exception.parse_error.110] parse error at 49: cannot read 4 bytes from vector"); // related test case: double-precision std::vector vec2 @@ -774,7 +808,9 @@ TEST_CASE("regression tests") 0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfb }; - CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_WITH(json::from_cbor(vec2), + "[json.exception.parse_error.110] parse error at 49: cannot read 8 bytes from vector"); } SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)")