Skip to content

Commit e4bb68b

Browse files
authored
[analyzer] Model constructor initializer for an array member (#107537)
Bind the array member to the compound region associated with the initializer list, e.g.: class C { int arr[2]; C() : arr{1, 2} {} }; C c; This change enables correct values in `c.arr[0]` and `c.arr[1]` CPP-5647
1 parent bf57ecf commit e4bb68b

File tree

3 files changed

+77
-14
lines changed

3 files changed

+77
-14
lines changed

clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,9 +1207,14 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
12071207
Init = ASE->getBase()->IgnoreImplicit();
12081208

12091209
SVal LValue = State->getSVal(Init, stackFrame);
1210-
if (!Field->getType()->isReferenceType())
1211-
if (std::optional<Loc> LValueLoc = LValue.getAs<Loc>())
1210+
if (!Field->getType()->isReferenceType()) {
1211+
if (std::optional<Loc> LValueLoc = LValue.getAs<Loc>()) {
12121212
InitVal = State->getSVal(*LValueLoc);
1213+
} else if (auto CV = LValue.getAs<nonloc::CompoundVal>()) {
1214+
// Initializer list for an array.
1215+
InitVal = *CV;
1216+
}
1217+
}
12131218

12141219
// If we fail to get the value for some reason, use a symbolic value.
12151220
if (InitVal.isUnknownOrUndef()) {

clang/test/Analysis/ctor-array.cpp

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -234,16 +234,58 @@ struct Parent {
234234
void member() {
235235
Parent arr[2];
236236

237-
// FIXME: Ideally these are TRUE, but at the moment InitListExpr has no
238-
// knowledge about where the initializer list is used, so we can't bind
239-
// the initializer list to the required region.
240-
clang_analyzer_eval(arr[0].arr[0].x == 1); // expected-warning{{UNKNOWN}}
241-
clang_analyzer_eval(arr[0].arr[0].y == 2); // expected-warning{{UNKNOWN}}
242-
clang_analyzer_eval(arr[0].arr[1].x == 3); // expected-warning{{UNKNOWN}}
243-
clang_analyzer_eval(arr[0].arr[1].y == 4); // expected-warning{{UNKNOWN}}
244-
245-
clang_analyzer_eval(arr[1].arr[0].x == 1); // expected-warning{{UNKNOWN}}
246-
clang_analyzer_eval(arr[1].arr[0].y == 2); // expected-warning{{UNKNOWN}}
247-
clang_analyzer_eval(arr[1].arr[1].x == 3); // expected-warning{{UNKNOWN}}
248-
clang_analyzer_eval(arr[1].arr[1].y == 4); // expected-warning{{UNKNOWN}}
237+
clang_analyzer_eval(arr[0].arr[0].x == 1); // expected-warning{{TRUE}}
238+
clang_analyzer_eval(arr[0].arr[0].y == 2); // expected-warning{{TRUE}}
239+
clang_analyzer_eval(arr[0].arr[1].x == 3); // expected-warning{{TRUE}}
240+
clang_analyzer_eval(arr[0].arr[1].y == 4); // expected-warning{{TRUE}}
241+
242+
clang_analyzer_eval(arr[1].arr[0].x == 1); // expected-warning{{TRUE}}
243+
clang_analyzer_eval(arr[1].arr[0].y == 2); // expected-warning{{TRUE}}
244+
clang_analyzer_eval(arr[1].arr[1].x == 3); // expected-warning{{TRUE}}
245+
clang_analyzer_eval(arr[1].arr[1].y == 4); // expected-warning{{TRUE}}
246+
}
247+
248+
struct HasArr {
249+
int arrDefault[2] = {1, 2};
250+
int arr[2];
251+
HasArr(int x, int y) : arr{x, y} {}
252+
};
253+
254+
struct ArrCombination : public HasArr {
255+
HasArr membDefault = {5, 6};
256+
HasArr memb;
257+
ArrCombination(int x) : HasArr(3, 4), memb{7, x} {}
258+
};
259+
260+
void derived_and_member() {
261+
ArrCombination a{8};
262+
// FIXME: Default initializers for array members are not modeled.
263+
clang_analyzer_eval(a.arrDefault[0] == 1); // expected-warning{{UNKNOWN}}
264+
clang_analyzer_eval(a.arrDefault[1] == 2); // expected-warning{{UNKNOWN}}
265+
clang_analyzer_eval(a.arr[0] == 3); // expected-warning{{TRUE}}
266+
clang_analyzer_eval(a.arr[1] == 4); // expected-warning{{TRUE}}
267+
clang_analyzer_eval(a.membDefault.arrDefault[0] == 1); // expected-warning{{UNKNOWN}}
268+
clang_analyzer_eval(a.membDefault.arrDefault[1] == 2); // expected-warning{{UNKNOWN}}
269+
clang_analyzer_eval(a.membDefault.arr[0] == 5); // expected-warning{{UNKNOWN}}
270+
clang_analyzer_eval(a.membDefault.arr[1] == 6); // expected-warning{{UNKNOWN}}
271+
clang_analyzer_eval(a.memb.arrDefault[0] == 1); // expected-warning{{UNKNOWN}}
272+
clang_analyzer_eval(a.memb.arrDefault[1] == 2); // expected-warning{{UNKNOWN}}
273+
clang_analyzer_eval(a.memb.arr[0] == 7); // expected-warning{{TRUE}}
274+
clang_analyzer_eval(a.memb.arr[1] == 8); // expected-warning{{TRUE}}
275+
276+
}
277+
278+
struct IncompleteArrInit {
279+
int arr[2];
280+
int arrDefault[3] = {1, 2, 3};
281+
IncompleteArrInit() : arr{1}, arrDefault{2, 3} {}
282+
};
283+
284+
void incomplete_array_init() {
285+
IncompleteArrInit a;
286+
clang_analyzer_eval(a.arr[0] == 1); // expected-warning{{TRUE}}
287+
clang_analyzer_eval(a.arr[1] == 0); // expected-warning{{TRUE}}
288+
clang_analyzer_eval(a.arrDefault[0] == 2); // expected-warning{{TRUE}}
289+
clang_analyzer_eval(a.arrDefault[1] == 3); // expected-warning{{TRUE}}
290+
clang_analyzer_eval(a.arrDefault[2] == 0); // expected-warning{{TRUE}}
249291
}

clang/test/Analysis/nullptr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,19 @@ void test_address_space_bind() {
173173
AS1 AS_ATTRIBUTE &r = *pa;
174174
r.x = 0; // no-warning
175175
}
176+
177+
namespace ArrMemWithCtorInitializer {
178+
struct ArrayMem {
179+
int* ptrArr[1];
180+
int* memPtr;
181+
ArrayMem() : ptrArr{nullptr}, memPtr{nullptr} {}
182+
// expected-note@-1{{Storing null pointer value}}
183+
};
184+
185+
void tp() {
186+
ArrayMem obj; // expected-note{{Calling default constructor for 'ArrayMem'}}
187+
// expected-note@-1{{Returning from default constructor for 'ArrayMem'}}
188+
*obj.ptrArr[0] = 0; // expected-warning{{Dereference of null pointer}}
189+
// expected-note@-1{{Dereference of null pointer}}
190+
}
191+
} // namespace ArrMemWithCtorInitializer

0 commit comments

Comments
 (0)