[c++] Use RapidJSON's iterative parser
Use RapidJSON's iterative parser to handle deeply nested JSON data without causing a stack overflow. Added a unit test with a deeply nested JSON array to test this.
This commit is contained in:
Родитель
04a5cb5662
Коммит
e2f74ee413
|
@ -31,6 +31,8 @@ different versioning scheme, following the Haskell community's
|
|||
used as a template" have been fixed.
|
||||
[Issue #538](https://github.com/Microsoft/bond/issues/538)
|
||||
* Guard against overflows in OutputMemoryStream, blob, and SimpleArray.
|
||||
* Use RapidJSON's iterative parser to handle deeply nested JSON data without
|
||||
causing a stack overflow.
|
||||
|
||||
### C# ###
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "encoding.h"
|
||||
#include "detail/rapidjson_helper.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/reader.h"
|
||||
#include <boost/call_traits.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
|
@ -60,7 +62,10 @@ public:
|
|||
// Don't need to reparse for nested fields
|
||||
if (!_value || _value == _document.get())
|
||||
{
|
||||
_document->ParseStream<rapidjson::kParseStopWhenDoneFlag>(_stream);
|
||||
const unsigned parseFlags = rapidjson::kParseIterativeFlag | rapidjson::kParseStopWhenDoneFlag;
|
||||
|
||||
_document->ParseStream<parseFlags>(_stream);
|
||||
BOOST_ASSERT(!_document->HasParseError());
|
||||
_value = _document.get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "precompiled.h"
|
||||
#include "json_tests.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <locale>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
@ -187,10 +189,8 @@ TEST_CASE_END
|
|||
|
||||
|
||||
template <uint16_t N, typename Reader, typename Writer>
|
||||
void StringTests(const char* name)
|
||||
void StringTests(UnitTestSuite& suite)
|
||||
{
|
||||
UnitTestSuite suite(name);
|
||||
|
||||
AddTestCase<TEST_ID(N),
|
||||
StringRoundtripTest, Reader, Writer>(suite, "Roundtrip string/wstring");
|
||||
|
||||
|
@ -199,14 +199,38 @@ void StringTests(const char* name)
|
|||
}
|
||||
|
||||
|
||||
TEST_CASE_BEGIN(DeepNesting)
|
||||
{
|
||||
const size_t nestingDepth = 10000;
|
||||
|
||||
std::string listOpens(nestingDepth, '[');
|
||||
std::string listCloses(nestingDepth, ']');
|
||||
|
||||
std::string deeplyNestedList = boost::str(
|
||||
boost::format("{\"deeplyNestedList\": %strue%s}") % listOpens % listCloses);
|
||||
|
||||
bond::SimpleJsonReader<const char*> json_reader(deeplyNestedList.c_str());
|
||||
|
||||
// The type here doesn't really matter. We need something with no
|
||||
// required fields, as we're really just testing that we can parse a
|
||||
// deeply nested JSON array without crashing.
|
||||
SimpleStruct to;
|
||||
bond::Deserialize(json_reader, to);
|
||||
}
|
||||
TEST_CASE_END
|
||||
|
||||
void JSONTest::Initialize()
|
||||
{
|
||||
UnitTestSuite suite("Simple JSON test");
|
||||
|
||||
TEST_SIMPLE_JSON_PROTOCOL(
|
||||
StringTests<
|
||||
0x1c04,
|
||||
bond::SimpleJsonReader<bond::InputBuffer>,
|
||||
bond::SimpleJsonWriter<bond::OutputBuffer> >("Simple JSON test");
|
||||
bond::SimpleJsonWriter<bond::OutputBuffer> >(suite);
|
||||
);
|
||||
|
||||
AddTestCase<TEST_ID(0x1c05), DeepNesting>(suite, "Deeply nested JSON struct");
|
||||
}
|
||||
|
||||
bool init_unit_test()
|
||||
|
|
Загрузка…
Ссылка в новой задаче