瀏覽代碼

Fixed "linked" strings incorrectly marked as "owned" (fixes #1318)

Benoit Blanchon 5 年之前
父節點
當前提交
4df29fbac1

+ 16 - 0
extras/tests/JsonDeserializer/input_types.cpp

@@ -3,11 +3,27 @@
 // MIT License
 // MIT License
 
 
 #include <ArduinoJson.h>
 #include <ArduinoJson.h>
+
 #include <catch.hpp>
 #include <catch.hpp>
 #include <sstream>
 #include <sstream>
 
 
 #include "CustomReader.hpp"
 #include "CustomReader.hpp"
 
 
+TEST_CASE("deserializeJson(char*)") {
+  StaticJsonDocument<1024> doc;
+
+  SECTION("should not duplicate strings") {
+    char input[] = "{\"hello\":\"world\"}";
+
+    DeserializationError err = deserializeJson(doc, input);
+
+    REQUIRE(err == DeserializationError::Ok);
+    CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1));
+    CHECK(doc.as<JsonVariant>().memoryUsage() ==
+          JSON_OBJECT_SIZE(1));  // issue #1318
+  }
+}
+
 TEST_CASE("deserializeJson(const std::string&)") {
 TEST_CASE("deserializeJson(const std::string&)") {
   DynamicJsonDocument doc(4096);
   DynamicJsonDocument doc(4096);
 
 

+ 3 - 2
src/ArduinoJson/Json/JsonDeserializer.hpp

@@ -240,7 +240,7 @@ class JsonDeserializer {
           if (!slot)
           if (!slot)
             return DeserializationError::NoMemory;
             return DeserializationError::NoMemory;
 
 
-          slot->setOwnedKey(make_not_null(key));
+          slot->setKey(key, typename TStringStorage::storage_policy());
 
 
           variant = slot->data();
           variant = slot->data();
         }
         }
@@ -339,7 +339,8 @@ class JsonDeserializer {
     if (err)
     if (err)
       return err;
       return err;
     const char *value = _stringStorage.save(_pool);
     const char *value = _stringStorage.save(_pool);
-    variant.setOwnedString(make_not_null(value));
+    variant.setString(make_not_null(value),
+                      typename TStringStorage::storage_policy());
     return DeserializationError::Ok;
     return DeserializationError::Ok;
   }
   }
 
 

+ 3 - 2
src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp

@@ -233,7 +233,8 @@ class MsgPackDeserializer {
     const char *s = 0;  // <- mute "maybe-uninitialized" (+4 bytes on AVR)
     const char *s = 0;  // <- mute "maybe-uninitialized" (+4 bytes on AVR)
     DeserializationError err = readString(s, n);
     DeserializationError err = readString(s, n);
     if (!err)
     if (!err)
-      variant.setOwnedString(make_not_null(s));
+      variant.setString(make_not_null(s),
+                        typename TStringStorage::storage_policy());
     return err;
     return err;
   }
   }
 
 
@@ -303,7 +304,7 @@ class MsgPackDeserializer {
       DeserializationError err = parseKey(key);
       DeserializationError err = parseKey(key);
       if (err)
       if (err)
         return err;
         return err;
-      slot->setOwnedKey(make_not_null(key));
+      slot->setKey(key, typename TStringStorage::storage_policy());
 
 
       err = parse(*slot->data(), nestingLimit.decrement());
       err = parse(*slot->data(), nestingLimit.decrement());
       if (err)
       if (err)

+ 2 - 0
src/ArduinoJson/StringStorage/StringCopier.hpp

@@ -48,6 +48,8 @@ class StringCopier {
     return _ptr;
     return _ptr;
   }
   }
 
 
+  typedef storage_policies::store_by_copy storage_policy;
+
  private:
  private:
   char* _ptr;
   char* _ptr;
   size_t _size;
   size_t _size;

+ 3 - 0
src/ArduinoJson/StringStorage/StringMover.hpp

@@ -5,6 +5,7 @@
 #pragma once
 #pragma once
 
 
 #include <ArduinoJson/Namespace.hpp>
 #include <ArduinoJson/Namespace.hpp>
