2828#pragma warning(disable : 4996)
2929#endif
3030
31+ static int const stackLimit_g = 1000 ;
32+ static int stackDepth_g = 0 ; // see readValue()
33+
3134namespace Json {
3235
3336#if __cplusplus >= 201103L
@@ -118,6 +121,7 @@ bool Reader::parse(const char* beginDoc,
118121 nodes_.pop ();
119122 nodes_.push (&root);
120123
124+ stackDepth_g = 0 ; // Yes, this is bad coding, but options are limited.
121125 bool successful = readValue ();
122126 Token token;
123127 skipCommentTokens (token);
@@ -140,6 +144,13 @@ bool Reader::parse(const char* beginDoc,
140144}
141145
142146bool Reader::readValue () {
147+ // This is a non-reentrant way to support a stackLimit. Terrible!
148+ // But this deprecated class has a security problem: Bad input can
149+ // cause a seg-fault. This seems like a fair, binary-compatible way
150+ // to prevent the problem.
151+ if (stackDepth_g >= stackLimit_g) throw std::runtime_error (" Exceeded stackLimit in readValue()." );
152+ ++stackDepth_g;
153+
143154 Token token;
144155 skipCommentTokens (token);
145156 bool successful = true ;
@@ -211,6 +222,7 @@ bool Reader::readValue() {
211222 lastValue_ = ¤tValue ();
212223 }
213224
225+ --stackDepth_g;
214226 return successful;
215227}
216228
@@ -902,7 +914,8 @@ class OurFeatures {
902914 bool strictRoot_;
903915 bool allowDroppedNullPlaceholders_;
904916 bool allowNumericKeys_;
905- }; // OldFeatures
917+ int stackLimit_;
918+ }; // OurFeatures
906919
907920// exact copy of Implementation of class Features
908921// ////////////////////////////////
@@ -1033,7 +1046,9 @@ class OurReader {
10331046 Location lastValueEnd_;
10341047 Value* lastValue_;
10351048 std::string commentsBefore_;
1036- OurFeatures features_;
1049+ int stackDepth_;
1050+
1051+ OurFeatures const features_;
10371052 bool collectComments_;
10381053}; // OurReader
10391054
@@ -1064,6 +1079,7 @@ bool OurReader::parse(const char* beginDoc,
10641079 nodes_.pop ();
10651080 nodes_.push (&root);
10661081
1082+ stackDepth_ = 0 ;
10671083 bool successful = readValue ();
10681084 Token token;
10691085 skipCommentTokens (token);
@@ -1086,6 +1102,8 @@ bool OurReader::parse(const char* beginDoc,
10861102}
10871103
10881104bool OurReader::readValue () {
1105+ if (stackDepth_ >= features_.stackLimit_ ) throw std::runtime_error (" Exceeded stackLimit in readValue()." );
1106+ ++stackDepth_;
10891107 Token token;
10901108 skipCommentTokens (token);
10911109 bool successful = true ;
@@ -1157,6 +1175,7 @@ bool OurReader::readValue() {
11571175 lastValue_ = ¤tValue ();
11581176 }
11591177
1178+ --stackDepth_;
11601179 return successful;
11611180}
11621181
@@ -1853,6 +1872,7 @@ CharReader* CharReaderBuilder::newCharReader() const
18531872 features.strictRoot_ = settings_[" strictRoot" ].asBool ();
18541873 features.allowDroppedNullPlaceholders_ = settings_[" allowDroppedNullPlaceholders" ].asBool ();
18551874 features.allowNumericKeys_ = settings_[" allowNumericKeys" ].asBool ();
1875+ features.stackLimit_ = settings_[" stackLimit" ].asInt ();
18561876 return new OurCharReader (collectComments, features);
18571877}
18581878static void getValidReaderKeys (std::set<std::string>* valid_keys)
@@ -1863,6 +1883,7 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
18631883 valid_keys->insert (" strictRoot" );
18641884 valid_keys->insert (" allowDroppedNullPlaceholders" );
18651885 valid_keys->insert (" allowNumericKeys" );
1886+ valid_keys->insert (" stackLimit" );
18661887}
18671888bool CharReaderBuilder::validate (Json::Value* invalid) const
18681889{
@@ -1901,6 +1922,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
19011922 (*settings)[" strictRoot" ] = false ;
19021923 (*settings)[" allowDroppedNullPlaceholders" ] = false ;
19031924 (*settings)[" allowNumericKeys" ] = false ;
1925+ (*settings)[" stackLimit" ] = 1000 ;
19041926// ! [CharReaderBuilderDefaults]
19051927}
19061928
0 commit comments