Remove stack size limit feature
It is not very useful for iterative parsing as the worst case of heap size is O(n) where n is number of character in JSON, for the worst synthetic cases. This is reasonable and should not create stack overflow security problem as in recursive parsing.
This commit is contained in:
parent
89865cb919
commit
e3e8fea0f3
@ -1221,13 +1221,12 @@ public:
|
||||
\tparam SourceEncoding Encoding of input stream
|
||||
\tparam InputStream Type of input stream, implementing Stream concept
|
||||
\param is Input stream to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
|
||||
GenericDocument& ParseStream(InputStream& is, size_t limit = 0) {
|
||||
GenericDocument& ParseStream(InputStream& is) {
|
||||
ValueType::SetNull(); // Remove existing root if exist
|
||||
GenericReader<SourceEncoding, Encoding, Allocator> reader(limit, &GetAllocator());
|
||||
GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());
|
||||
ClearStackOnExit scope(*this);
|
||||
parseResult_ = reader.template Parse<parseFlags>(is, *this);
|
||||
if (parseResult_) {
|
||||
@ -1241,23 +1240,21 @@ public:
|
||||
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
||||
\tparam InputStream Type of input stream, implementing Stream concept
|
||||
\param is Input stream to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <unsigned parseFlags, typename InputStream>
|
||||
GenericDocument& ParseStream(InputStream& is, size_t limit = 0) {
|
||||
return ParseStream<parseFlags,Encoding,InputStream>(is, limit);
|
||||
GenericDocument& ParseStream(InputStream& is) {
|
||||
return ParseStream<parseFlags,Encoding,InputStream>(is);
|
||||
}
|
||||
|
||||
//! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
|
||||
/*! \tparam InputStream Type of input stream, implementing Stream concept
|
||||
\param is Input stream to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <typename InputStream>
|
||||
GenericDocument& ParseStream(InputStream& is, size_t limit = 0) {
|
||||
return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is, limit);
|
||||
GenericDocument& ParseStream(InputStream& is) {
|
||||
return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
|
||||
}
|
||||
//!@}
|
||||
|
||||
@ -1268,33 +1265,30 @@ public:
|
||||
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
||||
\tparam SourceEncoding Transcoding from input Encoding
|
||||
\param str Mutable zero-terminated string to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <unsigned parseFlags, typename SourceEncoding>
|
||||
GenericDocument& ParseInsitu(Ch* str, size_t limit = 0) {
|
||||
GenericDocument& ParseInsitu(Ch* str) {
|
||||
GenericInsituStringStream<Encoding> s(str);
|
||||
return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(s, limit);
|
||||
return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(s);
|
||||
}
|
||||
|
||||
//! Parse JSON text from a mutable string
|
||||
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
||||
\param str Mutable zero-terminated string to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <unsigned parseFlags>
|
||||
GenericDocument& ParseInsitu(Ch* str, size_t limit = 0) {
|
||||
return ParseInsitu<parseFlags, Encoding>(str, limit);
|
||||
GenericDocument& ParseInsitu(Ch* str) {
|
||||
return ParseInsitu<parseFlags, Encoding>(str);
|
||||
}
|
||||
|
||||
//! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
|
||||
/*! \param str Mutable zero-terminated string to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
GenericDocument& ParseInsitu(Ch* str, size_t limit = 0) {
|
||||
return ParseInsitu<kParseDefaultFlags, Encoding>(str, limit);
|
||||
GenericDocument& ParseInsitu(Ch* str) {
|
||||
return ParseInsitu<kParseDefaultFlags, Encoding>(str);
|
||||
}
|
||||
//!@}
|
||||
|
||||
@ -1305,31 +1299,28 @@ public:
|
||||
/*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
|
||||
\tparam SourceEncoding Transcoding from input Encoding
|
||||
\param str Read-only zero-terminated string to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
*/
|
||||
template <unsigned parseFlags, typename SourceEncoding>
|
||||
GenericDocument& Parse(const Ch* str, size_t limit = 0) {
|
||||
GenericDocument& Parse(const Ch* str) {
|
||||
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
|
||||
GenericStringStream<SourceEncoding> s(str);
|
||||
return ParseStream<parseFlags, SourceEncoding>(s, limit);
|
||||
return ParseStream<parseFlags, SourceEncoding>(s);
|
||||
}
|
||||
|
||||
//! Parse JSON text from a read-only string
|
||||
/*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
|
||||
\param str Read-only zero-terminated string to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
*/
|
||||
template <unsigned parseFlags>
|
||||
GenericDocument& Parse(const Ch* str, size_t limit = 0) {
|
||||
return Parse<parseFlags, Encoding>(str, limit);
|
||||
GenericDocument& Parse(const Ch* str) {
|
||||
return Parse<parseFlags, Encoding>(str);
|
||||
}
|
||||
|
||||
//! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
|
||||
/*! \param str Read-only zero-terminated string to be parsed.
|
||||
\param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
*/
|
||||
GenericDocument& Parse(const Ch* str, size_t limit = 0) {
|
||||
return Parse<kParseDefaultFlags>(str, limit);
|
||||
GenericDocument& Parse(const Ch* str) {
|
||||
return Parse<kParseDefaultFlags>(str);
|
||||
}
|
||||
//!@}
|
||||
|
||||
|
@ -60,7 +60,6 @@ enum ParseErrorCode {
|
||||
|
||||
kParseErrorTermination, //!< Parsing was terminated.
|
||||
kParseErrorUnspecificSyntaxError, //!< Unspecific syntax error.
|
||||
kParseErrorStackSizeLimitExceeded //!< Parsing stack size limit is exceeded.
|
||||
};
|
||||
|
||||
//! Result of parsing (wraps ParseErrorCode)
|
||||
|
@ -273,11 +273,10 @@ public:
|
||||
typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
|
||||
|
||||
//! Constructor.
|
||||
/*! \param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
||||
\param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
||||
/*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
||||
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
|
||||
*/
|
||||
GenericReader(size_t limit = 0, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), kStackSizeLimit_(limit), parseResult_() {}
|
||||
GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {}
|
||||
|
||||
//! Parse JSON text.
|
||||
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
||||
@ -572,11 +571,6 @@ private:
|
||||
is.Take();
|
||||
Ch e = is.Take();
|
||||
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) {
|
||||
if (!(parseFlags & kParseInsituFlag)) {
|
||||
if (!CheckStackSpaceQuota(sizeof(Ch))) {
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorStackSizeLimitExceeded, is.Tell() - 1);
|
||||
}
|
||||
}
|
||||
os.Put(escape[(unsigned char)e]);
|
||||
}
|
||||
else if (e == 'u') { // Unicode
|
||||
@ -597,11 +591,6 @@ private:
|
||||
}
|
||||
else if (c == '"') { // Closing double quote
|
||||
is.Take();
|
||||
if (!(parseFlags & kParseInsituFlag)) {
|
||||
if (!CheckStackSpaceQuota(sizeof(Ch))) {
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorStackSizeLimitExceeded, is.Tell() - 1);
|
||||
}
|
||||
}
|
||||
os.Put('\0'); // null-terminate the string
|
||||
return;
|
||||
}
|
||||
@ -1059,11 +1048,6 @@ private:
|
||||
n = IterativeParsingElementState;
|
||||
else if (src == IterativeParsingKeyValueDelimiterState)
|
||||
n = IterativeParsingMemberValueState;
|
||||
// Check stack space limit.
|
||||
if (!CheckStackSpaceQuota(sizeof(IterativeParsingState) + sizeof(int))) {
|
||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStackSizeLimitExceeded, is.Tell());
|
||||
return IterativeParsingErrorState;
|
||||
}
|
||||
// Push current state.
|
||||
*stack_.template Push<IterativeParsingState>(1) = n;
|
||||
// Initialize and push the member/element count.
|
||||
@ -1235,13 +1219,8 @@ private:
|
||||
return parseResult_;
|
||||
}
|
||||
|
||||
bool CheckStackSpaceQuota(size_t size) const {
|
||||
return kStackSizeLimit_ == 0 || (stack_.GetSize() + size <= kStackSizeLimit_);
|
||||
}
|
||||
|
||||
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
|
||||
internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
|
||||
const size_t kStackSizeLimit_; //!< Stack size limit(in bytes). A value of 0 means no limit.
|
||||
ParseResult parseResult_;
|
||||
}; // class GenericReader
|
||||
|
||||
|
@ -932,18 +932,6 @@ TEST(Reader, IterativeParsing_ShortCircuit) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Reader, IterativeParsing_LimitStackSize) {
|
||||
BaseReaderHandler<> handler;
|
||||
Reader reader(20);
|
||||
StringStream is("[[[]]]");
|
||||
|
||||
ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
|
||||
|
||||
EXPECT_TRUE(reader.HasParseError());
|
||||
EXPECT_EQ(kParseErrorStackSizeLimitExceeded, r.Code());
|
||||
EXPECT_EQ(2u, r.Offset());
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user