Skip to content

Commit bcb4179

Browse files
Stop importing operator* and operator-> into Nullable. (#34353)
These are serious footguns because: 1. They don't do checks that there is actually a value, and will silently produce garbage. 2. They are really easy to accidentally use without a IsNull() check (especially operator->). I've now reviewed several PRs where people were misusing these and helped a few other people who were misusing them and then not getting expected behavior, so it would be better if we just didn't have these at all. Nullable is not a pointer and people shouldn't treat it like one.
1 parent 1da085d commit bcb4179

File tree

4 files changed

+13
-10
lines changed

4 files changed

+13
-10
lines changed

src/app/cluster-building-blocks/QuieterReporting.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ class QuieterReportingAttribute
178178
bool isChangeOfNull = newValue.IsNull() ^ mValue.IsNull();
179179
bool areBothValuesNonNull = !newValue.IsNull() && !mValue.IsNull();
180180

181-
bool changeToFromZero = areBothValuesNonNull && (*newValue == 0 || *mValue == 0);
182-
bool isIncrement = areBothValuesNonNull && (*newValue > *mValue);
183-
bool isDecrement = areBothValuesNonNull && (*newValue < *mValue);
181+
bool changeToFromZero = areBothValuesNonNull && (newValue.Value() == 0 || mValue.Value() == 0);
182+
bool isIncrement = areBothValuesNonNull && (newValue.Value() > mValue.Value());
183+
bool isDecrement = areBothValuesNonNull && (newValue.Value() < mValue.Value());
184184

185185
bool isNewlyDirty = isChangeOfNull;
186186
isNewlyDirty =

src/app/cluster-building-blocks/tests/TestQuieterReporting.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ TEST(TestQuieterReporting, ChangeOnIncrementPolicyWorks)
9898
QuieterReportingAttribute<int> attribute{ MakeNullable<int>(10) };
9999

100100
// Always start not dirty (because first sub priming always just read value anyway).
101-
ASSERT_EQ(*attribute.value(), 10);
101+
ASSERT_EQ(attribute.value().Value(), 10);
102102

103103
auto now = fakeClock.now();
104104

@@ -149,7 +149,7 @@ TEST(TestQuieterReporting, ChangeOnDecrementPolicyWorks)
149149
QuieterReportingAttribute<int> attribute{ MakeNullable<int>(9) };
150150

151151
// Always start not dirty (because first sub priming always just read value anyway).
152-
ASSERT_EQ(*attribute.value(), 9);
152+
ASSERT_EQ(attribute.value().Value(), 9);
153153

154154
auto now = fakeClock.now();
155155

@@ -202,7 +202,7 @@ TEST(TestQuieterReporting, SufficientChangePredicateWorks)
202202
QuieterReportingAttribute<int> attribute{ MakeNullable<int>(9) };
203203

204204
// Always start not dirty (because first sub priming always just read value anyway).
205-
ASSERT_EQ(*attribute.value(), 9);
205+
ASSERT_EQ(attribute.value().Value(), 9);
206206

207207
auto now = fakeClock.now();
208208

src/app/codegen-data-model/CodegenDataModel_Write.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ CHIP_ERROR DecodeIntoEmberBuffer(AttributeValueDecoder & decoder, bool isNullabl
166166
// Nullable<uint8_t>(0xFF) is not representable because 0xFF is the encoding of NULL in ember
167167
// as well as odd-sized integers (e.g. full 32-bit value like 0x11223344 cannot be written
168168
// to a 3-byte odd-sized integger).
169-
VerifyOrReturnError(Traits::CanRepresentValue(isNullable, *workingValue), CHIP_ERROR_INVALID_ARGUMENT);
170-
Traits::WorkingToStorage(*workingValue, storageValue);
169+
VerifyOrReturnError(Traits::CanRepresentValue(isNullable, workingValue.Value()), CHIP_ERROR_INVALID_ARGUMENT);
170+
Traits::WorkingToStorage(workingValue.Value(), storageValue);
171171
}
172172

173173
VerifyOrReturnError(out.size() >= sizeof(storageValue), CHIP_ERROR_INVALID_ARGUMENT);

src/app/data-model/Nullable.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@ struct Nullable : protected std::optional<T>
4545
// all constructors of the base class within this derived class.
4646
//
4747
using std::optional<T>::optional;
48-
using std::optional<T>::operator*;
49-
using std::optional<T>::operator->;
48+
49+
// Do NOT pull in optional::operator* or optional::operator->, because that
50+
// leads people to write code that looks like it should work, and compiles,
51+
// but does not do the right things with TLV encoding and decoding, when
52+
// nullable data model objects are involved.
5053

5154
Nullable(NullOptionalType) : std::optional<T>(std::nullopt) {}
5255

0 commit comments

Comments
 (0)