blob: 5d1716afdda252f62e2e9a997583485360089c4a [file] [log] [blame]
From af08e41dd05b3ba279bed1f9794ca0fa101e3272 Mon Sep 17 00:00:00 2001
From: Benno Evers <bevers@mesosphere.com>
Date: Fri, 14 Sep 2018 15:33:56 +0200
Subject: [PATCH] Backport depth check to v1.3.0
This is a backport of a similar, unpublished upstream commit
originally authored by kazuho. Minor modifications had to be made
to account for changed formatting and to fix up some counter
modifications that were moved to the wrong lines; as well as
two additional test cases.
---
picojson.h | 56 +++++++++++++++++++++++++++++++++++++++++++-----------
test.cc | 42 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+), 11 deletions(-)
diff --git a/picojson.h b/picojson.h
index 48bb64e..23485a6 100644
--- a/picojson.h
+++ b/picojson.h
@@ -101,7 +101,7 @@ namespace picojson {
};
enum {
- INDENT_WIDTH = 2
+ INDENT_WIDTH = 2, DEFAULT_MAX_DEPTHS = 100
};
struct null {};
@@ -705,7 +705,7 @@ namespace picojson {
return false;
}
if (in.expect('}')) {
- return true;
+ return ctx.parse_object_stop();
}
do {
std::string key;
@@ -718,7 +718,7 @@ namespace picojson {
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) {
@@ -820,8 +820,9 @@ namespace picojson {
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();
return true;
@@ -845,37 +846,53 @@ namespace picojson {
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) { return true; }
+ bool parse_array_stop(size_t) {
+ ++depths_;
+ return true;
+ }
bool parse_object_start() {
+ if (depths_ == 0)
+ return false;
+ --depths_;
*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; }
bool set_bool(bool) { return true; }
#ifdef PICOJSON_USE_INT64
@@ -886,15 +903,32 @@ namespace picojson {
dummy_str s;
return _parse_string(s, in);
}
- bool parse_array_start() { return true; }
+ 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) { return true; }
- bool parse_object_start() { return true; }
+ 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&) {
return _parse(*this, in);
}
+ bool parse_object_stop() {
+ ++depths_;
+ return true;
+ }
private:
null_parse_context(const null_parse_context&);
null_parse_context& operator=(const null_parse_context&);
diff --git a/test.cc b/test.cc
index ed9656d..b04ed59 100644
--- a/test.cc
+++ b/test.cc
@@ -308,5 +308,47 @@ int main(void)
is(v.get<picojson::array>()[1].get<std::string>(), "abc", "simple API value #1");
}
+ {
+ 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\": {\"b\": {\"c\": 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 due to nesting depth");
+ }
+
+ {
+ 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");
+ }
+
+ {
+ std::string s = "[{\"a\":123, \"b\":45, \"c\":67}, {\"b\": [456]}]", err;
+ picojson::null_parse_context ctx(2);
+ std::string::const_iterator end = picojson::_parse(ctx, s.begin(), s.end(), &err);
+ _ok(!err.empty(), "should fail due to nesting depth");
+ }
+
return done_testing();
}
--
2.17.1