From 925c1d77fcc72636924c3c13428a34180c30f96f Mon Sep 17 00:00:00 2001
From: Vladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com>
Date: Thu, 4 Oct 2018 23:27:37 +0700
Subject: [PATCH] =?UTF-8?q?Fix=20recursion=20counter=20check.=20Add=20cont?=
=?UTF-8?q?rol=20to=20override=20depth=20of=20nested=20=E2=80=A6=20(#4953)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Fix recursion counter check. Add control to override depth of nested objects.
* Change if-condition to `>=`
---
CMakeLists.txt | 6 ++++++
docs/source/Building.md | 8 ++++++++
docs/source/CppUsage.md | 9 +++++++++
include/flatbuffers/idl.h | 11 +++++++++--
src/idl_parser.cpp | 9 ++++++---
5 files changed, 38 insertions(+), 5 deletions(-)
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,