Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1640,7 +1640,21 @@ (!B.isMainAnalysis() || !VD->hasGlobalStorage())) return None; - // Array's declaration should have ConstantArrayType type. + // Array's declaration should have `ConstantArrayType` type, because only this + // type contains an array extent. It may happen that array type can be of + // `IncompleteArrayType` type. To get the declaration of `ConstantArrayType` + // type, we should find the declaration in the redeclarations chain that has + // the initialization expression. + // NOTE: `VD` is always non-null if `Init` is non-null, so we can check for + // null only one of them. + const Expr *Init = VD->getAnyInitializer(VD); + + // Array's declaration should have an initializer. + if (!Init) + return None; + + // Array's declaration should have ConstantArrayType type, because only this + // type contains an array extent. const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(VD->getType()); if (!CAT) return None; @@ -1683,11 +1697,6 @@ return UndefinedVal(); // From here `Offset` is in the bounds. - // Array's declaration should have an initializer. - const Expr *Init = VD->getAnyInitializer(); - if (!Init) - return None; - // Handle InitListExpr. if (const auto *ILE = dyn_cast(Init)) return getSValFromInitListExpr(ILE, Offset, R->getElementType()); Index: clang/test/Analysis/initialization.c =================================================================== --- clang/test/Analysis/initialization.c +++ clang/test/Analysis/initialization.c @@ -97,3 +97,42 @@ // FIXME: Should warn {{garbage or undefined}}. int res = glob_arr2[x][y]; // no-warning } + +const int glob_arr3[]; // IncompleteArrayType +const int glob_arr3[4] = {1, 2, 3}; // ConstantArrayType +void glob_arr_index4() { + 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}} +} + +const int glob_arr4[]; // IncompleteArrayType +const int glob_arr4[4] = {1, 2, 3}; // ConstantArrayType +const int glob_arr4[]; // ConstantArrayType (according to AST) +void glob_arr_index5() { + clang_analyzer_eval(glob_arr4[0] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr4[1] == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr4[2] == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr4[3] == 0); // expected-warning{{TRUE}} +} + +void glob_invalid_index7() { + int x = 42; + int res = glob_arr4[x]; // expected-warning{{garbage or undefined}} +} + +void glob_invalid_index8() { + int x = -42; + int res = glob_arr4[x]; // expected-warning{{garbage or undefined}} +}