Skip to content

Commit

Permalink
Merge pull request #135 from kazuho/kazuho/infinite-recursion
Browse files Browse the repository at this point in the history
limit recursion by retaining depth
  • Loading branch information
kazuho authored Nov 9, 2020
2 parents a495b83 + 2f9d3cf commit 35ce0b6
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 7 deletions.
39 changes: 32 additions & 7 deletions picojson.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ enum {
#endif
};

enum { INDENT_WIDTH = 2 };
enum { INDENT_WIDTH = 2, DEFAULT_MAX_DEPTHS = 100 };

struct null {};

Expand Down Expand Up @@ -839,7 +839,7 @@ template <typename Context, typename Iter> inline bool _parse_object(Context &ct
return false;
}
if (in.expect('}')) {
return true;
return ctx.parse_object_stop();
}
do {
std::string key;
Expand All @@ -850,7 +850,7 @@ template <typename Context, typename Iter> inline bool _parse_object(Context &ct
return false;
}
} while (in.expect(','));
return in.expect('}');
return in.expect('}') && ctx.parse_object_stop();
}

template <typename Iter> inline std::string _parse_number(input<Iter> &in) {
Expand Down Expand Up @@ -966,9 +966,10 @@ class deny_parse_context {
class default_parse_context {
protected:
value *out_;
size_t depths_;

public:
default_parse_context(value *out) : out_(out) {
default_parse_context(value *out, size_t depths = DEFAULT_MAX_DEPTHS) : out_(out), depths_(depths) {
}
bool set_null() {
*out_ = value();
Expand All @@ -993,42 +994,55 @@ class default_parse_context {
return _parse_string(out_->get<std::string>(), in);
}
bool parse_array_start() {
if (depths_ == 0)
return false;
--depths_;
*out_ = value(array_type, false);
return true;
}
template <typename Iter> bool parse_array_item(input<Iter> &in, size_t) {
array &a = out_->get<array>();
a.push_back(value());
default_parse_context ctx(&a.back());
default_parse_context ctx(&a.back(), depths_);
return _parse(ctx, in);
}
bool parse_array_stop(size_t) {
++depths_;
return true;
}
bool parse_object_start() {
if (depths_ == 0)
return false;
*out_ = value(object_type, false);
return true;
}
template <typename Iter> bool parse_object_item(input<Iter> &in, const std::string &key) {
object &o = out_->get<object>();
default_parse_context ctx(&o[key]);
default_parse_context ctx(&o[key], depths_);
return _parse(ctx, in);
}
bool parse_object_stop() {
++depths_;
return true;
}

private:
default_parse_context(const default_parse_context &);
default_parse_context &operator=(const default_parse_context &);
};

class null_parse_context {
protected:
size_t depths_;

public:
struct dummy_str {
void push_back(int) {
}
};

public:
null_parse_context() {
null_parse_context(size_t depths = DEFAULT_MAX_DEPTHS) : depths_(depths) {
}
bool set_null() {
return true;
Expand All @@ -1049,20 +1063,31 @@ class null_parse_context {
return _parse_string(s, in);
}
bool parse_array_start() {
if (depths_ == 0)
return false;
--depths_;
return true;
}
template <typename Iter> bool parse_array_item(input<Iter> &in, size_t) {
return _parse(*this, in);
}
bool parse_array_stop(size_t) {
++depths_;
return true;
}
bool parse_object_start() {
if (depths_ == 0)
return false;
--depths_;
return true;
}
template <typename Iter> bool parse_object_item(input<Iter> &in, const std::string &) {
++depths_;
return _parse(*this, in);
}
bool parse_object_stop() {
return true;
}

private:
null_parse_context(const null_parse_context &);
Expand Down
27 changes: 27 additions & 0 deletions test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -344,5 +344,32 @@ int main(void)
is(*reststr, 'a', "should point at the next char");
}

{
std::string s = "[{\"a\":123}]", err;
picojson::value v;
picojson::default_parse_context ctx(&v, 2);
std::string::const_iterator end = picojson::_parse(ctx, s.begin(), s.end(), &err);
_ok(err.empty(), "should succeed");
_ok(end == s.end(), "should have consumed all input");
_ok(v.get(0).get("a").get<double>() == 123, "should return correct value");
}

{
std::string s = "[{\"a\":123}]", err;
picojson::value v;
picojson::default_parse_context ctx(&v, 1);
std::string::const_iterator end = picojson::_parse(ctx, s.begin(), s.end(), &err);
_ok(!err.empty(), "should fail");
_ok(v.is<picojson::array>(), "should get an array");
_ok(v.get(0).is<picojson::null>(), "that contains null");
}

{
std::string s = "[{\"a\":123}]", err;
picojson::null_parse_context ctx(1);
std::string::const_iterator end = picojson::_parse(ctx, s.begin(), s.end(), &err);
_ok(!err.empty(), "should fail");
}

return done_testing();
}

0 comments on commit 35ce0b6

Please sign in to comment.