Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
R
rapidjson
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
rapidjson
Commits
1f53c6c0
Commit
1f53c6c0
authored
Jul 15, 2014
by
thebusytypist
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement stack size limitation for iterative parsing.
parent
46e89dad
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
71 additions
and
22 deletions
+71
-22
document.h
include/rapidjson/document.h
+27
-18
en.h
include/rapidjson/error/en.h
+1
-0
error.h
include/rapidjson/error/error.h
+2
-1
reader.h
include/rapidjson/reader.h
+29
-3
readertest.cpp
test/unittest/readertest.cpp
+12
-0
No files found.
include/rapidjson/document.h
View file @
1f53c6c0
...
...
@@ -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
);
}
//!@}
...
...
include/rapidjson/error/en.h
View file @
1f53c6c0
...
...
@@ -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."
);
...
...
include/rapidjson/error/error.h
View file @
1f53c6c0
...
...
@@ -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)
...
...
include/rapidjson/reader.h
View file @
1f53c6c0
...
...
@@ -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_
;
}
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
...
...
test/unittest/readertest.cpp
View file @
1f53c6c0
...
...
@@ -1288,6 +1288,18 @@ 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
(
2
,
r
.
Offset
());
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment