https://github.com/necto created https://github.com/llvm/llvm-project/pull/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 >From 63c856732aeda977786534d66597d0aba12cb0d4 Mon Sep 17 00:00:00 2001 From: Arseniy Zaostrovnykh <necto...@gmail.com> Date: Tue, 3 Sep 2024 18:01:02 +0200 Subject: [PATCH] [analyzer] Model constructor initializer for an array member Bind the array member to the compound region associated with the initializer list CPP-5647 --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 9 ++- clang/test/Analysis/ctor-array.cpp | 66 ++++++++++++++++---- clang/test/Analysis/nullptr.cpp | 16 +++++ 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index dfb7111b512552..a577c0b02c83f0 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -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()) { diff --git a/clang/test/Analysis/ctor-array.cpp b/clang/test/Analysis/ctor-array.cpp index 49412ee5a68c70..40c479cd39e31e 100644 --- a/clang/test/Analysis/ctor-array.cpp +++ b/clang/test/Analysis/ctor-array.cpp @@ -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[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[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{{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 modelled + 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}} } diff --git a/clang/test/Analysis/nullptr.cpp b/clang/test/Analysis/nullptr.cpp index 825f6570af591d..73f10a08d96c89 100644 --- a/clang/test/Analysis/nullptr.cpp +++ b/clang/test/Analysis/nullptr.cpp @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits