[idl_parser] Unify parsing of NaN values read from .fbs and .json files (#6296)

This commit unifies parsing of NaN values read
from .fbs and .json files by converting them to unsigned NaN.
This commit is contained in:
Vladimir Glavnyy
2020-12-08 02:12:58 +07:00
committed by GitHub
parent 2046bffa40
commit 8d9eae9ac9
7 changed files with 55 additions and 8 deletions

View File

@@ -197,12 +197,17 @@ namespace flatbuffers {
#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \
defined(__clang__)
#define FLATBUFFERS_DEFAULT_DECLARATION
#define FLATBUFFERS_DELETE_FUNC(func) func = delete;
#else
#define FLATBUFFERS_DELETE_FUNC(func) private: func;
#endif
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
defined(__clang__)
#define FLATBUFFERS_DEFAULT_DECLARATION
#endif
// Check if we can use template aliases
// Not possible if Microsoft Compiler before 2012
// Possible is the language feature __cpp_alias_templates is defined well

View File

@@ -164,6 +164,8 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
using conditional = std::conditional<B, T, F>;
template<class T, T v>
using integral_constant = std::integral_constant<T, v>;
template <bool B>
using bool_constant = integral_constant<bool, B>;
#else
// Map C++ TR1 templates defined by stlport.
template <typename T> using is_scalar = std::tr1::is_scalar<T>;
@@ -187,6 +189,8 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
using conditional = std::tr1::conditional<B, T, F>;
template<class T, T v>
using integral_constant = std::tr1::integral_constant<T, v>;
template <bool B>
using bool_constant = integral_constant<bool, B>;
#endif // !FLATBUFFERS_CPP98_STL
#else
// MSVC 2010 doesn't support C++11 aliases.
@@ -201,6 +205,8 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
struct conditional : public std::conditional<B, T, F> {};
template<class T, T v>
struct integral_constant : public std::integral_constant<T, v> {};
template <bool B>
struct bool_constant : public integral_constant<bool, B> {};
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#ifndef FLATBUFFERS_CPP98_STL

View File

@@ -172,8 +172,21 @@ template<typename T> std::string TypeToIntervalString() {
// atot: template version of atoi/atof: convert a string to an instance of T.
template<typename T>
inline CheckedError atot(const char *s, Parser &parser, T *val) {
auto done = StringToNumber(s, val);
bool atot_scalar(const char *s, T *val, bool_constant<false>) {
return StringToNumber(s, val);
}
template<typename T>
bool atot_scalar(const char *s, T *val, bool_constant<true>) {
// Normalize NaN parsed from fbs or json to unsigned NaN.
if (false == StringToNumber(s, val)) return false;
*val = (*val != *val) ? std::fabs(*val) : *val;
return true;
}
template<typename T>
CheckedError atot(const char *s, Parser &parser, T *val) {
auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
if (done) return NoError();
if (0 == *val)
return parser.Error("invalid number: \"" + std::string(s) + "\"");
@@ -1806,7 +1819,6 @@ CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
match = true;
}
// Parse a float/integer number from the string.
if (!match) check_now = true; // Re-pack if parsed from string literal.
// A "scalar-in-string" value needs extra checks.
if (!match && is_tok_string && IsScalar(in_type)) {
// Strip trailing whitespaces from attribute_.

View File

@@ -139,6 +139,23 @@ target_link_libraries(monster_fuzzer PRIVATE flatbuffers_fuzzed)
# Build debugger for weird cases found with fuzzer.
if(BUILD_DEBUGGER)
add_library(flatbuffers_nonfuzz STATIC ${FlatBuffers_Library_SRCS})
target_compile_options(
flatbuffers_nonfuzz
PUBLIC
$<$<BOOL:${USE_ASAN}>:
-fsanitize=undefined,address
>
-fno-limit-debug-info
)
target_link_libraries(
flatbuffers_nonfuzz
PUBLIC
$<$<BOOL:${USE_ASAN}>:
-fsanitize=undefined,address
>
)
target_compile_definitions(
flatbuffers_nonfuzz
PUBLIC
@@ -147,6 +164,9 @@ if(BUILD_DEBUGGER)
PRIVATE
FLATBUFFERS_MAX_PARSING_DEPTH=${FLATBUFFERS_MAX_PARSING_DEPTH}
)
add_executable(scalar_debug flatbuffers_scalar_fuzzer.cc scalar_debug.cpp)
add_executable(scalar_debug
flatbuffers_scalar_fuzzer.cc
scalar_debug.cpp
)
target_link_libraries(scalar_debug PRIVATE flatbuffers_nonfuzz)
endif(BUILD_DEBUGGER)

View File

@@ -288,7 +288,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
// Parse original input as-is.
auto orig_scalar = "{ \"Y\" : " + input + " }";
auto orig_scalar = "{\"Y\" : " + input + "}";
std::string orig_back;
auto orig_done = Parse(parser, orig_scalar, &orig_back);
@@ -326,7 +326,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Test quoted version of the string
if (!qouted_input.empty()) {
auto fix_scalar = "{ \"Y\" : " + qouted_input + " }";
auto fix_scalar = "{\"Y\" : " + qouted_input + "}";
std::string fix_back;
auto fix_done = Parse(parser, fix_scalar, &fix_back);

View File

@@ -23,6 +23,6 @@ int main(int argc, char *argv[]) {
auto rc = LLVMFuzzerTestOneInput(
reinterpret_cast<const uint8_t *>(crash_file_data.data()),
crash_file_data.size());
std::cout << "LLVMFuzzerTestOneInput finished with code " << rc;
std::cout << "LLVMFuzzerTestOneInput finished with code " << rc << "\n\n";
return rc;
}

View File

@@ -17,7 +17,11 @@
"e"
"f"
"nan"
"-nan"
"+nan"
"inf"
"+inf"
"-inf"
"infinity"
"+infinity"
"-infinity"