mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Fixed JsonBuffer::parse() nesting limit (fixes #693)
				
					
				
			This commit is contained in:
		| @@ -1,6 +1,12 @@ | ||||
| ArduinoJson: change log | ||||
| ======================= | ||||
|  | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Fixed `JsonBuffer::parse()` not respecting nesting limit correctly (issue #693) | ||||
| * Fixed inconsistencies in nesting level counting (PR #695 from Zhenyu Wu) | ||||
|  | ||||
| v5.13.1 | ||||
| ------- | ||||
|  | ||||
|   | ||||
| @@ -44,7 +44,6 @@ class JsonParser { | ||||
|  | ||||
|   const char *parseString(); | ||||
|   bool parseAnythingTo(JsonVariant *destination); | ||||
|   FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); | ||||
|  | ||||
|   inline bool parseArrayTo(JsonVariant *destination); | ||||
|   inline bool parseObjectTo(JsonVariant *destination); | ||||
|   | ||||
| @@ -20,17 +20,6 @@ template <typename TReader, typename TWriter> | ||||
| inline bool | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo( | ||||
|     JsonVariant *destination) { | ||||
|   if (_nestingLimit == 0) return false; | ||||
|   _nestingLimit--; | ||||
|   bool success = parseAnythingToUnsafe(destination); | ||||
|   _nestingLimit++; | ||||
|   return success; | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline bool | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingToUnsafe( | ||||
|     JsonVariant *destination) { | ||||
|   skipSpacesAndComments(_reader); | ||||
|  | ||||
|   switch (_reader.current()) { | ||||
| @@ -48,6 +37,9 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingToUnsafe( | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonArray & | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() { | ||||
|   if (_nestingLimit == 0) return JsonArray::invalid(); | ||||
|   _nestingLimit--; | ||||
|  | ||||
|   // Create an empty array | ||||
|   JsonArray &array = _buffer->createArray(); | ||||
|  | ||||
| @@ -69,6 +61,7 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() { | ||||
|  | ||||
| SUCCESS_EMPTY_ARRAY: | ||||
| SUCCES_NON_EMPTY_ARRAY: | ||||
|   _nestingLimit++; | ||||
|   return array; | ||||
|  | ||||
| ERROR_INVALID_VALUE: | ||||
| @@ -91,6 +84,9 @@ inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArrayTo( | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonObject & | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() { | ||||
|   if (_nestingLimit == 0) return JsonObject::invalid(); | ||||
|   _nestingLimit--; | ||||
|  | ||||
|   // Create an empty object | ||||
|   JsonObject &object = _buffer->createObject(); | ||||
|  | ||||
| @@ -117,6 +113,7 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() { | ||||
|  | ||||
| SUCCESS_EMPTY_OBJECT: | ||||
| SUCCESS_NON_EMPTY_OBJECT: | ||||
|   _nestingLimit++; | ||||
|   return object; | ||||
|  | ||||
| ERROR_INVALID_KEY: | ||||
|   | ||||
| @@ -5,44 +5,62 @@ | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| bool tryParseArray(const char *json, uint8_t nestingLimit) { | ||||
|   DynamicJsonBuffer buffer; | ||||
|   return buffer.parseArray(json, nestingLimit).success(); | ||||
| } | ||||
|  | ||||
| bool tryParseObject(const char *json, uint8_t nestingLimit) { | ||||
|   DynamicJsonBuffer buffer; | ||||
|   return buffer.parseObject(json, nestingLimit).success(); | ||||
| } | ||||
| #define SHOULD_WORK(expression) REQUIRE(true == expression.success()); | ||||
| #define SHOULD_FAIL(expression) REQUIRE(false == expression.success()); | ||||
|  | ||||
| TEST_CASE("JsonParser nestingLimit") { | ||||
|   SECTION("ParseArrayWithNestingLimit0") { | ||||
|     REQUIRE(true == tryParseArray("[]", 0)); | ||||
|     REQUIRE(false == tryParseArray("[[]]", 0)); | ||||
|   DynamicJsonBuffer jb; | ||||
|  | ||||
|   SECTION("parseArray()") { | ||||
|     SECTION("limit = 0") { | ||||
|       SHOULD_FAIL(jb.parseArray("[]", 0)); | ||||
|     } | ||||
|  | ||||
|     SECTION("limit = 1") { | ||||
|       SHOULD_WORK(jb.parseArray("[]", 1)); | ||||
|       SHOULD_FAIL(jb.parseArray("[[]]", 1)); | ||||
|     } | ||||
|  | ||||
|     SECTION("limit = 2") { | ||||
|       SHOULD_WORK(jb.parseArray("[[]]", 2)); | ||||
|       SHOULD_FAIL(jb.parseArray("[[[]]]", 2)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseArrayWithNestingLimit1") { | ||||
|     REQUIRE(true == tryParseArray("[[]]", 1)); | ||||
|     REQUIRE(false == tryParseArray("[[[]]]", 1)); | ||||
|   SECTION("parseObject()") { | ||||
|     SECTION("limit = 0") { | ||||
|       SHOULD_FAIL(jb.parseObject("{}", 0)); | ||||
|     } | ||||
|  | ||||
|     SECTION("limit = 1") { | ||||
|       SHOULD_WORK(jb.parseObject("{\"key\":42}", 1)); | ||||
|       SHOULD_FAIL(jb.parseObject("{\"key\":{\"key\":42}}", 1)); | ||||
|     } | ||||
|  | ||||
|     SECTION("limit = 2") { | ||||
|       SHOULD_WORK(jb.parseObject("{\"key\":{\"key\":42}}", 2)); | ||||
|       SHOULD_FAIL(jb.parseObject("{\"key\":{\"key\":{\"key\":42}}}", 2)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseArrayWithNestingLimit2") { | ||||
|     REQUIRE(true == tryParseArray("[[[]]]", 2)); | ||||
|     REQUIRE(false == tryParseArray("[[[[]]]]", 2)); | ||||
|   } | ||||
|   SECTION("parse()") { | ||||
|     SECTION("limit = 0") { | ||||
|       SHOULD_WORK(jb.parse("\"toto\"", 0)); | ||||
|       SHOULD_WORK(jb.parse("123", 0)); | ||||
|       SHOULD_WORK(jb.parse("true", 0)); | ||||
|       SHOULD_FAIL(jb.parse("[]", 0)); | ||||
|       SHOULD_FAIL(jb.parse("{}", 0)); | ||||
|       SHOULD_FAIL(jb.parse("[\"toto\"]", 0)); | ||||
|       SHOULD_FAIL(jb.parse("{\"toto\":1}", 0)); | ||||
|     } | ||||
|  | ||||
|   SECTION("ParseObjectWithNestingLimit0") { | ||||
|     REQUIRE(true == tryParseObject("{}", 0)); | ||||
|     REQUIRE(false == tryParseObject("{\"key\":{}}", 0)); | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseObjectWithNestingLimit1") { | ||||
|     REQUIRE(true == tryParseObject("{\"key\":{}}", 1)); | ||||
|     REQUIRE(false == tryParseObject("{\"key\":{\"key\":{}}}", 1)); | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseObjectWithNestingLimit2") { | ||||
|     REQUIRE(true == tryParseObject("{\"key\":{\"key\":{}}}", 2)); | ||||
|     REQUIRE(false == tryParseObject("{\"key\":{\"key\":{\"key\":{}}}}", 2)); | ||||
|     SECTION("limit = 1") { | ||||
|       SHOULD_WORK(jb.parse("[\"toto\"]", 1)); | ||||
|       SHOULD_WORK(jb.parse("{\"toto\":1}", 1)); | ||||
|       SHOULD_FAIL(jb.parse("{\"toto\":{}}", 1)); | ||||
|       SHOULD_FAIL(jb.parse("{\"toto\":[]}", 1)); | ||||
|       SHOULD_FAIL(jb.parse("[[\"toto\"]]", 1)); | ||||
|       SHOULD_FAIL(jb.parse("[{\"toto\":1}]", 1)); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user