[clang] 98a95d4 - [analyzer] Retrieve a value from list initialization of constant array declaration in a global scope.

Denys Petrov via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 24 02:38:06 PDT 2021


Author: Denys Petrov
Date: 2021-09-24T12:37:58+03:00
New Revision: 98a95d4844caf8edfabd9352393a5546049b54e8

URL: https://github.com/llvm/llvm-project/commit/98a95d4844caf8edfabd9352393a5546049b54e8
DIFF: https://github.com/llvm/llvm-project/commit/98a95d4844caf8edfabd9352393a5546049b54e8.diff

LOG: [analyzer] Retrieve a value from list initialization of constant array declaration in a global scope.

Summary: Fix the point that we didn't take into account array's dimension. Retrieve a value of global constant array by iterating through its initializer list.

Differential Revision: https://reviews.llvm.org/D104285

Fixes: https://bugs.llvm.org/show_bug.cgi?id=50604

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Core/RegionStore.cpp
    clang/test/Analysis/initialization.c
    clang/test/Analysis/initialization.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 4ffa1aacb41fa..a82749f30e027 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1668,23 +1668,50 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
         if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
           // The array index has to be known.
           if (auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
-            int64_t i = CI->getValue().getSExtValue();
-            // If it is known that the index is out of bounds, we can return
-            // an undefined value.
-            if (i < 0)
+            // If it is not an array, return Undef.
+            QualType T = VD->getType();
+            const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(T);
+            if (!CAT)
               return UndefinedVal();
 
-            if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
-              if (CAT->getSize().sle(i))
+            // 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<ConstantArrayType>(CAT->getElementType())) {
+              // One-dimensional array.
+              const llvm::APSInt &Idx = CI->getValue();
+              const auto I = static_cast<uint64_t>(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();
 
-            // If there is a list, but no init, it must be zero.
-            if (i >= InitList->getNumInits())
-              return svalBuilder.makeZeroVal(R->getElementType());
+              // 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());
 
-            if (const Expr *ElemInit = InitList->getInit(i))
-              if (Optional<SVal> V = svalBuilder.getConstantVal(ElemInit))
+              // Return a constant value, if it is presented.
+              // FIXME: Support other SVals.
+              const Expr *E = InitList->getInit(I);
+              if (Optional<SVal> V = svalBuilder.getConstantVal(E))
                 return *V;
+            }
           }
         }
       }

diff  --git a/clang/test/Analysis/initialization.c b/clang/test/Analysis/initialization.c
index c1d6361f1245b..a0899e678699b 100644
--- a/clang/test/Analysis/initialization.c
+++ b/clang/test/Analysis/initialization.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-config eagerly-assume=false  -analyzer-checker=core.uninitialized.Assign,debug.ExprInspection -verify %s
 
 void clang_analyzer_eval(int);
 
@@ -26,3 +26,74 @@ void multinit() {
   clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
   clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
 }
