diff --git a/CHANGELOG.md b/CHANGELOG.md index b3910925..2dde80e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ HEAD * Improved `deserializeMsgPack()` speed by reading several bytes at once * Added detection of Atmel AVR8/GNU C Compiler (issue #1112) * Fixed deserializer that stopped reading at the first `0xFF` (PR #1118 by @mikee47) +* Fixed dangling reference in copies of `MemberProxy` and `ElementProxy` (issue #1120) v6.12.0 (2019-09-05) ------- diff --git a/extras/tests/MixedConfiguration/cpp11.cpp b/extras/tests/MixedConfiguration/cpp11.cpp index 94eea383..35472dfc 100644 --- a/extras/tests/MixedConfiguration/cpp11.cpp +++ b/extras/tests/MixedConfiguration/cpp11.cpp @@ -28,4 +28,59 @@ TEST_CASE("nullptr") { } } +TEST_CASE("Issue #1120") { + StaticJsonDocument<500> doc; + constexpr char str[] = + "{\"contents\":[{\"module\":\"Packet\"},{\"module\":\"Analog\"}]}"; + deserializeJson(doc, str); + + SECTION("MemberProxy::isNull()") { + SECTION("returns false") { + auto value = doc[std::string("contents")]; + CHECK(value.isNull() == false); + } + + SECTION("returns true") { + auto value = doc[std::string("zontents")]; + CHECK(value.isNull() == true); + } + } + + SECTION("ElementProxy >::isNull()") { + SECTION("returns false") { // Issue #1120 + auto value = doc["contents"][1]; + CHECK(value.isNull() == false); + } + + SECTION("returns true") { + auto value = doc["contents"][2]; + CHECK(value.isNull() == true); + } + } + + SECTION("MemberProxy, const char*>::isNull()") { + SECTION("returns false") { + auto value = doc["contents"][1]["module"]; + CHECK(value.isNull() == false); + } + + SECTION("returns true") { + auto value = doc["contents"][1]["zodule"]; + CHECK(value.isNull() == true); + } + } + + SECTION("MemberProxy, std::string>::isNull()") { + SECTION("returns false") { + auto value = doc["contents"][1][std::string("module")]; + CHECK(value.isNull() == false); + } + + SECTION("returns true") { + auto value = doc["contents"][1][std::string("zodule")]; + CHECK(value.isNull() == true); + } + } +} + #endif diff --git a/src/ArduinoJson/Array/ArrayImpl.hpp b/src/ArduinoJson/Array/ArrayImpl.hpp index 2d379115..5cda7a73 100644 --- a/src/ArduinoJson/Array/ArrayImpl.hpp +++ b/src/ArduinoJson/Array/ArrayImpl.hpp @@ -19,4 +19,10 @@ inline ObjectRef ArrayShortcuts::createNestedObject() const { return impl()->addElement().template to(); } +template +inline ElementProxy ArrayShortcuts::operator[]( + size_t index) const { + return ElementProxy(*impl(), index); +} + } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Array/ArrayShortcuts.hpp b/src/ArduinoJson/Array/ArrayShortcuts.hpp index cfa46a38..ee0a270d 100644 --- a/src/ArduinoJson/Array/ArrayShortcuts.hpp +++ b/src/ArduinoJson/Array/ArrayShortcuts.hpp @@ -16,7 +16,7 @@ template class ArrayShortcuts { public: // Returns the element at specified index if the variant is an array. - FORCE_INLINE ElementProxy operator[](size_t index) const; + FORCE_INLINE ElementProxy operator[](size_t index) const; FORCE_INLINE ObjectRef createNestedObject() const; diff --git a/src/ArduinoJson/Array/ElementProxy.hpp b/src/ArduinoJson/Array/ElementProxy.hpp index 58f3a2e7..57d547d1 100644 --- a/src/ArduinoJson/Array/ElementProxy.hpp +++ b/src/ArduinoJson/Array/ElementProxy.hpp @@ -161,12 +161,6 @@ class ElementProxy : public VariantOperators >, const size_t _index; }; -template -inline ElementProxy ArrayShortcuts::operator[]( - size_t index) const { - return ElementProxy(*impl(), index); -} - } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index 784383ec..499c6502 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -141,11 +141,10 @@ class JsonDocument : public Visitable { // operator[](const std::string&) // operator[](const String&) template - FORCE_INLINE - typename enable_if::value, - MemberProxy >::type - operator[](const TString& key) { - return MemberProxy(*this, key); + FORCE_INLINE typename enable_if::value, + MemberProxy >::type + operator[](const TString& key) { + return MemberProxy(*this, key); } // operator[](char*) diff --git a/src/ArduinoJson/Object/MemberProxy.hpp b/src/ArduinoJson/Object/MemberProxy.hpp index 6fe7d4cc..1cfccd88 100644 --- a/src/ArduinoJson/Object/MemberProxy.hpp +++ b/src/ArduinoJson/Object/MemberProxy.hpp @@ -174,22 +174,6 @@ class MemberProxy : public VariantOperators >, TStringRef _key; }; -template -template -inline typename enable_if::value, - MemberProxy >::type - ObjectShortcuts::operator[](const TString &key) const { - return MemberProxy(*impl(), key); -} - -template -template -inline typename enable_if::value, - MemberProxy >::type - ObjectShortcuts::operator[](TString *key) const { - return MemberProxy(*impl(), key); -} - } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER diff --git a/src/ArduinoJson/Object/ObjectImpl.hpp b/src/ArduinoJson/Object/ObjectImpl.hpp index d381ac2f..037ecdf8 100644 --- a/src/ArduinoJson/Object/ObjectImpl.hpp +++ b/src/ArduinoJson/Object/ObjectImpl.hpp @@ -49,4 +49,21 @@ inline typename enable_if::value, bool>::type ObjectShortcuts::containsKey(TChar* key) const { return !impl()->getMember(key).isUndefined(); } + +template +template +inline typename enable_if::value, + MemberProxy >::type + ObjectShortcuts::operator[](TString* key) const { + return MemberProxy(*impl(), key); +} + +template +template +inline typename enable_if::value, + MemberProxy >::type + ObjectShortcuts::operator[](const TString& key) const { + return MemberProxy(*impl(), key); +} + } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Object/ObjectShortcuts.hpp b/src/ArduinoJson/Object/ObjectShortcuts.hpp index 909115bd..7e781da6 100644 --- a/src/ArduinoJson/Object/ObjectShortcuts.hpp +++ b/src/ArduinoJson/Object/ObjectShortcuts.hpp @@ -31,17 +31,16 @@ class ObjectShortcuts { // operator[](const std::string&) const // operator[](const String&) const template - FORCE_INLINE - typename enable_if::value, - MemberProxy >::type - operator[](const TString &key) const; + FORCE_INLINE typename enable_if::value, + MemberProxy >::type + operator[](const TString &key) const; // operator[](char*) const // operator[](const char*) const // operator[](const __FlashStringHelper*) const template FORCE_INLINE typename enable_if::value, - MemberProxy >::type + MemberProxy >::type operator[](TChar *key) const; // createNestedArray(const std::string&) const