Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/miloyip/rapidjson.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthebusytypist <ounanding@gmail.com>2014-07-15 10:16:06 +0400
committerthebusytypist <ounanding@gmail.com>2014-07-15 10:16:06 +0400
commit1f53c6c041eee6321eb18b5dc7f685f80cd62599 (patch)
tree6dfa781f9b8c29888da964297c0ea78c835108b2 /include
parent46e89dad0d973e6dbda335b7f18b599042f6ba5b (diff)
Implement stack size limitation for iterative parsing.
Diffstat (limited to 'include')
-rw-r--r--include/rapidjson/document.h45
-rw-r--r--include/rapidjson/error/en.h1
-rw-r--r--include/rapidjson/error/error.h3
-rw-r--r--include/rapidjson/reader.h34
4 files changed, 60 insertions, 23 deletions
diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h
index 4448600b..d94cd623 100644
--- a/include/rapidjson/document.h
+++ b/include/rapidjson/document.h
@@ -1221,12 +1221,13 @@ 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) {
+ GenericDocument& ParseStream(InputStream& is, size_t limit = 0) {
ValueType::SetNull(); // Remove existing root if exist
- GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());
+ GenericReader<SourceEncoding, Encoding, Allocator> reader(limit, &GetAllocator());
ClearStackOnExit scope(*this);
parseResult_ = reader.template Parse<parseFlags>(is, *this);
if (parseResult_) {
@@ -1240,21 +1241,23 @@ 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) {
- return ParseStream<parseFlags,Encoding,InputStream>(is);
+ GenericDocument& ParseStream(InputStream& is, size_t limit = 0) {
+ return ParseStream<parseFlags,Encoding,InputStream>(is, limit);
}
//! 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) {
- return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
+ GenericDocument& ParseStream(InputStream& is, size_t limit = 0) {
+ return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is, limit);
}
//!@}
@@ -1265,30 +1268,33 @@ 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) {
+ GenericDocument& ParseInsitu(Ch* str, size_t limit = 0) {
GenericInsituStringStream<Encoding> s(str);
- return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(s);
+ return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(s, limit);
}
//! 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) {
- return ParseInsitu<parseFlags, Encoding>(str);
+ GenericDocument& ParseInsitu(Ch* str, size_t limit = 0) {
+ return ParseInsitu<parseFlags, Encoding>(str, limit);
}
//! 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) {
- return ParseInsitu<kParseDefaultFlags, Encoding>(str);
+ GenericDocument& ParseInsitu(Ch* str, size_t limit = 0) {
+ return ParseInsitu<kParseDefaultFlags, Encoding>(str, limit);
}
//!@}
@@ -1299,28 +1305,31 @@ 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) {
+ GenericDocument& Parse(const Ch* str, size_t limit = 0) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<SourceEncoding> s(str);
- return ParseStream<parseFlags, SourceEncoding>(s);
+ return ParseStream<parseFlags, SourceEncoding>(s, limit);
}
//! 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) {
- return Parse<parseFlags, Encoding>(str);
+ GenericDocument& Parse(const Ch* str, size_t limit = 0) {
+ return Parse<parseFlags, Encoding>(str, limit);
}
//! 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) {
- return Parse<kParseDefaultFlags>(str);
+ GenericDocument& Parse(const Ch* str, size_t limit = 0) {
+ return Parse<kParseDefaultFlags>(str, limit);
}
//!@}
diff --git a/include/rapidjson/error/en.h b/include/rapidjson/error/en.h
index e9120c5b..e9a5d1d3 100644
--- a/include/rapidjson/error/en.h
+++ b/include/rapidjson/error/en.h
@@ -40,6 +40,7 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
+ case kParseErrorStackSizeLimitExceeded: return RAPIDJSON_ERROR_STRING("Parsing stack size limit is exceeded.");
default:
return RAPIDJSON_ERROR_STRING("Unknown error.");
diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h
index e5c2b1b4..a47dfaaf 100644
--- a/include/rapidjson/error/error.h
+++ b/include/rapidjson/error/error.h
@@ -59,7 +59,8 @@ enum ParseErrorCode {
kParseErrorNumberMissExponent, //!< Miss exponent in number.
kParseErrorTermination, //!< Parsing was terminated.
- kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
+ kParseErrorUnspecificSyntaxError, //!< Unspecific syntax error.
+ kParseErrorStackSizeLimitExceeded //!< Parsing stack size limit is exceeded.
};
//! Result of parsing (wraps ParseErrorCode)
diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h
index bdfd826a..95a29961 100644
--- a/include/rapidjson/reader.h
+++ b/include/rapidjson/reader.h
@@ -272,10 +272,11 @@ public:
typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
//! Constructor.
- /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
+ /*! \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 stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
*/
- GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {}
+ GenericReader(size_t limit = 0, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), kStackSizeLimit(limit), parseResult_() {}
//! Parse JSON text.
/*! \tparam parseFlags Combination of \ref ParseFlag.
@@ -569,8 +570,14 @@ private:
if (c == '\\') { // Escape
is.Take();
Ch e = is.Take();
- if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e])
+ if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) {
+ if (!(parseFlags & kParseInsituFlag)) {
+ if (!IsStackSpaceSufficient<Ch>(1)) {
+ RAPIDJSON_PARSE_ERROR(kParseErrorStackSizeLimitExceeded, is.Tell() - 1);
+ }
+ }
os.Put(escape[(unsigned char)e]);
+ }
else if (e == 'u') { // Unicode
unsigned codepoint = ParseHex4(is);
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
@@ -589,6 +596,11 @@ private:
}
else if (c == '"') { // Closing double quote
is.Take();
+ if (!(parseFlags & kParseInsituFlag)) {
+ if (!IsStackSpaceSufficient<Ch>(1)) {
+ RAPIDJSON_PARSE_ERROR(kParseErrorStackSizeLimitExceeded, is.Tell() - 1);
+ }
+ }
os.Put('\0'); // null-terminate the string
return;
}
@@ -1038,8 +1050,16 @@ private:
else if (src == IterativeParsingKeyValueDelimiterState)
n = IterativeParsingMemberValueState;
// Push current state.
+ if (!IsStackSpaceSufficient<IterativeParsingState>(1)) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStackSizeLimitExceeded, is.Tell());
+ return IterativeParsingErrorState;
+ }
*stack_.template Push<IterativeParsingState>(1) = n;
// Initialize and push the member/element count.
+ if (!IsStackSpaceSufficient<int>(1)) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStackSizeLimitExceeded, is.Tell());
+ return IterativeParsingErrorState;
+ }
*stack_.template Push<int>(1) = 0;
// Call handler
if (dst == IterativeParsingObjectInitialState)
@@ -1206,7 +1226,13 @@ private:
return parseResult_;
}
- static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
+ template <typename T>
+ bool IsStackSpaceSufficient(size_t count) const {
+ return kStackSizeLimit == 0 || (stack_.GetSize() + sizeof(T) * count <= kStackSizeLimit);
+ }
+
+ static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
+ const size_t kStackSizeLimit; //!< Stack size limit(in bytes). A value of 0 means no limit.
internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
ParseResult parseResult_;
}; // class GenericReader