Skip to content

Commit

Permalink
Fixed dangling reference in MemberProxy and ElementProxy (fixes #1120)
Browse files Browse the repository at this point in the history
  • Loading branch information
bblanchon committed Oct 30, 2019
1 parent ef63757 commit 6da6f92
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 33 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
-------
Expand Down
55 changes: 55 additions & 0 deletions extras/tests/MixedConfiguration/cpp11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions src/ArduinoJson/Array/ArrayImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion src/ArduinoJson/Array/ArrayShortcuts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
6 changes: 0 additions & 6 deletions src/ArduinoJson/Array/ElementProxy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 4 additions & 5 deletions src/ArduinoJson/Document/JsonDocument.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
operator[](const TString& key) {
return MemberProxy<JsonDocument&, const TString&>(*this, key);
FORCE_INLINE typename enable_if<IsString<TString>::value,
MemberProxy<JsonDocument&, TString> >::type
operator[](const TString& key) {
return MemberProxy<JsonDocument&, TString>(*this, key);
}

// operator[](char*)
Expand Down
16 changes: 0 additions & 16 deletions src/ArduinoJson/Object/MemberProxy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions src/ArduinoJson/Object/ObjectImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 4 additions & 5 deletions src/ArduinoJson/Object/ObjectShortcuts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,16 @@ 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
operator[](const TString &key) const;
FORCE_INLINE typename enable_if<IsString<TString>::value,
MemberProxy<TObject, TString> >::type
operator[](const TString &key) const;

// operator[](char*) const
// operator[](const char*) const
// 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
Expand Down

0 comments on commit 6da6f92

Please sign in to comment.