diff --git a/CMakeLists.txt b/CMakeLists.txt index 76619dcbd..4a6b259fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,12 @@ if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS) set(FLATBUFFERS_BUILD_TESTS OFF) endif() +if(DEFINED FLATBUFFERS_MAX_PARSING_DEPTH) + # Override the default recursion depth limit. + add_definitions(-DFLATBUFFERS_MAX_PARSING_DEPTH=${FLATBUFFERS_MAX_PARSING_DEPTH}) + message(STATUS "FLATBUFFERS_MAX_PARSING_DEPTH: ${FLATBUFFERS_MAX_PARSING_DEPTH}") +endif() + set(FlatBuffers_Library_SRCS include/flatbuffers/code_generators.h include/flatbuffers/base.h diff --git a/docs/source/Building.md b/docs/source/Building.md index c2faddad2..a89671109 100644 --- a/docs/source/Building.md +++ b/docs/source/Building.md @@ -80,6 +80,14 @@ target_link_libraries(own_project_target PRIVATE flatbuffers) When build your project the `flatbuffers` library will be compiled and linked to a target as part of your project. +#### Override default depth limit of nested objects +To override [the depth limit of recursion](@ref flatbuffers_guide_use_cpp), +add this directive: +```cmake +set(FLATBUFFERS_MAX_PARSING_DEPTH 16) +``` +to `CMakeLists.txt` file before `add_subdirectory(${FLATBUFFERS_SRC_DIR})` line. + #### For Google Play apps For applications on Google Play that integrate this library, usage is tracked. diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index 983dc5ae6..fff04a9d9 100644 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -495,4 +495,13 @@ needed to use unions. To use scalars, simply wrap them in a struct. +## Depth limit of nested objects and stack-overflow control +The parser of Flatbuffers schema or json-files is kind of recursive parser. +To avoid stack-overflow problem the parser has a built-in limiter of recursion depth. +Number of nested declarations in a schema or number of nested json-objects is limited. +By default, this depth limit set to `64`. +It is possible to override this limit with `FLATBUFFERS_MAX_PARSING_DEPTH` definition. +This definition can be helpful for testing purposes or embedded applications. +For details see [build](@ref flatbuffers_guide_building) of CMake-based projects. +
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 63446247d..cf5446a2d 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -34,6 +34,12 @@ // This file defines the data types representing a parsed IDL (Interface // Definition Language) / schema file. +// Limits maximum depth of nested objects. +// Prevents stack overflow while parse flatbuffers or json. +#if !defined(FLATBUFFERS_MAX_PARSING_DEPTH) +# define FLATBUFFERS_MAX_PARSING_DEPTH 64 +#endif + namespace flatbuffers { // The order of these matters for Is*() functions below. @@ -745,10 +751,11 @@ class Parser : public ParserState { bool SupportsVectorOfUnions() const; Namespace *UniqueNamespace(Namespace *ns); - enum { kMaxParsingDepth = 64 }; FLATBUFFERS_CHECKED_ERROR RecurseError(); template CheckedError Recurse(F f) { - if (++recurse_protection_counter >= kMaxParsingDepth) return RecurseError(); + if (recurse_protection_counter >= (FLATBUFFERS_MAX_PARSING_DEPTH)) + return RecurseError(); + recurse_protection_counter++; auto ce = f(); recurse_protection_counter--; return ce; diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 518ef7b82..e686f628f 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -115,8 +115,8 @@ CheckedError Parser::Error(const std::string &msg) { inline CheckedError NoError() { return CheckedError(false); } CheckedError Parser::RecurseError() { - return Error("maximum parsing recursion of " + NumToString(kMaxParsingDepth) + - " reached"); + return Error("maximum parsing recursion of " + + NumToString(FLATBUFFERS_MAX_PARSING_DEPTH) + " reached"); } inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op, @@ -2254,7 +2254,10 @@ bool Parser::ParseFlexBuffer(const char *source, const char *source_filename, bool Parser::Parse(const char *source, const char **include_paths, const char *source_filename) { - return !ParseRoot(source, include_paths, source_filename).Check(); + FLATBUFFERS_ASSERT(0 == recurse_protection_counter); + auto r = !ParseRoot(source, include_paths, source_filename).Check(); + FLATBUFFERS_ASSERT(0 == recurse_protection_counter); + return r; } CheckedError Parser::StartParseFile(const char *source,