🚑 added special case to fuzzers to fix #504
Since #329, NaN and inf numbers do not yield an exception, but are stored internally and are dumped as “null”. This commit adjusts the fuzz testers to deal with this special case.
This commit is contained in:
parent
bfe4788e32
commit
b026591e9e
4 changed files with 96 additions and 6 deletions
39
src/json.hpp
39
src/json.hpp
|
@ -174,6 +174,7 @@ json.exception.parse_error.109 | parse error: array index 'one' is not a number
|
|||
json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
|
||||
json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set.
|
||||
json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
|
||||
json.exception.parse_error.113 | | While parsing a map key, a value that is not a string has been read.
|
||||
|
||||
@since version 3.0.0
|
||||
*/
|
||||
|
@ -8020,7 +8021,7 @@ class basic_json
|
|||
@param[in] v MessagePack serialization
|
||||
@param[in] idx byte index in @a v to check for a string
|
||||
|
||||
@throw std::invalid_argument if `v[idx]` does not belong to a string
|
||||
@throw parse_error.113 if `v[idx]` does not belong to a string
|
||||
*/
|
||||
static void msgpack_expect_string(const std::vector<uint8_t>& v, size_t idx)
|
||||
{
|
||||
|
@ -8032,7 +8033,39 @@ class basic_json
|
|||
return;
|
||||
}
|
||||
|
||||
JSON_THROW(std::invalid_argument("error parsing a msgpack string @ " + std::to_string(idx) + ": " + std::to_string(static_cast<int>(v[idx]))));
|
||||
std::stringstream ss;
|
||||
ss << std::hex << static_cast<int>(v[idx]);
|
||||
JSON_THROW(parse_error(113, idx + 1, "expected a MessagePack string; last byte: 0x" + ss.str()));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief check if the next byte belongs to a string
|
||||
|
||||
While parsing a map, the keys must be strings. This function checks if the
|
||||
current byte is one of the start bytes for a string in CBOR:
|
||||
|
||||
- 0x60 - 0x77: fixed length
|
||||
- 0x78 - 0x7b: variable length
|
||||
- 0x7f: indefinity length
|
||||
|
||||
@param[in] v CBOR serialization
|
||||
@param[in] idx byte index in @a v to check for a string
|
||||
|
||||
@throw parse_error.113 if `v[idx]` does not belong to a string
|
||||
*/
|
||||
static void cbor_expect_string(const std::vector<uint8_t>& v, size_t idx)
|
||||
{
|
||||
check_length(v.size(), 1, idx);
|
||||
|
||||
const auto byte = v[idx];
|
||||
if ((byte >= 0x60 and byte <= 0x7b) or byte == 0x7f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::hex << static_cast<int>(v[idx]);
|
||||
JSON_THROW(parse_error(113, idx + 1, "expected a CBOR string; last byte: 0x" + ss.str()));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -8046,6 +8079,7 @@ class basic_json
|
|||
@throw parse_error.110 if the given vector ends prematurely
|
||||
@throw parse_error.112 if unsupported features from MessagePack were
|
||||
used in the given vector @a v or if the input is not valid MessagePack
|
||||
@throw parse_error.113 if a string was expected as map key, but not found
|
||||
|
||||
@sa https://github.com/msgpack/msgpack/blob/master/spec.md
|
||||
*/
|
||||
|
@ -8291,6 +8325,7 @@ class basic_json
|
|||
@throw parse_error.110 if the given vector ends prematurely
|
||||
@throw parse_error.112 if unsupported features from CBOR were
|
||||
used in the given vector @a v or if the input is not valid CBOR
|
||||
@throw parse_error.113 if a string was expected as map key, but not found
|
||||
|
||||
@sa https://tools.ietf.org/html/rfc7049
|
||||
*/
|
||||
|
|
|
@ -174,6 +174,7 @@ json.exception.parse_error.109 | parse error: array index 'one' is not a number
|
|||
json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
|
||||
json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set.
|
||||
json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
|
||||
json.exception.parse_error.113 | | While parsing a map key, a value that is not a string has been read.
|
||||
|
||||
@since version 3.0.0
|
||||
*/
|
||||
|
@ -8020,7 +8021,7 @@ class basic_json
|
|||
@param[in] v MessagePack serialization
|
||||
@param[in] idx byte index in @a v to check for a string
|
||||
|
||||
@throw std::invalid_argument if `v[idx]` does not belong to a string
|
||||
@throw parse_error.113 if `v[idx]` does not belong to a string
|
||||
*/
|
||||
static void msgpack_expect_string(const std::vector<uint8_t>& v, size_t idx)
|
||||
{
|
||||
|
@ -8032,7 +8033,39 @@ class basic_json
|
|||
return;
|
||||
}
|
||||
|
||||
JSON_THROW(std::invalid_argument("error parsing a msgpack string @ " + std::to_string(idx) + ": " + std::to_string(static_cast<int>(v[idx]))));
|
||||
std::stringstream ss;
|
||||
ss << std::hex << static_cast<int>(v[idx]);
|
||||
JSON_THROW(parse_error(113, idx + 1, "expected a MessagePack string; last byte: 0x" + ss.str()));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief check if the next byte belongs to a string
|
||||
|
||||
While parsing a map, the keys must be strings. This function checks if the
|
||||
current byte is one of the start bytes for a string in CBOR:
|
||||
|
||||
- 0x60 - 0x77: fixed length
|
||||
- 0x78 - 0x7b: variable length
|
||||
- 0x7f: indefinity length
|
||||
|
||||
@param[in] v CBOR serialization
|
||||
@param[in] idx byte index in @a v to check for a string
|
||||
|
||||
@throw parse_error.113 if `v[idx]` does not belong to a string
|
||||
*/
|
||||
static void cbor_expect_string(const std::vector<uint8_t>& v, size_t idx)
|
||||
{
|
||||
check_length(v.size(), 1, idx);
|
||||
|
||||
const auto byte = v[idx];
|
||||
if ((byte >= 0x60 and byte <= 0x7b) or byte == 0x7f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::hex << static_cast<int>(v[idx]);
|
||||
JSON_THROW(parse_error(113, idx + 1, "expected a CBOR string; last byte: 0x" + ss.str()));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -8046,6 +8079,7 @@ class basic_json
|
|||
@throw parse_error.110 if the given vector ends prematurely
|
||||
@throw parse_error.112 if unsupported features from MessagePack were
|
||||
used in the given vector @a v or if the input is not valid MessagePack
|
||||
@throw parse_error.113 if a string was expected as map key, but not found
|
||||
|
||||
@sa https://github.com/msgpack/msgpack/blob/master/spec.md
|
||||
*/
|
||||
|
@ -8291,6 +8325,7 @@ class basic_json
|
|||
@throw parse_error.110 if the given vector ends prematurely
|
||||
@throw parse_error.112 if unsupported features from CBOR were
|
||||
used in the given vector @a v or if the input is not valid CBOR
|
||||
@throw parse_error.113 if a string was expected as map key, but not found
|
||||
|
||||
@sa https://tools.ietf.org/html/rfc7049
|
||||
*/
|
||||
|
|
|
@ -41,8 +41,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||
// parse serialization
|
||||
json j2 = json::from_cbor(vec2);
|
||||
|
||||
// deserializations must match
|
||||
assert(j1 == j2);
|
||||
// serializations must match
|
||||
assert(json::to_cbor(j2) == vec2);
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
|
|
|
@ -909,4 +909,24 @@ TEST_CASE("regression tests")
|
|||
|
||||
CHECK(j["bool_vector"].dump() == "[false,true,false,false]");
|
||||
}
|
||||
|
||||
SECTION("issue #504 - assertion error (OSS-Fuzz 856)")
|
||||
{
|
||||
std::vector<uint8_t> vec1 = {0xf9, 0xff, 0xff, 0x4a, 0x3a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x37, 0x02, 0x38};
|
||||
json j1 = json::from_cbor(vec1);
|
||||
|
||||
// step 2: round trip
|
||||
std::vector<uint8_t> vec2 = json::to_cbor(j1);
|
||||
|
||||
// parse serialization
|
||||
json j2 = json::from_cbor(vec2);
|
||||
|
||||
// NaN is dumped to "null"
|
||||
CHECK(j2.is_number_float());
|
||||
CHECK(std::isnan(j2.get<json::number_float_t>()));
|
||||
CHECK(j2.dump() == "null");
|
||||
|
||||
// check if serializations match
|
||||
CHECK(json::to_cbor(j2) == vec2);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue