return opts_;
}
-private:
+ void incrementRecursionLevel() {
+ if (currentRecursionLevel_ > opts_.recursion_limit) {
+ error("recursion limit exceeded");
+ }
+ currentRecursionLevel_++;
+ }
+
+ void decrementRecursionLevel() {
+ currentRecursionLevel_--;
+ }
+
+ private:
void storeCurrent() {
current_ = range_.empty() ? EOF : range_.front();
}
json::serialization_opts const& opts_;
unsigned lineNum_;
int current_;
+ unsigned int currentRecursionLevel_{0};
+};
+
+class RecursionGuard {
+ public:
+ explicit RecursionGuard(Input& in) : in_(in) {
+ in_.incrementRecursionLevel();
+ }
+
+ ~RecursionGuard() {
+ in_.decrementRecursionLevel();
+ }
+
+ private:
+ Input& in_;
};
dynamic parseValue(Input& in);
}
dynamic parseValue(Input& in) {
+ RecursionGuard guard(in);
+
in.skipWhitespace();
return *in == '[' ? parseArray(in) :
*in == '{' ? parseObject(in) :
struct serialization_opts {
explicit serialization_opts()
- : allow_non_string_keys(false)
- , javascript_safe(false)
- , pretty_formatting(false)
- , encode_non_ascii(false)
- , validate_utf8(false)
- , allow_trailing_comma(false)
- , sort_keys(false)
- , skip_invalid_utf8(false)
- , allow_nan_inf(false)
- , double_mode(double_conversion::DoubleToStringConverter::SHORTEST)
- , double_num_digits(0) // ignored when mode is SHORTEST
- , double_fallback(false)
- , parse_numbers_as_strings(false)
- {}
+ : allow_non_string_keys(false),
+ javascript_safe(false),
+ pretty_formatting(false),
+ encode_non_ascii(false),
+ validate_utf8(false),
+ allow_trailing_comma(false),
+ sort_keys(false),
+ skip_invalid_utf8(false),
+ allow_nan_inf(false),
+ double_mode(double_conversion::DoubleToStringConverter::SHORTEST),
+ double_num_digits(0), // ignored when mode is SHORTEST
+ double_fallback(false),
+ parse_numbers_as_strings(false),
+ recursion_limit(100) {}
// If true, keys in an object can be non-strings. (In strict
// JSON, object keys must be strings.) This is used by dynamic's
// Do not parse numbers. Instead, store them as strings and leave the
// conversion up to the user.
bool parse_numbers_as_strings;
+
+ // Recursion limit when parsing.
+ unsigned int recursion_limit;
};
/*
PrintTo(value, &oss);
EXPECT_EQ(expected, oss.str());
}
+
+TEST(Json, RecursionLimit) {
+ std::string in;
+ for (int i = 0; i < 1000; i++) {
+ in.append("{\"x\":");
+ }
+ in.append("\"hi\"");
+ for (int i = 0; i < 1000; i++) {
+ in.append("}");
+ }
+ EXPECT_ANY_THROW(parseJson(in));
+
+ folly::json::serialization_opts opts_high_recursion_limit;
+ opts_high_recursion_limit.recursion_limit = 10000;
+ parseJson(in, opts_high_recursion_limit);
+}