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
* 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)
-------

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

View File

@ -19,4 +19,10 @@ inline ObjectRef ArrayShortcuts<TArray>::createNestedObject() const {
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

View File

@ -16,7 +16,7 @@ template <typename TArray>
class ArrayShortcuts {
public:
// 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;

View File

@ -161,12 +161,6 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
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
#ifdef _MSC_VER

View File

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

View File

@ -174,22 +174,6 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
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
#ifdef _MSC_VER

View File

@ -49,4 +49,21 @@ inline typename enable_if<IsString<TChar*>::value, bool>::type
ObjectShortcuts<TObject>::containsKey(TChar* key) const {
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

View File

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