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 | 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 | v5.13.1 | ||||||
| ------- | ------- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -44,7 +44,6 @@ class JsonParser { | |||||||
|  |  | ||||||
|   const char *parseString(); |   const char *parseString(); | ||||||
|   bool parseAnythingTo(JsonVariant *destination); |   bool parseAnythingTo(JsonVariant *destination); | ||||||
|   FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); |  | ||||||
|  |  | ||||||
|   inline bool parseArrayTo(JsonVariant *destination); |   inline bool parseArrayTo(JsonVariant *destination); | ||||||
|   inline bool parseObjectTo(JsonVariant *destination); |   inline bool parseObjectTo(JsonVariant *destination); | ||||||
|   | |||||||
| @@ -20,17 +20,6 @@ template <typename TReader, typename TWriter> | |||||||
| inline bool | inline bool | ||||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo( | ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo( | ||||||
|     JsonVariant *destination) { |     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); |   skipSpacesAndComments(_reader); | ||||||
|  |  | ||||||
|   switch (_reader.current()) { |   switch (_reader.current()) { | ||||||
| @@ -48,6 +37,9 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingToUnsafe( | |||||||
| template <typename TReader, typename TWriter> | template <typename TReader, typename TWriter> | ||||||
| inline ArduinoJson::JsonArray & | inline ArduinoJson::JsonArray & | ||||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() { | ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() { | ||||||
|  |   if (_nestingLimit == 0) return JsonArray::invalid(); | ||||||
|  |   _nestingLimit--; | ||||||
|  |  | ||||||
|   // Create an empty array |   // Create an empty array | ||||||
|   JsonArray &array = _buffer->createArray(); |   JsonArray &array = _buffer->createArray(); | ||||||
|  |  | ||||||
| @@ -69,6 +61,7 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() { | |||||||
|  |  | ||||||
| SUCCESS_EMPTY_ARRAY: | SUCCESS_EMPTY_ARRAY: | ||||||
| SUCCES_NON_EMPTY_ARRAY: | SUCCES_NON_EMPTY_ARRAY: | ||||||
|  |   _nestingLimit++; | ||||||
|   return array; |   return array; | ||||||
|  |  | ||||||
| ERROR_INVALID_VALUE: | ERROR_INVALID_VALUE: | ||||||
| @@ -91,6 +84,9 @@ inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArrayTo( | |||||||
| template <typename TReader, typename TWriter> | template <typename TReader, typename TWriter> | ||||||
| inline ArduinoJson::JsonObject & | inline ArduinoJson::JsonObject & | ||||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() { | ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() { | ||||||
|  |   if (_nestingLimit == 0) return JsonObject::invalid(); | ||||||
|  |   _nestingLimit--; | ||||||
|  |  | ||||||
|   // Create an empty object |   // Create an empty object | ||||||
|   JsonObject &object = _buffer->createObject(); |   JsonObject &object = _buffer->createObject(); | ||||||
|  |  | ||||||
| @@ -117,6 +113,7 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() { | |||||||
|  |  | ||||||
| SUCCESS_EMPTY_OBJECT: | SUCCESS_EMPTY_OBJECT: | ||||||
| SUCCESS_NON_EMPTY_OBJECT: | SUCCESS_NON_EMPTY_OBJECT: | ||||||
|  |   _nestingLimit++; | ||||||
|   return object; |   return object; | ||||||
|  |  | ||||||
| ERROR_INVALID_KEY: | ERROR_INVALID_KEY: | ||||||
|   | |||||||
| @@ -5,44 +5,62 @@ | |||||||
| #include <ArduinoJson.h> | #include <ArduinoJson.h> | ||||||
| #include <catch.hpp> | #include <catch.hpp> | ||||||
|  |  | ||||||
| bool tryParseArray(const char *json, uint8_t nestingLimit) { | #define SHOULD_WORK(expression) REQUIRE(true == expression.success()); | ||||||
|   DynamicJsonBuffer buffer; | #define SHOULD_FAIL(expression) REQUIRE(false == expression.success()); | ||||||
|   return buffer.parseArray(json, nestingLimit).success(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool tryParseObject(const char *json, uint8_t nestingLimit) { |  | ||||||
|   DynamicJsonBuffer buffer; |  | ||||||
|   return buffer.parseObject(json, nestingLimit).success(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| TEST_CASE("JsonParser nestingLimit") { | TEST_CASE("JsonParser nestingLimit") { | ||||||
|   SECTION("ParseArrayWithNestingLimit0") { |   DynamicJsonBuffer jb; | ||||||
|     REQUIRE(true == tryParseArray("[]", 0)); |  | ||||||
|     REQUIRE(false == tryParseArray("[[]]", 0)); |   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") { |   SECTION("parseObject()") { | ||||||
|     REQUIRE(true == tryParseArray("[[]]", 1)); |     SECTION("limit = 0") { | ||||||
|     REQUIRE(false == tryParseArray("[[[]]]", 1)); |       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") { |   SECTION("parse()") { | ||||||
|     REQUIRE(true == tryParseArray("[[[]]]", 2)); |     SECTION("limit = 0") { | ||||||
|     REQUIRE(false == tryParseArray("[[[[]]]]", 2)); |       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") { |     SECTION("limit = 1") { | ||||||
|     REQUIRE(true == tryParseObject("{}", 0)); |       SHOULD_WORK(jb.parse("[\"toto\"]", 1)); | ||||||
|     REQUIRE(false == tryParseObject("{\"key\":{}}", 0)); |       SHOULD_WORK(jb.parse("{\"toto\":1}", 1)); | ||||||
|   } |       SHOULD_FAIL(jb.parse("{\"toto\":{}}", 1)); | ||||||
|  |       SHOULD_FAIL(jb.parse("{\"toto\":[]}", 1)); | ||||||
|   SECTION("ParseObjectWithNestingLimit1") { |       SHOULD_FAIL(jb.parse("[[\"toto\"]]", 1)); | ||||||
|     REQUIRE(true == tryParseObject("{\"key\":{}}", 1)); |       SHOULD_FAIL(jb.parse("[{\"toto\":1}]", 1)); | ||||||
|     REQUIRE(false == tryParseObject("{\"key\":{\"key\":{}}}", 1)); |     } | ||||||
|   } |  | ||||||
|  |  | ||||||
|   SECTION("ParseObjectWithNestingLimit2") { |  | ||||||
|     REQUIRE(true == tryParseObject("{\"key\":{\"key\":{}}}", 2)); |  | ||||||
|     REQUIRE(false == tryParseObject("{\"key\":{\"key\":{\"key\":{}}}}", 2)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user