Fixed dangling reference in MemberProxy and ElementProxy (fixes #1120)

This commit is contained in:
Benoit Blanchon
2019-10-30 19:09:21 +01:00
parent ef63757b1a
commit 6da6f921cd
9 changed files with 88 additions and 33 deletions

View File

@ -10,6 +10,7 @@ HEAD
* Improved `deserializeMsgPack()` speed by reading several bytes at once * Improved `deserializeMsgPack()` speed by reading several bytes at once
* Added detection of Atmel AVR8/GNU C Compiler (issue #1112) * Added detection of Atmel AVR8/GNU C Compiler (issue #1112)
* Fixed deserializer that stopped reading at the first `0xFF` (PR #1118 by @mikee47) * 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) v6.12.0 (2019-09-05)
------- -------

View File

@ -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<std::string>::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<MemberProxy<const char*> >::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<ElementProxy<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<ElementProxy<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 #endif

View File

@ -19,4 +19,10 @@ inline ObjectRef ArrayShortcuts<TArray>::createNestedObject() const {
return impl()->addElement().template to<ObjectRef>(); return impl()->addElement().template to<ObjectRef>();
} }
template <typename TArray>
inline ElementProxy<TArray> ArrayShortcuts<TArray>::operator[](
size_t index) const {
return ElementProxy<TArray>(*impl(), index);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -16,7 +16,7 @@ template <typename TArray>
class ArrayShortcuts { class ArrayShortcuts {
public: public:
// Returns the element at specified index if the variant is an array. // Returns the element at specified index if the variant is an array.
FORCE_INLINE ElementProxy<const TArray &> operator[](size_t index) const; FORCE_INLINE ElementProxy<TArray> operator[](size_t index) const;
FORCE_INLINE ObjectRef createNestedObject() const; FORCE_INLINE ObjectRef createNestedObject() const;

View File

@ -161,12 +161,6 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
const size_t _index; const size_t _index;
}; };
template <typename TArray>
inline ElementProxy<const TArray&> ArrayShortcuts<TArray>::operator[](
size_t index) const {
return ElementProxy<const TArray&>(*impl(), index);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -141,11 +141,10 @@ class JsonDocument : public Visitable {
// operator[](const std::string&) // operator[](const std::string&)
// operator[](const String&) // operator[](const String&)
template <typename TString> template <typename TString>
FORCE_INLINE FORCE_INLINE typename enable_if<IsString<TString>::value,
typename enable_if<IsString<TString>::value, MemberProxy<JsonDocument&, TString> >::type
MemberProxy<JsonDocument&, const TString&> >::type operator[](const TString& key) {
operator[](const TString& key) { return MemberProxy<JsonDocument&, TString>(*this, key);
return MemberProxy<JsonDocument&, const TString&>(*this, key);
} }
// operator[](char*) // operator[](char*)

View File

@ -174,22 +174,6 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
TStringRef _key; TStringRef _key;
}; };
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString>::value,
MemberProxy<const TObject &, const TString &> >::type
ObjectShortcuts<TObject>::operator[](const TString &key) const {
return MemberProxy<const TObject &, const TString &>(*impl(), key);
}
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString *>::value,
MemberProxy<const TObject &, TString *> >::type
ObjectShortcuts<TObject>::operator[](TString *key) const {
return MemberProxy<const TObject &, TString *>(*impl(), key);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -49,4 +49,21 @@ inline typename enable_if<IsString<TChar*>::value, bool>::type
ObjectShortcuts<TObject>::containsKey(TChar* key) const { ObjectShortcuts<TObject>::containsKey(TChar* key) const {
return !impl()->getMember(key).isUndefined(); return !impl()->getMember(key).isUndefined();
} }
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString*>::value,
MemberProxy<TObject, TString*> >::type
ObjectShortcuts<TObject>::operator[](TString* key) const {
return MemberProxy<TObject, TString*>(*impl(), key);
}
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString>::value,
MemberProxy<TObject, TString> >::type
ObjectShortcuts<TObject>::operator[](const TString& key) const {
return MemberProxy<TObject, TString>(*impl(), key);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -31,17 +31,16 @@ class ObjectShortcuts {
// operator[](const std::string&) const // operator[](const std::string&) const
// operator[](const String&) const // operator[](const String&) const
template <typename TString> template <typename TString>
FORCE_INLINE FORCE_INLINE typename enable_if<IsString<TString>::value,
typename enable_if<IsString<TString>::value, MemberProxy<TObject, TString> >::type
MemberProxy<const TObject &, const TString &> >::type operator[](const TString &key) const;
operator[](const TString &key) const;
// operator[](char*) const // operator[](char*) const
// operator[](const char*) const // operator[](const char*) const
// operator[](const __FlashStringHelper*) const // operator[](const __FlashStringHelper*) const
template <typename TChar> template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar *>::value, FORCE_INLINE typename enable_if<IsString<TChar *>::value,
MemberProxy<const TObject &, TChar *> >::type MemberProxy<TObject, TChar *> >::type
operator[](TChar *key) const; operator[](TChar *key) const;
// createNestedArray(const std::string&) const // createNestedArray(const std::string&) const