ASDenysPetrov created this revision.
ASDenysPetrov added reviewers: NoQ, vsavchenko, steakhal, xazax.hun.
ASDenysPetrov added a project: clang.
Herald added subscribers: manas, martong, dkrupp, donat.nagy, Szelethus,
mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware.
ASDenysPetrov requested review of this revision.
Herald added a subscriber: cfe-commits.
Ignore direct bindings for constant arrays of local storage duration with list
initialization. Constant arrays don't change their values during a lifetime.
Therefore, we don't have to bind values directly for each array element.
Retrieve values from list initialization on-demand as it currently works for
arrays of global storage duration (See https://reviews.llvm.org/D106681 for
details).
Example: `const int arr[42] = {1,2,3,4};`.
We can get values directly from list initializaion in any time, no matter
whether the array has **global** or **local** storage duration. Previously it
works only for **global** arrays.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D107073
Files:
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/Analysis/initialization.c
clang/test/Analysis/initialization.cpp
Index: clang/test/Analysis/initialization.cpp
===================================================================
--- clang/test/Analysis/initialization.cpp
+++ clang/test/Analysis/initialization.cpp
@@ -167,7 +167,7 @@
clang_analyzer_eval(glob_arr3[3][1] == 0); // expected-warning{{TRUE}}
}
-void negative_index1() {
+void glob_arr_negative_index1() {
int x = 2, y = -2;
clang_analyzer_eval(glob_arr3[x][y] == 3); // expected-warning{{TRUE}}
x = 4;
@@ -175,12 +175,12 @@
clang_analyzer_eval(glob_arr3[x][y] == 7); // expected-warning{{TRUE}}
}
-void out_of_bound_index1() {
+void glob_arr_out_of_bound_index1() {
int x = -3, y = 2;
int res = glob_arr3[x][y]; // expected-warning{{garbage or undefined}}
}
-void out_of_bound_index2() {
+void glob_arr_out_of_bound_index2() {
int x = 3, y = 2;
int res = glob_arr3[x][y]; // expected-warning{{garbage or undefined}}
}
@@ -197,12 +197,101 @@
clang_analyzer_eval(glob_arr4[7] == 0); // expected-warning{{TRUE}}
}
-void out_of_bound_index3() {
+void glob_arr_out_of_bound_index3() {
int x = -42;
int res = glob_arr4[x]; // expected-warning{{garbage or undefined}}
}
-void out_of_bound_index4() {
+void glob_arr_out_of_bound_index4() {
int x = 42;
int res = glob_arr4[x]; // expected-warning{{garbage or undefined}}
}
+
+void local_arr_index1() {
+ const int local_arr[2][2][3] = {{{1, 2}}, {{7}}};
+ clang_analyzer_eval(local_arr[0][0][0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][0][1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][0][2] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][1][0] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][1][1] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][1][2] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][0][0] == 7); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][0][1] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][0][2] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][1][0] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][1][1] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][1][2] == 0); // expected-warning{{TRUE}}
+}
+
+void local_arr_index2() {
+ int const local_arr[2][2][3] = {{{1, 2}, {}}, {{7, 8}, {10, 11, 12}}};
+ clang_analyzer_eval(local_arr[0][0][0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][0][1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][0][2] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][1][0] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][1][1] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][1][2] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][0][0] == 7); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][0][1] == 8); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][0][2] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][1][0] == 10); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][1][1] == 11); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][1][2] == 12); // expected-warning{{TRUE}}
+}
+
+void local_arr_index3() {
+ const int local_arr[4][2] = {{}, {3}, {}, {7}};
+ clang_analyzer_eval(local_arr[0][0] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[0][1] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][0] == 3); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1][1] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[2][0] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[2][1] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[3][0] == 7); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[3][1] == 0); // expected-warning{{TRUE}}
+}
+
+void local_arr_negative_index1() {
+ const int local_arr[4][2] = {{}, {3}, {}, {7}};
+ int x = 2, y = -2;
+ clang_analyzer_eval(local_arr[x][y] == 3); // expected-warning{{TRUE}}
+ x = 4;
+ y = -2;
+ clang_analyzer_eval(local_arr[x][y] == 7); // expected-warning{{TRUE}}
+}
+
+void local_arr_out_of_bound_index1() {
+ const int local_arr[4][2] = {{}, {3}, {}, {7}};
+ int x = -3, y = 2;
+ int res = local_arr[x][y]; // expected-warning{{garbage or undefined}}
+}
+
+void local_arr_out_of_bound_index2() {
+ const int local_arr[4][2] = {{}, {3}, {}, {7}};
+ int x = 3, y = 2;
+ int res = local_arr[x][y]; // expected-warning{{garbage or undefined}}
+}
+
+void local_arr_index4() {
+ const int local_arr[8] = {1, 2, 3, 4};
+ clang_analyzer_eval(local_arr[0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[2] == 3); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[3] == 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[4] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[5] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[6] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[7] == 0); // expected-warning{{TRUE}}
+}
+
+void local_arr_out_of_bound_index3() {
+ const int local_arr[8] = {1, 2, 3, 4};
+ int x = -42;
+ int res = local_arr[x]; // expected-warning{{garbage or undefined}}
+}
+
+void local_arr_out_of_bound_index4() {
+ const int local_arr[8] = {1, 2, 3, 4};
+ int x = 42;
+ int res = local_arr[x]; // expected-warning{{garbage or undefined}}
+}
Index: clang/test/Analysis/initialization.c
===================================================================
--- clang/test/Analysis/initialization.c
+++ clang/test/Analysis/initialization.c
@@ -57,3 +57,27 @@
int x = 3, y = 2;
int res = glob_arr1[x][y]; // expected-warning{{garbage or undefined}}
}
+
+void local_arr_index1() {
+ const int local_arr[8] = {[2] = 3, [0] = 1, [1] = 2, [3] = 4};
+ clang_analyzer_eval(local_arr[0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[2] == 3); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[3] == 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[4] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[5] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[6] == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(local_arr[7] == 0); // expected-warning{{TRUE}}
+}
+
+void local_arr_out_of_bound_index1() {
+ const int local_arr[8] = {[2] = 3, [0] = 1, [1] = 2, [3] = 4};
+ int x = -42;
+ int res = local_arr[x]; // expected-warning{{garbage or undefined}}
+}
+
+void local_arr_out_of_bound_index2() {
+ const int local_arr[8] = {[2] = 3, [0] = 1, [1] = 2, [3] = 4};
+ int x = 42;
+ int res = local_arr[x]; // expected-warning{{garbage or undefined}}
+}
Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1639,7 +1639,7 @@
return None;
// Array should have an initialization list.
const Expr *Init = VD->getAnyInitializer();
- // FIXME: Support StringLiteral as an initializer as well.
+ // FIXME: Support StringLiteral and CompoundLiteralExpr as well.
const auto *InitList = dyn_cast_or_null<InitListExpr>(Init);
if (!InitList)
return None;
@@ -2215,12 +2215,30 @@
return B.addBinding(R, BindingKey::Default, V);
}
-RegionBindingsRef
-RegionStoreManager::bindArray(RegionBindingsConstRef B,
- const TypedValueRegion* R,
- SVal Init) {
+RegionBindingsRef RegionStoreManager::bindArray(RegionBindingsConstRef B,
+ const TypedValueRegion *R,
+ SVal Init) {
+ // Ignore binding `InitListExpr` to arrays of const type, since
+ // we can directly retrieve values from `InitListExpr` using
+ // `getConstantValFromConstArrayInitializer`.For example:
+ // const int arr[42] = { 1, 2, 3 };
+ // The init values of this array will never change, so we don't have to
+ // additionally store them in the RegionStore.
+ if (auto VR = dyn_cast<VarRegion>(R)) {
+ const VarDecl *VD = VR->getDecl();
+ if (const bool isConstQualified = VD->getType().isConstQualified()) {
+ const Expr *Init = VD->getAnyInitializer();
+ // FIXME: Ignore `CompoundLiteralExpr` and `StringLiteral` as well when
+ // `getConstantValFromConstArrayInitializer` supports them.
+ if (const bool hasInitList = isa_and_nonnull<InitListExpr>(Init)) {
+ if (isConstQualified && hasInitList)
+ return B;
+ }
+ }
+ }
- const ArrayType *AT =cast<ArrayType>(Ctx.getCanonicalType(R->getValueType()));
+ const ArrayType *AT =
+ cast<ArrayType>(Ctx.getCanonicalType(R->getValueType()));
QualType ElementTy = AT->getElementType();
Optional<uint64_t> Size;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits