[PATCH] D108032: [analyzer] Retrieve a character from CompoundLiteralExpr as an initializer for constant arrays.
ASDenysPetrov abandoned this revision. ASDenysPetrov added a comment. Paused for a while. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D108032/new/ https://reviews.llvm.org/D108032 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D108032: [analyzer] Retrieve a character from CompoundLiteralExpr as an initializer for constant arrays.
ASDenysPetrov updated this revision to Diff 373964. ASDenysPetrov edited the summary of this revision. ASDenysPetrov added a comment. Rebased. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D108032/new/ https://reviews.llvm.org/D108032 Files: clang/lib/StaticAnalyzer/Core/RegionStore.cpp clang/test/Analysis/compound-literals.c Index: clang/test/Analysis/compound-literals.c === --- clang/test/Analysis/compound-literals.c +++ clang/test/Analysis/compound-literals.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple=i386-apple-darwin10 -verify %s -analyze \ -// RUN: -analyzer-checker=debug.ExprInspection +// RUN: -analyzer-checker=debug.ExprInspection,core.uninitialized.Assign #define NULL 0 void clang_analyzer_eval(int); @@ -21,3 +21,63 @@ clang_analyzer_eval(pointers[0] == NULL); // expected-warning{{FALSE}} clang_analyzer_eval(pointers[1] == NULL); // expected-warning{{TRUE}} } + +const int glob_arr1[8] = (const int[8]){[2] = 3, [0] = 1, [1] = 2, [3] = 4}; +void glob_arr_index1() { + clang_analyzer_eval(glob_arr1[0] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr1[1] == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr1[2] == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr1[3] == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr1[4] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr1[5] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr1[6] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr1[7] == 0); // expected-warning{{TRUE}} +} + +void glob_invalid_index1() { + int x = -42; + int res = glob_arr1[x]; // expected-warning{{garbage or undefined}} +} + +void glob_invalid_index2() { + int x = 42; + int res = glob_arr1[x]; // expected-warning{{garbage or undefined}} +} + +const int glob_arr2[8] = (const int[8]){1, 2, 3, 4}; +void glob_arr_index2() { + clang_analyzer_eval(glob_arr2[0] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr2[1] == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr2[2] == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr2[3] == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr2[4] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr2[5] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr2[6] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(glob_arr2[7] == 0); // expected-warning{{TRUE}} +} + +void glob_ptr_index1() { + int const *ptr = glob_arr2; + clang_analyzer_eval(ptr[0] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[1] == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[2] == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[3] == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[4] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[5] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[6] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[7] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[8] == 0); // expected-warning{{UNDEFINED}} + clang_analyzer_eval(ptr[9] == 0); // expected-warning{{UNDEFINED}} +} + +void glob_invalid_index3() { + int const *ptr = glob_arr2; + int idx = -42; + int res = ptr[idx]; // expected-warning{{garbage or undefined}} +} + +void glob_invalid_index4() { + int const *ptr = glob_arr2; + int idx = 42; + int res = ptr[idx]; // expected-warning{{garbage or undefined}} +} Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp === --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1680,52 +1680,63 @@ QualType ElemT = R->getElementType(); return getSValFromStringLiteralByIndex(SL, Idx, ElemT); } -} else 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 -//
[PATCH] D108032: [analyzer] Retrieve a character from CompoundLiteralExpr as an initializer for constant arrays.
ASDenysPetrov created this revision. ASDenysPetrov added reviewers: NoQ, vsavchenko, steakhal, martong. ASDenysPetrov added a project: clang. Herald added subscribers: manas, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun. ASDenysPetrov requested review of this revision. Herald added a subscriber: cfe-commits. Add support of handling `CompoundLiteralExpr` in `RegionStoreManager::getConstantValFromConstArrayInitializer`. Retrieve a value from `CompoundLiteralExpr` which is an initializer of constant arrays in global and local scopes. This patch also disables direct binding a compound literal for constant arrays of local storage duration. Example: const int arr[8] = (const int[8]){1, 2, 3, 4}; // compound literal Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D108032 Files: clang/lib/AST/Expr.cpp clang/lib/StaticAnalyzer/Core/RegionStore.cpp clang/test/Analysis/compound-literals.c Index: clang/test/Analysis/compound-literals.c === --- clang/test/Analysis/compound-literals.c +++ clang/test/Analysis/compound-literals.c @@ -21,3 +21,139 @@ clang_analyzer_eval(pointers[0] == NULL); // expected-warning{{FALSE}} clang_analyzer_eval(pointers[1] == NULL); // expected-warning{{TRUE}} } + +void local_arr_index2() { + const int local_arr[8] = (const int[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_index3() { + const int local_arr[8] = (const int[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_index4() { + const int local_arr[8] = (const int[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_index3() { + const int local_arr[8] = (const int[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_index4() { + int const local_arr[][2][3] = (int const[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_index5() { + int const(*ptr_arr)[2][3] = (int const[2][2][3]){{{1, 2}, {}}, {{7, 8}, {10, 11, 12}}}; + clang_analyzer_eval(ptr_arr[0][0][0] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr_arr[0][0][1] == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr_arr[0][0][2] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr_arr[0][1][0] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr_arr[0][1][1] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr_arr[0][1][2] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr_arr[1][0][0] == 7); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr_arr[1][0][1] == 8); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr_arr[1][0][2] == 0); // expected-warning{{TRUE}} +