🚑 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.
pull/508/head
Niels Lohmann 2017-03-14 21:05:38 +01:00
parent bfe4788e32
commit b026591e9e
No known key found for this signature in database
GPG Key ID: 7F3CEA63AE251B69
4 changed files with 96 additions and 6 deletions

View File

@ -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
*/

View File

@ -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
*/

View File

@ -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&)
{

View File

@ -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);
}
}