+
+const int glob_arr1[6] = {[2] = 3, [0] = 1, [1] = 2, [3] = 4};
+void glob_array_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}}
+}
+
+void glob_array_index2() {
+  const int *ptr = glob_arr1;
+  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}}
+}
+
+void glob_invalid_index1() {
+  int x = -42;
+  int res = glob_arr1[x]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_invalid_index2() {
+  const int *ptr = glob_arr1;
+  int x = 42;
+  int res = ptr[x]; // expected-warning{{garbage or undefined}}
+}
+
+// TODO: Support multidimensional array.
+const int glob_arr2[3][3] = {[0][0] = 1, [1][1] = 5, [2][0] = 7};
+void glob_arr_index3() {
+  // FIXME: These all should be TRUE.
+  clang_analyzer_eval(glob_arr2[0][0] == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(glob_arr2[0][1] == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(glob_arr2[0][2] == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(glob_arr2[1][0] == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(glob_arr2[1][1] == 5); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(glob_arr2[1][2] == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(glob_arr2[2][0] == 7); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(glob_arr2[2][1] == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(glob_arr2[2][2] == 0); // expected-warning{{UNKNOWN}}
+}
+
+// TODO: Support multidimensional array.
+void negative_index() {
+  int x = 2, y = -2;
+  // FIXME: Should be UNDEFINED.
+  clang_analyzer_eval(glob_arr2[x][y] == 5); // expected-warning{{UNKNOWN}}
+  x = 3;
+  y = -3;
+  // FIXME: Should be UNDEFINED.
+  clang_analyzer_eval(glob_arr2[x][y] == 7); // expected-warning{{UNKNOWN}}
+}
+
+// TODO: Support multidimensional array.
+void glob_invalid_index3() {
+  int x = -1, y = -1;
+  // FIXME: Should warn {{garbage or undefined}}.
+  int res = glob_arr2[x][y]; // no-warning
+}
+
+// TODO: Support multidimensional array.
+void glob_invalid_index4() {
+  int x = 3, y = 2;
+  // FIXME: Should warn {{garbage or undefined}}.
+  int res = glob_arr2[x][y]; // no-warning
+}

diff  --git a/clang/test/Analysis/initialization.cpp b/clang/test/Analysis/initialization.cpp
index dd622e077e934..ad9acc880aec7 100644
--- a/clang/test/Analysis/initialization.cpp
+++ b/clang/test/Analysis/initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++14 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -std=c++14 -triple i386-apple-darwin10 -analyze -analyzer-config eagerly-assume=false -analyzer-checker=core.uninitialized.Assign,core.builtin,debug.ExprInspection,core.uninitialized.UndefReturn -verify %s
 
 void clang_analyzer_eval(int);
 
@@ -18,3 +18,113 @@ void arr2init() {
   // FIXME: Should recognize that it is 0.
   clang_analyzer_eval(arr[i][0]); // expected-warning{{UNKNOWN}}
 }
+
+int const glob_arr1[3] = {};
+void glob_array_index1() {
+  clang_analyzer_eval(glob_arr1[0] == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(glob_arr1[1] == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(glob_arr1[2] == 0); // expected-warning{{TRUE}}
+}
+
+void glob_invalid_index1() {
+  const int *ptr = glob_arr1;
+  int idx = -42;
+  auto x = ptr[idx]; // expected-warning{{garbage or undefined}}
+}
+
+int const glob_arr2[4] = {1, 2};
+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] == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptr[3] == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNDEFINED}}
+}
+
+void glob_invalid_index2() {
+  const int *ptr = glob_arr2;
+  int idx = 42;
+  auto x = ptr[idx]; // expected-warning{{garbage or undefined}}
+}
+
+const float glob_arr3[] = {
+    0.0000, 0.0235, 0.0470, 0.0706, 0.0941, 0.1176};
+float no_warn_garbage_value() {
+  return glob_arr3[0]; // no-warning (garbage or undefined)
+}
+
+// TODO: Support multidimensional array.
+int const glob_arr4[4][2] = {};
+void glob_array_index2() {
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr4[1][0] == 0); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr4[1][1] == 0); // expected-warning{{UNKNOWN}}
+}
+
+// TODO: Support multidimensional array.
+void glob_invalid_index3() {
+  int idx = -42;
+  // FIXME: Should warn {{garbage or undefined}}.
+  auto x = glob_arr4[1][idx]; // no-warning
+}
+
+// TODO: Support multidimensional array.
+void glob_invalid_index4() {
+  const int *ptr = glob_arr4[1];
+  int idx = -42;
+  // FIXME: Should warn {{garbage or undefined}}.
+  auto x = ptr[idx]; // no-warning
+}
+
+// TODO: Support multidimensional array.
+int const glob_arr5[4][2] = {{1}, 3, 4, 5};
+void glob_array_index3() {
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr5[0][0] == 1); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr5[0][1] == 0); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr5[1][0] == 3); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr5[1][1] == 4); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr5[2][0] == 5); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr5[2][1] == 0); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr5[3][0] == 0); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(glob_arr5[3][1] == 0); // expected-warning{{UNKNOWN}}
+}
+
+// TODO: Support multidimensional array.
+void glob_ptr_index2() {
+  int const *ptr = glob_arr5[1];
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(ptr[0] == 3); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be TRUE.
+  clang_analyzer_eval(ptr[1] == 4); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be UNDEFINED.
+  clang_analyzer_eval(ptr[2] == 5); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be UNDEFINED.
+  clang_analyzer_eval(ptr[3] == 0); // expected-warning{{UNKNOWN}}
+  // FIXME: Should be UNDEFINED.
+  clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNKNOWN}}
+}
+
+// TODO: Support multidimensional array.
+void glob_invalid_index5() {
+  int idx = -42;
+  // FIXME: Should warn {{garbage or undefined}}.
+  auto x = glob_arr5[1][idx]; // no-warning
+}
+
+// TODO: Support multidimensional array.
+void glob_invalid_index6() {
+  int const *ptr = &glob_arr5[1][0];
+  int idx = 42;
+  // FIXME: Should warn {{garbage or undefined}}.
+  auto x = ptr[idx]; // // no-warning
+}


        


More information about the cfe-commits mailing list