r331556 - [analyzer] Treat more const variables and fields as known contants.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Fri May 4 13:52:39 PDT 2018


Author: dergachev
Date: Fri May  4 13:52:39 2018
New Revision: 331556

URL: http://llvm.org/viewvc/llvm-project?rev=331556&view=rev
Log:
[analyzer] Treat more const variables and fields as known contants.

When loading from a variable or a field that is declared as constant,
the analyzer will try to inspect its initializer and constant-fold it.
Upon success, the analyzer would skip normal load and return the respective
constant.

The new behavior also applies to fields/elements of brace-initialized structures
and arrays.

Patch by Rafael Stahl!

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

Added:
    cfe/trunk/test/Analysis/globals.cpp
Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/SValBuilder.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=331556&r1=331555&r2=331556&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Fri May  4 13:52:39 2018
@@ -1606,7 +1606,7 @@ SVal RegionStoreManager::getBindingForEl
   const MemRegion* superR = R->getSuperRegion();
 
   // Check if the region is an element region of a string literal.
-  if (const StringRegion *StrR=dyn_cast<StringRegion>(superR)) {
+  if (const StringRegion *StrR = dyn_cast<StringRegion>(superR)) {
     // FIXME: Handle loads from strings where the literal is treated as
     // an integer, e.g., *((unsigned int*)"hello")
     QualType T = Ctx.getAsArrayType(StrR->getValueType())->getElementType();
@@ -1629,6 +1629,27 @@ SVal RegionStoreManager::getBindingForEl
       char c = (i >= length) ? '\0' : Str->getCodeUnit(i);
       return svalBuilder.makeIntVal(c, T);
     }
+  } else if (const VarRegion *VR = dyn_cast<VarRegion>(superR)) {
+    // Check if the containing array is const and has an initialized value.
+    const VarDecl *VD = VR->getDecl();
+    // Either the array or the array element has to be const.
+    if (VD->getType().isConstQualified() || R->getElementType().isConstQualified()) {
+      if (const Expr *Init = VD->getInit()) {
+        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();
+            // Return unknown value if index is out of bounds.
+            if (i < 0 || i >= InitList->getNumInits())
+              return UnknownVal();
+
+            if (const Expr *ElemInit = InitList->getInit(i))
+              if (Optional<SVal> V = svalBuilder.getConstantVal(ElemInit))
+                return *V;
+          }
+        }
+      }
+    }
   }
 
   // Check for loads from a code text region.  For such loads, just give up.
@@ -1678,7 +1699,28 @@ SVal RegionStoreManager::getBindingForFi
   if (const Optional<SVal> &V = B.getDirectBinding(R))
     return *V;
 
-  QualType Ty = R->getValueType();
+  // Is the field declared constant and has an in-class initializer?
+  const FieldDecl *FD = R->getDecl();
+  QualType Ty = FD->getType();
+  if (Ty.isConstQualified())
+    if (const Expr *Init = FD->getInClassInitializer())
+      if (Optional<SVal> V = svalBuilder.getConstantVal(Init))
+        return *V;
+
+  // If the containing record was initialized, try to get its constant value.
+  const MemRegion* superR = R->getSuperRegion();
+  if (const auto *VR = dyn_cast<VarRegion>(superR)) {
+    const VarDecl *VD = VR->getDecl();
+    QualType RecordVarTy = VD->getType();
+    // 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 (const Expr *FieldInit = InitList->getInit(FD->getFieldIndex()))
+            if (Optional<SVal> V = svalBuilder.getConstantVal(FieldInit))
+              return *V;
+  }
+
   return getBindingForFieldOrElementCommon(B, R, Ty);
 }
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/SValBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/SValBuilder.cpp?rev=331556&r1=331555&r2=331556&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/SValBuilder.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/SValBuilder.cpp Fri May  4 13:52:39 2018
@@ -119,7 +119,7 @@ SValBuilder::getRegionValueSymbolVal(con
 
   if (T->isNullPtrType())
     return makeZeroVal(T);
-  
+
   if (!SymbolManager::canSymbolicate(T))
     return UnknownVal();
 
@@ -328,12 +328,19 @@ Optional<SVal> SValBuilder::getConstantV
   case Stmt::CXXNullPtrLiteralExprClass:
     return makeNull();
 
+  case Stmt::CStyleCastExprClass:
+  case Stmt::CXXFunctionalCastExprClass:
+  case Stmt::CXXConstCastExprClass:
+  case Stmt::CXXReinterpretCastExprClass:
+  case Stmt::CXXStaticCastExprClass:
   case Stmt::ImplicitCastExprClass: {
     const auto *CE = cast<CastExpr>(E);
     switch (CE->getCastKind()) {
     default:
       break;
     case CK_ArrayToPointerDecay:
+    case CK_IntegralToPointer:
+    case CK_NoOp:
     case CK_BitCast: {
       const Expr *SE = CE->getSubExpr();
       Optional<SVal> Val = getConstantVal(SE);

Added: cfe/trunk/test/Analysis/globals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/globals.cpp?rev=331556&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/globals.cpp (added)
+++ cfe/trunk/test/Analysis/globals.cpp Fri May  4 13:52:39 2018
@@ -0,0 +1,111 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+
+static const unsigned long long scull = 0;
+void static_int()
+{
+    *(int*)scull = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+const unsigned long long cull = 0;
+void const_int()
+{
+    *(int*)cull = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+static int * const spc = 0;
+void static_ptr()
+{
+    *spc = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+int * const pc = 0;
+void const_ptr()
+{
+    *pc = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+const unsigned long long cull_nonnull = 4;
+void nonnull_int()
+{
+    *(int*)(cull_nonnull - 4) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+int * const pc_nonnull = (int*)sizeof(int);
+void nonnull_ptr()
+{
+    *(pc_nonnull - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+int * const constcast = const_cast<int * const>((int*)sizeof(int));
+void cast1()
+{
+    *(constcast - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+int * const recast = reinterpret_cast<int*>(sizeof(int));
+void cast2()
+{
+    *(recast - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+int * const staticcast = static_cast<int * const>((int*)sizeof(int));
+void cast3()
+{
+    *(staticcast - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+struct Foo { int a; };
+Foo * const dyncast = dynamic_cast<Foo * const>((Foo*)sizeof(Foo));
+void cast4()
+{
+    // Do not handle dynamic_cast for now, because it may change the pointer value.
+    (dyncast - 1)->a = 0; // no-warning
+}
+
+typedef int * const intptrconst;
+int * const funccast = intptrconst(sizeof(int));
+void cast5()
+{
+    *(funccast - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+struct S1
+{
+    int * p;
+};
+const S1 s1 = {
+    .p = (int*)sizeof(int)
+};
+void conststruct()
+{
+    *(s1.p - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+struct S2
+{
+    int * const p;
+};
+S2 s2 = {
+    .p = (int*)sizeof(int)
+};
+void constfield()
+{
+    *(s2.p - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+int * const parr[1] = { (int*)sizeof(int) };
+void constarr()
+{
+    *(parr[0] - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+struct S3
+{
+    int * p = (int*)sizeof(int);
+};
+void recordinit()
+{
+    S3 s3;
+    *(s3.p - 1) = 0; // expected-warning{{Dereference of null pointer}}
+}




More information about the cfe-commits mailing list