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