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<InitListExpr>(Init)) {
-          // The array index has to be known.
-          if (auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
-            // 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<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)
+        } else {
+          const InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
+          if (!InitList) {
+            if (const auto *CLE = dyn_cast<CompoundLiteralExpr>(Init)) {
+              const Expr *Init = CLE->getInitializer();
+              if (const auto *ILE = dyn_cast<InitListExpr>(Init))
+                InitList = ILE;
+            }
+          }
+          if (InitList) {
+            // The array index has to be known.
+            if (auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
+              // If it is not an array, return Undef.
+              QualType T = VD->getType();
+              const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(T);
+              if (!CAT)
                 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<SVal> V = svalBuilder.getConstantVal(E))
-                return *V;
+              // 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();
+
+                // 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<SVal> V = svalBuilder.getConstantVal(E))
+                  return *V;
+              }
             }
           }
         }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to