summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-05-04 20:52:39 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-05-04 20:52:39 +0000
commita2e053638bbfea50b29a29ee687f1bdd6abd427f (patch)
treedfeae83b24cdb39419329099fd0f93862296aae2 /clang/lib/StaticAnalyzer
parentb6211d9084e13d892faa6c7020561d9193b5513f (diff)
downloadbcm5719-llvm-a2e053638bbfea50b29a29ee687f1bdd6abd427f.tar.gz
bcm5719-llvm-a2e053638bbfea50b29a29ee687f1bdd6abd427f.zip
[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 llvm-svn: 331556
Diffstat (limited to 'clang/lib/StaticAnalyzer')
-rw-r--r--clang/lib/StaticAnalyzer/Core/RegionStore.cpp46
-rw-r--r--clang/lib/StaticAnalyzer/Core/SValBuilder.cpp9
2 files changed, 52 insertions, 3 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index c4bc9810919..7f2c1d58262 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1606,7 +1606,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
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::getBindingForElement(RegionBindingsConstRef B,
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::getBindingForField(RegionBindingsConstRef B,
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);
}
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index ab5ec9f12fc..137e9a7af2f 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -119,7 +119,7 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion *region) {
if (T->isNullPtrType())
return makeZeroVal(T);
-
+
if (!SymbolManager::canSymbolicate(T))
return UnknownVal();
@@ -328,12 +328,19 @@ Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
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);
OpenPOWER on IntegriCloud