Add files via upload

Removed a static variable used to contain the current recursion depth of Reader::readValue().  The number of elements in an internal container Reader::nodes_  is used instead.  It is correct because any recursive call of Reader::readValue() is executed with adjacent nodes_.push()  and nodes_.pop() calls.  
Added the option to change the allowed recursion depth at compile time by defining a macro JSONCPP_STACK_LIMIT as the required integer value.
This commit is contained in:
nnkur 2016-11-30 18:30:12 +03:00 committed by GitHub
parent 77632b2611
commit 2ecd2a59de

View File

@ -1,4 +1,5 @@
// Copyright 2007-2011 Baptiste Lepilleur // Copyright 2007-2011 Baptiste Lepilleur
// Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
// Distributed under MIT license, or public domain if desired and // Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction. // recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
@ -44,13 +45,13 @@
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
#endif #endif
static int const stackLimit_g = 1000; // Define JSONCPP_STACK_LIMIT as an appropriate integer at compile time to change the stack limit
#if __cplusplus >= 201103L #if !defined(JSONCPP_STACK_LIMIT)
thread_local static int stackDepth_g = 0; // see readValue() #define JSONCPP_STACK_LIMIT 1000
#else
static int stackDepth_g = 0; // see readValue()
#endif #endif
static size_t const stackLimit_g = JSONCPP_STACK_LIMIT; // see readValue()
namespace Json { namespace Json {
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
@ -142,7 +143,6 @@ bool Reader::parse(const char* beginDoc,
nodes_.pop(); nodes_.pop();
nodes_.push(&root); nodes_.push(&root);
stackDepth_g = 0; // Yes, this is bad coding, but options are limited.
bool successful = readValue(); bool successful = readValue();
Token token; Token token;
skipCommentTokens(token); skipCommentTokens(token);
@ -165,12 +165,10 @@ bool Reader::parse(const char* beginDoc,
} }
bool Reader::readValue() { bool Reader::readValue() {
// This is a non-reentrant way to support a stackLimit. Terrible! // readValue() may call itself only if it calls readObject() or ReadArray().
// But this deprecated class has a security problem: Bad input can // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue().
// cause a seg-fault. This seems like a fair, binary-compatible way // parse() executes one nodes_.push(), so > instead of >=.
// to prevent the problem. if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
++stackDepth_g;
Token token; Token token;
skipCommentTokens(token); skipCommentTokens(token);
@ -244,7 +242,6 @@ bool Reader::readValue() {
lastValue_ = &currentValue(); lastValue_ = &currentValue();
} }
--stackDepth_g;
return successful; return successful;
} }
@ -1032,7 +1029,6 @@ private:
Location lastValueEnd_; Location lastValueEnd_;
Value* lastValue_; Value* lastValue_;
JSONCPP_STRING commentsBefore_; JSONCPP_STRING commentsBefore_;
int stackDepth_;
OurFeatures const features_; OurFeatures const features_;
bool collectComments_; bool collectComments_;
@ -1043,7 +1039,6 @@ private:
OurReader::OurReader(OurFeatures const& features) OurReader::OurReader(OurFeatures const& features)
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
lastValue_(), commentsBefore_(), lastValue_(), commentsBefore_(),
stackDepth_(0),
features_(features), collectComments_() { features_(features), collectComments_() {
} }
@ -1067,7 +1062,6 @@ bool OurReader::parse(const char* beginDoc,
nodes_.pop(); nodes_.pop();
nodes_.push(&root); nodes_.push(&root);
stackDepth_ = 0;
bool successful = readValue(); bool successful = readValue();
Token token; Token token;
skipCommentTokens(token); skipCommentTokens(token);
@ -1096,8 +1090,8 @@ bool OurReader::parse(const char* beginDoc,
} }
bool OurReader::readValue() { bool OurReader::readValue() {
if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); // To preserve the old behaviour we cast size_t to int.
++stackDepth_; if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
Token token; Token token;
skipCommentTokens(token); skipCommentTokens(token);
bool successful = true; bool successful = true;
@ -1194,7 +1188,6 @@ bool OurReader::readValue() {
lastValue_ = &currentValue(); lastValue_ = &currentValue();
} }
--stackDepth_;
return successful; return successful;
} }