+#include <ArduinoJson/Strings/StoragePolicy.hpp>
 
 
 namespace ARDUINOJSON_NAMESPACE {
 namespace ARDUINOJSON_NAMESPACE {
 
 
@@ -32,6 +33,8 @@ class StringMover {
     return _startPtr;
     return _startPtr;
   }
   }
 
 
+  typedef storage_policies::store_by_address storage_policy;
+
  private:
  private:
   char* _writePtr;
   char* _writePtr;
   char* _startPtr;
   char* _startPtr;

+ 2 - 2
src/ArduinoJson/Variant/SlotFunctions.hpp

@@ -30,7 +30,7 @@ template <typename TAdaptedString>
 inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*,
 inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*,
                        storage_policies::store_by_address) {
                        storage_policies::store_by_address) {
   ARDUINOJSON_ASSERT(var);
   ARDUINOJSON_ASSERT(var);
-  var->setLinkedKey(make_not_null(key.data()));
+  var->setKey(key.data(), storage_policies::store_by_address());
   return true;
   return true;
 }
 }
 
 
@@ -41,7 +41,7 @@ inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool,
   if (!dup)
   if (!dup)
     return false;
     return false;
   ARDUINOJSON_ASSERT(var);
   ARDUINOJSON_ASSERT(var);
-  var->setOwnedKey(make_not_null(dup));
+  var->setKey(dup, storage_policies::store_by_copy());
   return true;
   return true;
 }
 }
 
 

+ 34 - 15
src/ArduinoJson/Variant/VariantData.hpp

@@ -101,7 +101,7 @@ class VariantData {
       case VALUE_IS_OBJECT:
       case VALUE_IS_OBJECT:
         return toObject().copyFrom(src._content.asCollection, pool);
         return toObject().copyFrom(src._content.asCollection, pool);
       case VALUE_IS_OWNED_STRING:
       case VALUE_IS_OWNED_STRING:
-        return setOwnedString(RamStringAdapter(src._content.asString), pool);
+        return setString(RamStringAdapter(src._content.asString), pool);
       case VALUE_IS_OWNED_RAW:
       case VALUE_IS_OWNED_RAW:
         return setOwnedRaw(
         return setOwnedRaw(
             serialized(src._content.asRaw.data, src._content.asRaw.size), pool);
             serialized(src._content.asRaw.data, src._content.asRaw.size), pool);
@@ -238,27 +238,24 @@ class VariantData {
     _content.asInteger = value;
     _content.asInteger = value;
   }
   }
 
 
-  void setLinkedString(const char *value) {
-    if (value) {
-      setType(VALUE_IS_LINKED_STRING);
-      _content.asString = value;
-    } else {
-      setType(VALUE_IS_NULL);
-    }
-  }
-
   void setNull() {
   void setNull() {
     setType(VALUE_IS_NULL);
     setType(VALUE_IS_NULL);
   }
   }
 
 
-  void setOwnedString(not_null<const char *> s) {
+  void setString(not_null<const char *> s, storage_policies::store_by_copy) {
     setType(VALUE_IS_OWNED_STRING);
     setType(VALUE_IS_OWNED_STRING);
     _content.asString = s.get();
     _content.asString = s.get();
   }
   }
 
 
-  bool setOwnedString(const char *s) {
+  void setString(not_null<const char *> s, storage_policies::store_by_address) {
+    setType(VALUE_IS_LINKED_STRING);
+    _content.asString = s.get();
+  }
+
+  template <typename TStoragePolicy>
+  bool setString(const char *s, TStoragePolicy storage_policy) {
     if (s) {
     if (s) {
-      setOwnedString(make_not_null(s));
+      setString(make_not_null(s), storage_policy);
       return true;
       return true;
     } else {
     } else {
       setType(VALUE_IS_NULL);
       setType(VALUE_IS_NULL);
@@ -267,8 +264,30 @@ class VariantData {
   }
   }
 
 
   template <typename TAdaptedString>
   template <typename TAdaptedString>
-  bool setOwnedString(TAdaptedString value, MemoryPool *pool) {
-    return setOwnedString(pool->saveString(value));
+  bool setString(TAdaptedString value, MemoryPool *pool) {
+    return setString(value, pool, typename TAdaptedString::storage_policy());
+  }
+
+  template <typename TAdaptedString>
+  inline bool setString(TAdaptedString value, MemoryPool *pool,
+                        storage_policies::decide_at_runtime) {
+    if (value.isStatic())
+      return setString(value, pool, storage_policies::store_by_address());
+    else
+      return setString(value, pool, storage_policies::store_by_copy());
+  }
+
+  template <typename TAdaptedString>
+  inline bool setString(TAdaptedString value, MemoryPool *,
+                        storage_policies::store_by_address) {
+    return setString(value.data(), storage_policies::store_by_address());
+  }
+
+  template <typename TAdaptedString>
+  inline bool setString(TAdaptedString value, MemoryPool *pool,
+                        storage_policies::store_by_copy) {
+    return setString(pool->saveString(value),
+                     storage_policies::store_by_copy());
   }
   }
 
 
   CollectionData &toArray() {
   CollectionData &toArray() {

+ 3 - 47
src/ArduinoJson/Variant/VariantFunctions.hpp

@@ -99,62 +99,18 @@ inline bool variantSetOwnedRaw(VariantData *var, SerializedValue<T> value,
   return var != 0 && var->setOwnedRaw(value, pool);
   return var != 0 && var->setOwnedRaw(value, pool);
 }
 }
 
 
-inline bool variantSetLinkedString(VariantData *var, const char *value) {
-  if (!var)
-    return false;
-  var->setLinkedString(value);
-  return true;
-}
-
 inline void variantSetNull(VariantData *var) {
 inline void variantSetNull(VariantData *var) {
   if (!var)
   if (!var)
     return;
     return;
   var->setNull();
   var->setNull();
 }
 }
 
 
-inline bool variantSetOwnedString(VariantData *var, char *value) {
-  if (!var)
-    return false;
-  var->setOwnedString(value);
-  return true;
-}
-
-template <typename TAdaptedString>
-inline bool variantSetOwnedString(VariantData *var, TAdaptedString value,
-                                  MemoryPool *pool) {
-  return var != 0 && var->setOwnedString(value, pool);
-}
-
-template <typename TAdaptedString>
-inline bool variantSetString(VariantData *var, TAdaptedString value,
-                             MemoryPool *pool,
-                             storage_policies::decide_at_runtime) {
-  if (value.isStatic())
-    return variantSetString(var, value, pool,
-                            storage_policies::store_by_address());
-  else
-    return variantSetString(var, value, pool,
-                            storage_policies::store_by_copy());
-}
-
 template <typename TAdaptedString>
 template <typename TAdaptedString>
 inline bool variantSetString(VariantData *var, TAdaptedString value,
 inline bool variantSetString(VariantData *var, TAdaptedString value,
                              MemoryPool *pool) {
                              MemoryPool *pool) {
-  return variantSetString(var, value, pool,
-                          typename TAdaptedString::storage_policy());
-}
-
-template <typename TAdaptedString>
-inline bool variantSetString(VariantData *var, TAdaptedString value,
-                             MemoryPool *, storage_policies::store_by_address) {
-  return variantSetLinkedString(var, value.data());
-}
-
-template <typename TAdaptedString>
-inline bool variantSetString(VariantData *var, TAdaptedString value,
-                             MemoryPool *pool,
-                             storage_policies::store_by_copy) {
-  return variantSetOwnedString(var, value, pool);
+  if (!var)
+    return false;
+  return var->setString(value, pool);
 }
 }
 
 
 template <typename T>
 template <typename T>

+ 9 - 6
src/ArduinoJson/Variant/VariantSlot.hpp

@@ -4,12 +4,13 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <stdint.h>  // int8_t, int16_t
+
 #include <ArduinoJson/Polyfills/gsl/not_null.hpp>
 #include <ArduinoJson/Polyfills/gsl/not_null.hpp>
 #include <ArduinoJson/Polyfills/type_traits.hpp>
 #include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Strings/StoragePolicy.hpp>
 #include <ArduinoJson/Variant/VariantContent.hpp>
 #include <ArduinoJson/Variant/VariantContent.hpp>
 
 
-#include <stdint.h>  // int8_t, int16_t
-
 namespace ARDUINOJSON_NAMESPACE {
 namespace ARDUINOJSON_NAMESPACE {
 
 
 typedef conditional<sizeof(void*) <= 2, int8_t, int16_t>::type VariantSlotDiff;
 typedef conditional<sizeof(void*) <= 2, int8_t, int16_t>::type VariantSlotDiff;
@@ -69,14 +70,16 @@ class VariantSlot {
     _next = VariantSlotDiff(slot - this);
     _next = VariantSlotDiff(slot - this);
   }
   }
 
 
-  void setOwnedKey(not_null<const char*> k) {
+  void setKey(const char* k, storage_policies::store_by_copy) {
+    ARDUINOJSON_ASSERT(k != NULL);
     _flags |= KEY_IS_OWNED;
     _flags |= KEY_IS_OWNED;
-    _key = k.get();
+    _key = k;
   }
   }
 
 
-  void setLinkedKey(not_null<const char*> k) {
+  void setKey(const char* k, storage_policies::store_by_address) {
+    ARDUINOJSON_ASSERT(k != NULL);
     _flags &= VALUE_MASK;
     _flags &= VALUE_MASK;
-    _key = k.get();
+    _key = k;
   }
   }
 
 
   const char* key() const {
   const char* key() const {