mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 17:06:46 +00:00
[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
This commit is contained in:
parent
bf57ecf06e
commit
e4bb68b871
@ -1207,9 +1207,14 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
|
||||
Init = ASE->getBase()->IgnoreImplicit();
|
||||
|
||||
SVal LValue = State->getSVal(Init, stackFrame);
|
||||
if (!Field->getType()->isReferenceType())
|
||||
if (std::optional<Loc> LValueLoc = LValue.getAs<Loc>())
|
||||
if (!Field->getType()->isReferenceType()) {
|
||||
if (std::optional<Loc> LValueLoc = LValue.getAs<Loc>()) {
|
||||
InitVal = State->getSVal(*LValueLoc);
|
||||
} else if (auto CV = LValue.getAs<nonloc::CompoundVal>()) {
|
||||
// Initializer list for an array.
|
||||
InitVal = *CV;
|
||||
}
|
||||
}
|
||||
|
||||
// If we fail to get the value for some reason, use a symbolic value.
|
||||
if (InitVal.isUnknownOrUndef()) {
|
||||
|
@ -234,16 +234,58 @@ struct Parent {
|
||||
void member() {
|
||||
Parent arr[2];
|
||||
|
||||
// FIXME: Ideally these are TRUE, but at the moment InitListExpr has no
|
||||
// knowledge about where the initializer list is used, so we can't bind
|
||||
// the initializer list to the required region.
|
||||
clang_analyzer_eval(arr[0].arr[0].x == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(arr[0].arr[0].y == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(arr[0].arr[1].x == 3); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(arr[0].arr[1].y == 4); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(arr[0].arr[0].x == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(arr[0].arr[0].y == 2); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(arr[0].arr[1].x == 3); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(arr[0].arr[1].y == 4); // expected-warning{{TRUE}}
|
||||
|
||||
clang_analyzer_eval(arr[1].arr[0].x == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(arr[1].arr[0].y == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(arr[1].arr[1].x == 3); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(arr[1].arr[1].y == 4); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(arr[1].arr[0].x == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(arr[1].arr[0].y == 2); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(arr[1].arr[1].x == 3); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(arr[1].arr[1].y == 4); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
struct HasArr {
|
||||
int arrDefault[2] = {1, 2};
|
||||
int arr[2];
|
||||
HasArr(int x, int y) : arr{x, y} {}
|
||||
};
|
||||
|
||||
struct ArrCombination : public HasArr {
|
||||
HasArr membDefault = {5, 6};
|
||||
HasArr memb;
|
||||
ArrCombination(int x) : HasArr(3, 4), memb{7, x} {}
|
||||
};
|
||||
|
||||
void derived_and_member() {
|
||||
ArrCombination a{8};
|
||||
// FIXME: Default initializers for array members are not modeled.
|
||||
clang_analyzer_eval(a.arrDefault[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a.arrDefault[1] == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a.arr[0] == 3); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(a.arr[1] == 4); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(a.membDefault.arrDefault[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a.membDefault.arrDefault[1] == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a.membDefault.arr[0] == 5); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a.membDefault.arr[1] == 6); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a.memb.arrDefault[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a.memb.arrDefault[1] == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a.memb.arr[0] == 7); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(a.memb.arr[1] == 8); // expected-warning{{TRUE}}
|
||||
|
||||
}
|
||||
|
||||
struct IncompleteArrInit {
|
||||
int arr[2];
|
||||
int arrDefault[3] = {1, 2, 3};
|
||||
IncompleteArrInit() : arr{1}, arrDefault{2, 3} {}
|
||||
};
|
||||
|
||||
void incomplete_array_init() {
|
||||
IncompleteArrInit a;
|
||||
clang_analyzer_eval(a.arr[0] == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(a.arr[1] == 0); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(a.arrDefault[0] == 2); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(a.arrDefault[1] == 3); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(a.arrDefault[2] == 0); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
@ -173,3 +173,19 @@ void test_address_space_bind() {
|
||||
AS1 AS_ATTRIBUTE &r = *pa;
|
||||
r.x = 0; // no-warning
|
||||
}
|
||||
|
||||
namespace ArrMemWithCtorInitializer {
|
||||
struct ArrayMem {
|
||||
int* ptrArr[1];
|
||||
int* memPtr;
|
||||
ArrayMem() : ptrArr{nullptr}, memPtr{nullptr} {}
|
||||
// expected-note@-1{{Storing null pointer value}}
|
||||
};
|
||||
|
||||
void tp() {
|
||||
ArrayMem obj; // expected-note{{Calling default constructor for 'ArrayMem'}}
|
||||
// expected-note@-1{{Returning from default constructor for 'ArrayMem'}}
|
||||
*obj.ptrArr[0] = 0; // expected-warning{{Dereference of null pointer}}
|
||||
// expected-note@-1{{Dereference of null pointer}}
|
||||
}
|
||||
} // namespace ArrMemWithCtorInitializer
|
||||
|
Loading…
x
Reference in New Issue
Block a user