Author: Arseniy Zaostrovnykh Date: 2024-09-06T15:55:16+02:00 New Revision: e4bb68b8717a20c5828b479f83c8648c2596e598
URL: https://github.com/llvm/llvm-project/commit/e4bb68b8717a20c5828b479f83c8648c2596e598 DIFF: https://github.com/llvm/llvm-project/commit/e4bb68b8717a20c5828b479f83c8648c2596e598.diff LOG: [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 Added: Modified: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/test/Analysis/ctor-array.cpp clang/test/Analysis/nullptr.cpp Removed: ################################################################################ diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index dfb7111b512552..315d85319a85a9 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..52600b314b010f 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 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}} } 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