Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1660,7 +1660,7 @@ } else if (const VarRegion *VR = dyn_cast(superR)) { // Check if the containing array has an initialized value that we can trust. // We can trust a const value or a value of a global initializer in main(). - const VarDecl *VD = VR->getDecl(); + const VarDecl *VD = VR->getDecl()->getMostRecentDecl(); if (VD->getType().isConstQualified() || R->getElementType().isConstQualified() || (B.isMainAnalysis() && VD->hasGlobalStorage())) { @@ -1668,49 +1668,48 @@ if (const auto *InitList = dyn_cast(Init)) { // The array index has to be known. if (auto CI = R->getIndex().getAs()) { - // If it is not an array, return Undef. - QualType T = VD->getType(); - const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(T); - if (!CAT) - return UndefinedVal(); - - // Support one-dimensional array. - // C++20 [expr.add] 7.6.6.4 (excerpt): - // If P points to an array element i of an array object x with n - // elements, where i < 0 or i > n, the behavior is undefined. - // Dereferencing is not allowed on the "one past the last - // element", when i == n. - // Example: - // const int arr[4] = {1, 2}; - // const int *ptr = arr; - // int x0 = ptr[0]; // 1 - // int x1 = ptr[1]; // 2 - // int x2 = ptr[2]; // 0 - // int x3 = ptr[3]; // 0 - // int x4 = ptr[4]; // UB - // TODO: Support multidimensional array. - if (!isa(CAT->getElementType())) { - // One-dimensional array. - const llvm::APSInt &Idx = CI->getValue(); - const auto I = static_cast(Idx.getExtValue()); - // Use `getZExtValue` because array extent can not be negative. - const uint64_t Extent = CAT->getSize().getZExtValue(); - // Check for `Idx < 0`, NOT for `I < 0`, because `Idx` CAN be - // negative, but `I` can NOT. - if (Idx < 0 || I >= Extent) - return UndefinedVal(); - - // C++20 [expr.add] 9.4.17.5 (excerpt): - // i-th array element is value-initialized for each k < i ≤ n, - // where k is an expression-list size and n is an array extent. - if (I >= InitList->getNumInits()) - return svalBuilder.makeZeroVal(R->getElementType()); - - // Return a constant value, if it is presented. - // FIXME: Support other SVals. - const Expr *E = InitList->getInit(I); - if (Optional V = svalBuilder.getConstantVal(E)) - return *V; + // We treat only ConstantArrayType. + const QualType T = VD->getType(); + if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(T)) { + // Support one-dimensional array. + // C++20 [expr.add] 7.6.6.4 (excerpt): + // If P points to an array element i of an array object x with n + // elements, where i < 0 or i > n, the behavior is undefined. + // Dereferencing is not allowed on the "one past the last + // element", when i == n. + // Example: + // const int arr[4] = {1, 2}; + // const int *ptr = arr; + // int x0 = ptr[0]; // 1 + // int x1 = ptr[1]; // 2 + // int x2 = ptr[2]; // 0 + // int x3 = ptr[3]; // 0 + // int x4 = ptr[4]; // UB + // TODO: Support multidimensional array. + if (!isa(CAT->getElementType())) { + // One-dimensional array. + const llvm::APSInt &Idx = CI->getValue(); + const auto I = static_cast(Idx.getExtValue()); + // Use `getZExtValue` because array extent can not be negative. + const uint64_t Extent = CAT->getSize().getZExtValue(); + // Check for `Idx < 0`, NOT for `I < 0`, because `Idx` CAN be + // negative, but `I` can NOT. + if (Idx < 0 || I >= Extent) + return UndefinedVal(); + + // C++20 [expr.add] 9.4.17.5 (excerpt): + // i-th array element is value-initialized for each k < i ≤ n, + // where k is an expression-list size and n is an array + // extent. + if (I >= InitList->getNumInits()) + return svalBuilder.makeZeroVal(R->getElementType()); + + // Return a constant value, if it is presented. + // FIXME: Support other SVals. + const Expr *E = InitList->getInit(I); + if (Optional V = svalBuilder.getConstantVal(E)) + return *V; + } } } } Index: clang/test/Analysis/initialization.c =================================================================== --- clang/test/Analysis/initialization.c +++ clang/test/Analysis/initialization.c @@ -97,3 +97,22 @@ // FIXME: Should warn {{garbage or undefined}}. int res = glob_arr2[x][y]; // no-warning } + +const int glob_arr3[]; // Incomplete array declaration +const int glob_arr3[4] = {1, 2, 3}; // Incomplete Array redeclaration +void foo() { + clang_analyzer_eval(glob_arr3[0] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr3[1] == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr3[2] == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr3[3] == 0); // expected-warning{{TRUE}} +} + +void glob_invalid_index5() { + int x = 42; + int res = glob_arr3[x]; // expected-warning{{garbage or undefined}} +} + +void glob_invalid_index6() { + int x = -42; + int res = glob_arr3[x]; // expected-warning{{garbage or undefined}} +}