mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Fixed JsonVariant::isNull() not returning true after set((char*)0)
				
					
				
			This commit is contained in:
		| @@ -13,6 +13,8 @@ HEAD | ||||
| * Renamed `JsonArray::add()` (without arg) to `addElement()` | ||||
| * Renamed `JsonObject::get()` to `getMember()` | ||||
| * Renamed `JsonObject::getOrCreate()` to `getOrAddMember()` | ||||
| * Fixed `JsonVariant::isNull()` not returning `true` after `set((char*)0)` | ||||
| * Fixed segfault after `variant.set(serialized((char*)0))` | ||||
|  | ||||
| v6.8.0-beta (2019-01-30) | ||||
| ----------- | ||||
|   | ||||
| @@ -19,7 +19,6 @@ template <typename TReader, typename TStringStorage> | ||||
| class JsonDeserializer { | ||||
|   typedef typename remove_reference<TStringStorage>::type::StringBuilder | ||||
|       StringBuilder; | ||||
|   typedef const char *StringType; | ||||
|  | ||||
|  public: | ||||
|   JsonDeserializer(MemoryPool &pool, TReader reader, | ||||
| @@ -124,10 +123,10 @@ class JsonDeserializer { | ||||
|       if (!slot) return DeserializationError::NoMemory; | ||||
|  | ||||
|       // Parse key | ||||
|       StringType key; | ||||
|       const char *key; | ||||
|       err = parseKey(key); | ||||
|       if (err) return err; | ||||
|       slot->setOwnedKey(key); | ||||
|       slot->setOwnedKey(make_not_null(key)); | ||||
|  | ||||
|       // Skip spaces | ||||
|       err = skipSpacesAndComments(); | ||||
| @@ -162,7 +161,7 @@ class JsonDeserializer { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseKey(StringType &key) { | ||||
|   DeserializationError parseKey(const char *&key) { | ||||
|     if (isQuote(current())) { | ||||
|       return parseQuotedString(key); | ||||
|     } else { | ||||
| @@ -171,14 +170,14 @@ class JsonDeserializer { | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseStringValue(VariantData &variant) { | ||||
|     StringType value; | ||||
|     const char *value; | ||||
|     DeserializationError err = parseQuotedString(value); | ||||
|     if (err) return err; | ||||
|     variant.setOwnedString(value); | ||||
|     variant.setOwnedString(make_not_null(value)); | ||||
|     return DeserializationError::Ok; | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseQuotedString(StringType &result) { | ||||
|   DeserializationError parseQuotedString(const char *&result) { | ||||
|     StringBuilder builder = _stringStorage.startString(); | ||||
|     const char stopChar = current(); | ||||
|  | ||||
| @@ -219,7 +218,7 @@ class JsonDeserializer { | ||||
|     return DeserializationError::Ok; | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseNonQuotedString(StringType &result) { | ||||
|   DeserializationError parseNonQuotedString(const char *&result) { | ||||
|     StringBuilder builder = _stringStorage.startString(); | ||||
|  | ||||
|     char c = current(); | ||||
|   | ||||
| @@ -17,7 +17,6 @@ template <typename TReader, typename TStringStorage> | ||||
| class MsgPackDeserializer { | ||||
|   typedef typename remove_reference<TStringStorage>::type::StringBuilder | ||||
|       StringBuilder; | ||||
|   typedef const char *StringType; | ||||
|  | ||||
|  public: | ||||
|   MsgPackDeserializer(MemoryPool &pool, TReader reader, | ||||
| @@ -227,20 +226,20 @@ class MsgPackDeserializer { | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   DeserializationError readString(StringType &str) { | ||||
|   DeserializationError readString(const char *&str) { | ||||
|     T size; | ||||
|     if (!readInteger(size)) return DeserializationError::IncompleteInput; | ||||
|     return readString(str, size); | ||||
|   } | ||||
|  | ||||
|   DeserializationError readString(VariantData &variant, size_t n) { | ||||
|     StringType s; | ||||
|     const char *s; | ||||
|     DeserializationError err = readString(s, n); | ||||
|     if (!err) variant.setOwnedString(s); | ||||
|     if (!err) variant.setOwnedString(make_not_null(s)); | ||||
|     return err; | ||||
|   } | ||||
|  | ||||
|   DeserializationError readString(StringType &result, size_t n) { | ||||
|   DeserializationError readString(const char *&result, size_t n) { | ||||
|     StringBuilder builder = _stringStorage.startString(); | ||||
|     for (; n; --n) { | ||||
|       uint8_t c; | ||||
| @@ -287,10 +286,10 @@ class MsgPackDeserializer { | ||||
|       VariantSlot *slot = object.addSlot(_pool); | ||||
|       if (!slot) return DeserializationError::NoMemory; | ||||
|  | ||||
|       StringType key; | ||||
|       const char *key; | ||||
|       DeserializationError err = parseKey(key); | ||||
|       if (err) return err; | ||||
|       slot->setOwnedKey(key); | ||||
|       slot->setOwnedKey(make_not_null(key)); | ||||
|  | ||||
|       err = parse(*slot->data()); | ||||
|       if (err) return err; | ||||
| @@ -299,7 +298,7 @@ class MsgPackDeserializer { | ||||
|     return DeserializationError::Ok; | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseKey(StringType &key) { | ||||
|   DeserializationError parseKey(const char *&key) { | ||||
|     uint8_t code; | ||||
|     if (!readByte(code)) return DeserializationError::IncompleteInput; | ||||
|  | ||||
|   | ||||
							
								
								
									
										33
									
								
								src/ArduinoJson/Polyfills/gsl/not_null.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/ArduinoJson/Polyfills/gsl/not_null.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2019 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../assert.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename T> | ||||
| class not_null { | ||||
|  public: | ||||
|   explicit not_null(T ptr) : _ptr(ptr) { | ||||
|     ARDUINOJSON_ASSERT(ptr != NULL); | ||||
|   } | ||||
|  | ||||
|   T get() const { | ||||
|     ARDUINOJSON_ASSERT(_ptr != NULL); | ||||
|     return _ptr; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   T _ptr; | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
| not_null<T> make_not_null(T ptr) { | ||||
|   ARDUINOJSON_ASSERT(ptr != NULL); | ||||
|   return not_null<T>(ptr); | ||||
| } | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -29,6 +29,7 @@ class ConstRamStringAdapter { | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     if (!_str) return 0; | ||||
|     return strlen(_str); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -33,6 +33,7 @@ class FlashStringAdapter { | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     if (!_str) return 0; | ||||
|     return strlen_P(reinterpret_cast<const char*>(_str)); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class SizedFlashStringAdapter { | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return strlen_P(reinterpret_cast<const char*>(_str)); | ||||
|     return _size; | ||||
|   } | ||||
|  | ||||
|   bool isStatic() const { | ||||
|   | ||||
| @@ -30,7 +30,7 @@ class SizedRamStringAdapter { | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return strlen(reinterpret_cast<const char*>(_str)); | ||||
|     return _size; | ||||
|   } | ||||
|  | ||||
|   bool isStatic() const { | ||||
|   | ||||
| @@ -15,11 +15,11 @@ template <typename TAdaptedString> | ||||
| inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { | ||||
|   if (!var) return false; | ||||
|   if (key.isStatic()) { | ||||
|     var->setLinkedKey(key.data()); | ||||
|     var->setLinkedKey(make_not_null(key.data())); | ||||
|   } else { | ||||
|     char* dup = key.save(pool); | ||||
|     const char* dup = key.save(pool); | ||||
|     if (!dup) return false; | ||||
|     var->setOwnedKey(dup); | ||||
|     var->setOwnedKey(make_not_null(dup)); | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../Misc/SerializedValue.hpp" | ||||
| #include "../Polyfills/gsl/not_null.hpp" | ||||
| #include "VariantContent.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| @@ -179,9 +180,13 @@ class VariantData { | ||||
|   } | ||||
|  | ||||
|   void setLinkedRaw(SerializedValue<const char *> value) { | ||||
|     setType(VALUE_IS_LINKED_RAW); | ||||
|     _content.asRaw.data = value.data(); | ||||
|     _content.asRaw.size = value.size(); | ||||
|     if (value.data()) { | ||||
|       setType(VALUE_IS_LINKED_RAW); | ||||
|       _content.asRaw.data = value.data(); | ||||
|       _content.asRaw.size = value.size(); | ||||
|     } else { | ||||
|       setType(VALUE_IS_NULL); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
| @@ -220,25 +225,26 @@ class VariantData { | ||||
|   } | ||||
|  | ||||
|   void setLinkedString(const char *value) { | ||||
|     setType(VALUE_IS_LINKED_STRING); | ||||
|     _content.asString = value; | ||||
|     if (value) { | ||||
|       setType(VALUE_IS_LINKED_STRING); | ||||
|       _content.asString = value; | ||||
|     } else { | ||||
|       setType(VALUE_IS_NULL); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void setNull() { | ||||
|     setType(VALUE_IS_NULL); | ||||
|   } | ||||
|  | ||||
|   void setOwnedString(const char *s) { | ||||
|   void setOwnedString(not_null<const char *> s) { | ||||
|     setType(VALUE_IS_OWNED_STRING); | ||||
|     _content.asString = s; | ||||
|     _content.asString = s.get(); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   bool setOwnedString(T value, MemoryPool *pool) { | ||||
|     char *dup = value.save(pool); | ||||
|     if (dup) { | ||||
|       setType(VALUE_IS_OWNED_STRING); | ||||
|       _content.asString = dup; | ||||
|   bool setOwnedString(const char *s) { | ||||
|     if (s) { | ||||
|       setOwnedString(make_not_null(s)); | ||||
|       return true; | ||||
|     } else { | ||||
|       setType(VALUE_IS_NULL); | ||||
| @@ -246,6 +252,11 @@ class VariantData { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   bool setOwnedString(T value, MemoryPool *pool) { | ||||
|     return setOwnedString(value.save(pool)); | ||||
|   } | ||||
|  | ||||
|   void setUnsignedInteger(UInt value) { | ||||
|     setType(VALUE_IS_POSITIVE_INTEGER); | ||||
|     _content.asInteger = static_cast<UInt>(value); | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Polyfills/gsl/not_null.hpp" | ||||
| #include "../Polyfills/type_traits.hpp" | ||||
| #include "../Variant/VariantContent.hpp" | ||||
|  | ||||
| @@ -67,14 +68,14 @@ class VariantSlot { | ||||
|     _next = VariantSlotDiff(slot - this); | ||||
|   } | ||||
|  | ||||
|   void setOwnedKey(const char* k) { | ||||
|   void setOwnedKey(not_null<const char*> k) { | ||||
|     _flags |= KEY_IS_OWNED; | ||||
|     _key = k; | ||||
|     _key = k.get(); | ||||
|   } | ||||
|  | ||||
|   void setLinkedKey(const char* k) { | ||||
|   void setLinkedKey(not_null<const char*> k) { | ||||
|     _flags &= VALUE_MASK; | ||||
|     _key = k; | ||||
|     _key = k.get(); | ||||
|   } | ||||
|  | ||||
|   const char* key() const { | ||||
|   | ||||
| @@ -64,3 +64,11 @@ TEST_CASE("Invalid JSON string") { | ||||
|     REQUIRE(deserializeJson(doc, input) == DeserializationError::InvalidInput); | ||||
|   } | ||||
| } | ||||
|  | ||||
| TEST_CASE("Not enough room to duplicate the string") { | ||||
|   DynamicJsonDocument doc(4); | ||||
|  | ||||
|   REQUIRE(deserializeJson(doc, "\"hello world!\"") == | ||||
|           DeserializationError::NoMemory); | ||||
|   REQUIRE(doc.isNull() == true); | ||||
| } | ||||
|   | ||||
| @@ -35,15 +35,40 @@ TEST_CASE("JsonVariant::isNull()") { | ||||
|     REQUIRE(variant.isNull() == false); | ||||
|   } | ||||
|  | ||||
|   /*  SECTION("return true when InvalidArray") { | ||||
|       variant.set(JsonArray()); | ||||
|       REQUIRE(variant.isNull() == true); | ||||
|     } | ||||
|   */ | ||||
|   /*  SECTION("return true when InvalidObject") { | ||||
|       variant.set(JsonObject()); | ||||
|       REQUIRE(variant.isNull() == true); | ||||
|     }*/ | ||||
|   SECTION("return true after set(JsonArray())") { | ||||
|     variant.set(JsonArray()); | ||||
|     REQUIRE(variant.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("return true after set(JsonObject())") { | ||||
|     variant.set(JsonObject()); | ||||
|     REQUIRE(variant.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("return false after set('hello')") { | ||||
|     variant.set("hello"); | ||||
|     REQUIRE(variant.isNull() == false); | ||||
|   } | ||||
|  | ||||
|   SECTION("return true after set((char*)0)") { | ||||
|     variant.set(static_cast<char*>(0)); | ||||
|     REQUIRE(variant.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("return true after set((const char*)0)") { | ||||
|     variant.set(static_cast<const char*>(0)); | ||||
|     REQUIRE(variant.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("return true after set(serialized((char*)0))") { | ||||
|     variant.set(serialized(static_cast<char*>(0))); | ||||
|     REQUIRE(variant.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("return true after set(serialized((const char*)0))") { | ||||
|     variant.set(serialized(static_cast<const char*>(0))); | ||||
|     REQUIRE(variant.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("works with JsonVariantConst") { | ||||
|     variant.set(42); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user