]> granicus.if.org Git - clang/commitdiff
[analyzer] const init: handle non-explicit cases more accurately
authorRafael Stahl <r.stahl@tum.de>
Tue, 29 May 2018 14:14:22 +0000 (14:14 +0000)
committerRafael Stahl <r.stahl@tum.de>
Tue, 29 May 2018 14:14:22 +0000 (14:14 +0000)
Summary: If the access is out of bounds, return UndefinedVal. If it is missing an explicit init, return the implicit zero value it must have.

Reviewers: NoQ, xazax.hun, george.karpenkov

Reviewed By: NoQ

Subscribers: szepet, rnkovacs, a.sidorin, cfe-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@333417 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/RegionStore.cpp
test/Analysis/initialization.c
test/Analysis/initialization.cpp [new file with mode: 0644]

index be4b5aa9189e9043a0701c89b95823735a2c1594..acb6eeab8d915803e7ad47aee928bd6e5fe775cc 100644 (file)
@@ -1638,9 +1638,18 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
           // The array index has to be known.
           if (auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
             int64_t i = CI->getValue().getSExtValue();
-            // Return unknown value if index is out of bounds.
-            if (i < 0 || i >= InitList->getNumInits())
-              return UnknownVal();
+            // If it is known that the index is out of bounds, we can return
+            // an undefined value.
+            if (i < 0)
+              return UndefinedVal();
+
+            if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
+              if (CAT->getSize().sle(i))
+                return UndefinedVal();
+
+            // If there is a list, but no init, it must be zero.
+            if (i >= InitList->getNumInits())
+              return svalBuilder.makeZeroVal(R->getElementType());
 
             if (const Expr *ElemInit = InitList->getInit(i))
               if (Optional<SVal> V = svalBuilder.getConstantVal(ElemInit))
@@ -1715,11 +1724,15 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
     // Either the record variable or the field has to be const qualified.
     if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
       if (const Expr *Init = VD->getInit())
-        if (const auto *InitList = dyn_cast<InitListExpr>(Init))
-          if (Index < InitList->getNumInits())
+        if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
+          if (Index < InitList->getNumInits()) {
             if (const Expr *FieldInit = InitList->getInit(Index))
               if (Optional<SVal> V = svalBuilder.getConstantVal(FieldInit))
                 return *V;
+          } else {
+            return svalBuilder.makeZeroVal(Ty);
+          }
+        }
   }
 
   return getBindingForFieldOrElementCommon(B, R, Ty);
index a6fe9be2b701af5bde71f7cd97e3ebf5a278ff53..c1d6361f1245bd6afa0fcfdb051a093ce87a8c02 100644 (file)
@@ -1,7 +1,28 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
 
 void initbug() {
   const union { float a; } u = {};
   (void)u.a; // no-crash
 }
+
+int const parr[2] = {1};
+void constarr() {
+  int i = 2;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+  i = 1;
+  clang_analyzer_eval(parr[i] == 0); // expected-warning{{TRUE}}
+  i = -1;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+}
+
+struct SM {
+  int a;
+  int b;
+};
+const struct SM sm = {.a = 1};
+void multinit() {
+  clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/initialization.cpp b/test/Analysis/initialization.cpp
new file mode 100644 (file)
index 0000000..db76593
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+
+struct S {
+  int a = 3;
+};
+S const sarr[2] = {};
+void definit() {
+  int i = 1;
+  // FIXME: Should recognize that it is 3.
+  clang_analyzer_eval(sarr[i].a); // expected-warning{{UNKNOWN}}
+}
+
+int const arr[2][2] = {};
+void arr2init() {
+  int i = 1;
+  // FIXME: Should recognize that it is 0.
+  clang_analyzer_eval(arr[i][0]); // expected-warning{{UNKNOWN}}
+}