28
28
#pragma warning(disable : 4996)
29
29
#endif
30
30
31
+ static int const stackLimit_g = 1000 ;
32
+ static int stackDepth_g = 0 ; // see readValue()
33
+
31
34
namespace Json {
32
35
33
36
#if __cplusplus >= 201103L
@@ -118,6 +121,7 @@ bool Reader::parse(const char* beginDoc,
118
121
nodes_.pop ();
119
122
nodes_.push (&root);
120
123
124
+ stackDepth_g = 0 ; // Yes, this is bad coding, but options are limited.
121
125
bool successful = readValue ();
122
126
Token token;
123
127
skipCommentTokens (token);
@@ -140,6 +144,13 @@ bool Reader::parse(const char* beginDoc,
140
144
}
141
145
142
146
bool 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
+
143
154
Token token;
144
155
skipCommentTokens (token);
145
156
bool successful = true ;
@@ -211,6 +222,7 @@ bool Reader::readValue() {
211
222
lastValue_ = ¤tValue ();
212
223
}
213
224
225
+ --stackDepth_g;
214
226
return successful;
215
227
}
216
228
@@ -902,7 +914,8 @@ class OurFeatures {
902
914
bool strictRoot_;
903
915
bool allowDroppedNullPlaceholders_;
904
916
bool allowNumericKeys_;
905
- }; // OldFeatures
917
+ int stackLimit_;
918
+ }; // OurFeatures
906
919
907
920
// exact copy of Implementation of class Features
908
921
// ////////////////////////////////
@@ -1033,7 +1046,9 @@ class OurReader {
1033
1046
Location lastValueEnd_;
1034
1047
Value* lastValue_;
1035
1048
std::string commentsBefore_;
1036
- OurFeatures features_;
1049
+ int stackDepth_;
1050
+
1051
+ OurFeatures const features_;
1037
1052
bool collectComments_;
1038
1053
}; // OurReader
1039
1054
@@ -1064,6 +1079,7 @@ bool OurReader::parse(const char* beginDoc,
1064
1079
nodes_.pop ();
1065
1080
nodes_.push (&root);
1066
1081
1082
+ stackDepth_ = 0 ;
1067
1083
bool successful = readValue ();
1068
1084
Token token;
1069
1085
skipCommentTokens (token);
@@ -1086,6 +1102,8 @@ bool OurReader::parse(const char* beginDoc,
1086
1102
}
1087
1103
1088
1104
bool OurReader::readValue () {
1105
+ if (stackDepth_ >= features_.stackLimit_ ) throw std::runtime_error (" Exceeded stackLimit in readValue()." );
1106
+ ++stackDepth_;
1089
1107
Token token;
1090
1108
skipCommentTokens (token);
1091
1109
bool successful = true ;
@@ -1157,6 +1175,7 @@ bool OurReader::readValue() {
1157
1175
lastValue_ = ¤tValue ();
1158
1176
}
1159
1177
1178
+ --stackDepth_;
1160
1179
return successful;
1161
1180
}
1162
1181
@@ -1853,6 +1872,7 @@ CharReader* CharReaderBuilder::newCharReader() const
1853
1872
features.strictRoot_ = settings_[" strictRoot" ].asBool ();
1854
1873
features.allowDroppedNullPlaceholders_ = settings_[" allowDroppedNullPlaceholders" ].asBool ();
1855
1874
features.allowNumericKeys_ = settings_[" allowNumericKeys" ].asBool ();
1875
+ features.stackLimit_ = settings_[" stackLimit" ].asInt ();
1856
1876
return new OurCharReader (collectComments, features);
1857
1877
}
1858
1878
static void getValidReaderKeys (std::set<std::string>* valid_keys)
@@ -1863,6 +1883,7 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
1863
1883
valid_keys->insert (" strictRoot" );
1864
1884
valid_keys->insert (" allowDroppedNullPlaceholders" );
1865
1885
valid_keys->insert (" allowNumericKeys" );
1886
+ valid_keys->insert (" stackLimit" );
1866
1887
}
1867
1888
bool CharReaderBuilder::validate (Json::Value* invalid) const
1868
1889
{
@@ -1901,6 +1922,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
1901
1922
(*settings)[" strictRoot" ] = false ;
1902
1923
(*settings)[" allowDroppedNullPlaceholders" ] = false ;
1903
1924
(*settings)[" allowNumericKeys" ] = false ;
1925
+ (*settings)[" stackLimit" ] = 1000 ;
1904
1926
// ! [CharReaderBuilderDefaults]
1905
1927
}
1906
1928
0 commit comments