Skip to content

Commit 3448c02

Browse files
authored
Enforce const correctness for deserialization in TableEntryData (#39112)
1 parent e458040 commit 3448c02

File tree

1 file changed

+29
-6
lines changed

1 file changed

+29
-6
lines changed

src/app/storage/FabricTableImpl.ipp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,29 @@ struct EndpointEntryCount : public PersistentData<kPersistentBufferEntryCountByt
100100
}
101101
};
102102

103+
// Prevent mutations from happening in TableEntryData::Serialize
104+
// If we just used a raw reference for TableEntryData::mEntry, C++ allows us
105+
// to mutate mEntry.mStorageId & mEntry.mStorageData in TableEntryData::Serialize
106+
// without having to do a const_cast; as an example, if we were to accidentally introduce
107+
// the following code in TableEntryData::Serialize (a const method):
108+
//
109+
// this->mEntry->mStorageData = StorageData();
110+
//
111+
// If TableEntryData::mEntry is a reference, it allows this with no compilation error;
112+
// But with ConstCorrectRef, we get a compile-time error that TableEntryData::mEntry->mStorageData
113+
// cannot be modified because it is a const value
114+
template <typename T>
115+
class ConstCorrectRef
116+
{
117+
T & mRef;
118+
119+
public:
120+
inline ConstCorrectRef(T & ref) : mRef(ref) {}
121+
122+
inline const T * operator->() const { return &mRef; }
123+
inline T * operator->() { return &mRef; }
124+
};
125+
103126
template <class StorageId, class StorageData>
104127
struct TableEntryData : DataAccessor
105128
{
@@ -110,7 +133,7 @@ struct TableEntryData : DataAccessor
110133
FabricIndex fabric_index = kUndefinedFabricIndex;
111134
EntryIndex index = 0;
112135
bool first = true;
113-
Data::TableEntry<StorageId, StorageData> & mEntry;
136+
ConstCorrectRef<Data::TableEntry<StorageId, StorageData>> mEntry;
114137

115138
TableEntryData(EndpointId endpoint, FabricIndex fabric, TableEntry & entry, EntryIndex idx = 0) :
116139
endpoint_id(endpoint), fabric_index(fabric), index(idx), mEntry(entry)
@@ -124,16 +147,16 @@ struct TableEntryData : DataAccessor
124147
return CHIP_NO_ERROR;
125148
}
126149

127-
void Clear() override { this->mEntry.mStorageData.Clear(); }
150+
void Clear() override { this->mEntry->mStorageData.Clear(); }
128151

129152
CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
130153
{
131154
TLV::TLVType container;
132155
ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
133156

134-
ReturnErrorOnFailure(Serializer::SerializeId(writer, this->mEntry.mStorageId));
157+
ReturnErrorOnFailure(Serializer::SerializeId(writer, this->mEntry->mStorageId));
135158

136-
ReturnErrorOnFailure(Serializer::SerializeData(writer, this->mEntry.mStorageData));
159+
ReturnErrorOnFailure(Serializer::SerializeData(writer, this->mEntry->mStorageData));
137160

138161
return writer.EndContainer(container);
139162
}
@@ -145,9 +168,9 @@ struct TableEntryData : DataAccessor
145168
TLV::TLVType container;
146169
ReturnErrorOnFailure(reader.EnterContainer(container));
147170

148-
ReturnErrorOnFailure(Serializer::DeserializeId(reader, this->mEntry.mStorageId));
171+
ReturnErrorOnFailure(Serializer::DeserializeId(reader, this->mEntry->mStorageId));
149172

150-
ReturnErrorOnFailure(Serializer::DeserializeData(reader, this->mEntry.mStorageData));
173+
ReturnErrorOnFailure(Serializer::DeserializeData(reader, this->mEntry->mStorageData));
151174

152175
return reader.ExitContainer(container);
153176
}

0 commit comments

Comments
 (0)