summaryrefslogtreecommitdiffstats
path: root/lib/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis')
-rw-r--r--lib/Analysis/AnalysisContext.cpp21
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp26
-rw-r--r--lib/Analysis/BasicStore.cpp14
-rw-r--r--lib/Analysis/CFG.cpp22
-rw-r--r--lib/Analysis/CFRefCount.cpp83
-rw-r--r--lib/Analysis/GRExprEngine.cpp105
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp15
-rw-r--r--lib/Analysis/LiveVariables.cpp15
-rw-r--r--lib/Analysis/RegionStore.cpp140
-rw-r--r--lib/Analysis/SimpleSValuator.cpp25
10 files changed, 213 insertions, 253 deletions
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index a4cb66b..640912a 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -33,6 +33,12 @@ AnalysisContextManager::~AnalysisContextManager() {
delete I->second;
}
+void AnalysisContextManager::clear() {
+ for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
+ delete I->second;
+ Contexts.clear();
+}
+
Stmt *AnalysisContext::getBody() {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
return FD->getBody();
@@ -103,6 +109,21 @@ void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
ID.AddPointer(s);
}
+LocationContextManager::~LocationContextManager() {
+ clear();
+}
+
+void LocationContextManager::clear() {
+ for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
+ E = Contexts.end(); I != E; ) {
+ LocationContext *LC = &*I;
+ ++I;
+ delete LC;
+ }
+
+ Contexts.clear();
+}
+
StackFrameContext*
LocationContextManager::getStackFrame(AnalysisContext *ctx,
const LocationContext *parent,
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index af300f3..aa2d0ab 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -45,9 +45,9 @@ static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
}
static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
- const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
- return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
- : NULL;
+ if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
+ return ReceiverType->getDecl()->getIdentifier()->getNameStart();
+ return NULL;
}
namespace {
@@ -62,7 +62,7 @@ class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
BugReporter& BR;
ASTContext &Ctx;
- bool isNSString(const ObjCInterfaceType *T, const char* suffix);
+ bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix);
bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME);
void Warn(ExplodedNode* N, const Expr* E, const std::string& s);
@@ -114,18 +114,8 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode* N,
if (!ReceiverType)
return false;
- const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
-
- if (!name)
- return false;
-
- if (name[0] != 'N' || name[1] != 'S')
- return false;
-
- name += 2;
-
- // FIXME: Make all of this faster.
- if (isNSString(ReceiverType, name))
+ if (isNSString(ReceiverType,
+ ReceiverType->getDecl()->getIdentifier()->getName()))
return AuditNSString(N, ME);
return false;
@@ -158,8 +148,8 @@ bool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) {
//===----------------------------------------------------------------------===//
bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T,
- const char* suffix) {
- return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
+ llvm::StringRef ClassName) {
+ return ClassName == "NSString" || ClassName == "NSMutableString";
}
bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index a4f451f..d81d83c 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -49,7 +49,8 @@ public:
QualType T = QualType());
const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
- const Expr *E, unsigned Count);
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS);
const GRState *Bind(const GRState *state, Loc L, SVal V) {
return state->makeWithStore(BindInternal(state->getStore(), L, V));
@@ -623,12 +624,21 @@ StoreManager::BindingsHandler::~BindingsHandler() {}
const GRState *BasicStoreManager::InvalidateRegion(const GRState *state,
const MemRegion *R,
const Expr *E,
- unsigned Count) {
+ unsigned Count,
+ InvalidatedSymbols *IS) {
R = R->getBaseRegion();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
return state;
+ if (IS) {
+ BindingsTy B = GetBindings(state->getStore());
+ if (BindingsTy::data_type *Val = B.lookup(R)) {
+ if (SymbolRef Sym = Val->getAsSymbol())
+ IS->insert(Sym);
+ }
+ }
+
QualType T = cast<TypedRegion>(R)->getValueType(R->getContext());
SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count);
return Bind(state, loc::MemRegionVal(R), V);
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 7b1d50c..3141759 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/Format.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/OwningPtr.h"
using namespace clang;
@@ -51,7 +52,7 @@ static SourceLocation GetEndLoc(Decl* D) {
///
class VISIBILITY_HIDDEN CFGBuilder {
ASTContext *Context;
- CFG* cfg;
+ llvm::OwningPtr<CFG> cfg;
CFGBlock* Block;
CFGBlock* Succ;
@@ -79,8 +80,6 @@ public:
ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {}
- ~CFGBuilder() { delete cfg; }
-
// buildCFG - Used by external clients to construct the CFG.
CFG* buildCFG(Stmt *Statement, ASTContext *C);
@@ -195,7 +194,7 @@ static VariableArrayType* FindVA(Type* t) {
/// NULL.
CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) {
Context = C;
- assert(cfg);
+ assert(cfg.get());
if (!Statement)
return NULL;
@@ -210,7 +209,8 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) {
// Visit the statements and create the CFG.
CFGBlock* B = addStmt(Statement);
- if (!B) B = Succ;
+ if (!B)
+ B = Succ;
if (B) {
// Finalize the last constructed block. This usually involves reversing the
@@ -254,17 +254,7 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) {
// Create an empty entry block that has no predecessors.
cfg->setEntry(createBlock());
- if (badCFG) {
- delete cfg;
- cfg = NULL;
- return NULL;
- }
-
- // NULL out cfg so that repeated calls to the builder will fail and that the
- // ownership of the constructed CFG is passed to the caller.
- CFG* t = cfg;
- cfg = NULL;
- return t;
+ return badCFG ? NULL : cfg.take();
}
/// createBlock - Used to lazily create blocks that are connected
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index eb1265d..c629ad1 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -81,7 +81,7 @@ static NamingConvention deriveNamingConvention(Selector S) {
if (!II)
return NoConvention;
- const char *s = II->getName();
+ const char *s = II->getNameStart();
// A method/function name may contain a prefix. We don't know it is there,
// however, until we encounter the first '_'.
@@ -93,12 +93,14 @@ static NamingConvention deriveNamingConvention(Selector S) {
// Skip '_'.
if (*s == '_') {
if (InPossiblePrefix) {
+ // If we already have a convention, return it. Otherwise, skip
+ // the prefix as if it wasn't there.
+ if (C != NoConvention)
+ break;
+
InPossiblePrefix = false;
AtBeginning = true;
- // Discard whatever 'convention' we
- // had already derived since it occurs
- // in the prefix.
- C = NoConvention;
+ assert(C == NoConvention);
}
++s;
continue;
@@ -208,41 +210,16 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
// Type querying functions.
//===----------------------------------------------------------------------===//
-static bool hasPrefix(const char* s, const char* prefix) {
- if (!prefix)
- return true;
-
- char c = *s;
- char cP = *prefix;
-
- while (c != '\0' && cP != '\0') {
- if (c != cP) break;
- c = *(++s);
- cP = *(++prefix);
- }
-
- return cP == '\0';
-}
-
-static bool hasSuffix(const char* s, const char* suffix) {
- const char* loc = strstr(s, suffix);
- return loc && strcmp(suffix, loc) == 0;
-}
-
static bool isRefType(QualType RetTy, const char* prefix,
ASTContext* Ctx = 0, const char* name = 0) {
// Recursively walk the typedef stack, allowing typedefs of reference types.
- while (1) {
- if (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
- const char* TDName = TD->getDecl()->getIdentifier()->getName();
- if (hasPrefix(TDName, prefix) && hasSuffix(TDName, "Ref"))
- return true;
+ while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
+ llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
+ if (TDName.startswith(prefix) && TDName.endswith("Ref"))
+ return true;
- RetTy = TD->getDecl()->getUnderlyingType();
- continue;
- }
- break;
+ RetTy = TD->getDecl()->getUnderlyingType();
}
if (!Ctx || !name)
@@ -254,7 +231,7 @@ static bool isRefType(QualType RetTy, const char* prefix,
return false;
// Does the name start with the prefix?
- return hasPrefix(name, prefix);
+ return llvm::StringRef(name).startswith(prefix);
}
//===----------------------------------------------------------------------===//
@@ -956,7 +933,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the
// function's type.
const FunctionType* FT = FD->getType()->getAs<FunctionType>();
- const char* FName = FD->getIdentifier()->getName();
+ const char* FName = FD->getIdentifier()->getNameStart();
// Strip away preceding '_'. Doing this here will effect all the checks
// down below.
@@ -1009,7 +986,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// Part of <rdar://problem/6961230>. (IOKit)
// This should be addressed using a API table.
ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,DoNothing);
}
break;
@@ -1432,16 +1409,19 @@ void RetainSummaryManager::InitializeClassMethodSummaries() {
addNSObjectClsMethSummary(GetUnarySelector("allocWithZone", Ctx), Summ);
// Create the [NSAssertionHandler currentHander] summary.
- addClsMethSummary(&Ctx.Idents.get("NSAssertionHandler"),
- GetNullarySelector("currentHandler", Ctx),
+ addClassMethSummary("NSAssertionHandler", "currentHandler",
getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC)));
// Create the [NSAutoreleasePool addObject:] summary.
ScratchArgs = AF.Add(ScratchArgs, 0, Autorelease);
- addClsMethSummary(&Ctx.Idents.get("NSAutoreleasePool"),
- GetUnarySelector("addObject", Ctx),
- getPersistentSummary(RetEffect::MakeNoRet(),
- DoNothing, Autorelease));
+ addClassMethSummary("NSAutoreleasePool", "addObject",
+ getPersistentSummary(RetEffect::MakeNoRet(),
+ DoNothing, Autorelease));
+
+ // Create a summary for [NSCursor dragCopyCursor].
+ addClassMethSummary("NSCursor", "dragCopyCursor",
+ getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
+ DoNothing));
// Create the summaries for [NSObject performSelector...]. We treat
// these as 'stop tracking' for the arguments because they are often
@@ -2856,14 +2836,13 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
// FIXME: What about layers of ElementRegions?
}
- // Is the invalidated variable something that we were tracking?
- SymbolRef Sym = state->getSValAsScalarOrLoc(R).getAsLocSymbol();
-
- // Remove any existing reference-count binding.
- if (Sym)
- state = state->remove<RefBindings>(Sym);
-
- state = StoreMgr.InvalidateRegion(state, R, *I, Count);
+ StoreManager::InvalidatedSymbols IS;
+ state = StoreMgr.InvalidateRegion(state, R, *I, Count, &IS);
+ for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
+ E = IS.end(); I!=E; ++I) {
+ // Remove any existing reference-count binding.
+ state = state->remove<RefBindings>(*I);
+ }
}
else {
// Nuke all other arguments passed by reference.
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 5079ace..ea0255d 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -207,7 +207,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Precondition: the first argument of 'main' is an integer guaranteed
// to be > 0.
- if (strcmp(FD->getIdentifier()->getName(), "main") == 0 &&
+ if (FD->getIdentifier()->getName() == "main" &&
FD->getNumParams() > 0) {
const ParmVarDecl *PD = FD->getParamDecl(0);
QualType T = PD->getType();
@@ -1445,10 +1445,9 @@ static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE,
// HACK: Some functions are not marked noreturn, and don't return.
// Here are a few hardwired ones. If this takes too long, we can
// potentially cache these results.
- const char* s = FD->getIdentifier()->getName();
- unsigned n = strlen(s);
+ const char* s = FD->getIdentifier()->getNameStart();
- switch (n) {
+ switch (FD->getIdentifier()->getLength()) {
default:
break;
@@ -2788,66 +2787,55 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
SVal RightV = state->getSVal(RHS);
BinaryOperator::Opcode Op = B->getOpcode();
- switch (Op) {
- case BinaryOperator::Assign: {
-
- // EXPERIMENTAL: "Conjured" symbols.
- // FIXME: Handle structs.
- QualType T = RHS->getType();
-
- if ((RightV.isUnknown() ||
- !getConstraintManager().canReasonAbout(RightV))
- && (Loc::IsLocType(T) ||
- (T->isScalarType() && T->isIntegerType()))) {
- unsigned Count = Builder->getCurrentBlockCount();
- RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count);
- }
- // Simulate the effects of a "store": bind the value of the RHS
- // to the L-Value represented by the LHS.
- EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV),
- LeftV, RightV);
- continue;
+ if (Op == BinaryOperator::Assign) {
+ // EXPERIMENTAL: "Conjured" symbols.
+ // FIXME: Handle structs.
+ QualType T = RHS->getType();
+
+ if ((RightV.isUnknown()||!getConstraintManager().canReasonAbout(RightV))
+ && (Loc::IsLocType(T) || (T->isScalarType()&&T->isIntegerType()))) {
+ unsigned Count = Builder->getCurrentBlockCount();
+ RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count);
}
-
- // FALL-THROUGH.
-
- default: {
-
- if (B->isAssignmentOp())
- break;
-
- // Process non-assignments except commas or short-circuited
- // logical expressions (LAnd and LOr).
- SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
-
- if (Result.isUnknown()) {
- if (OldSt != state) {
- // Generate a new node if we have already created a new state.
- MakeNode(Dst, B, *I2, state);
- }
- else
- Dst.Add(*I2);
-
- continue;
+
+ // Simulate the effects of a "store": bind the value of the RHS
+ // to the L-Value represented by the LHS.
+ EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV), LeftV, RightV);
+ continue;
+ }
+
+ if (!B->isAssignmentOp()) {
+ // Process non-assignments except commas or short-circuited
+ // logical expressions (LAnd and LOr).
+ SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
+
+ if (Result.isUnknown()) {
+ if (OldSt != state) {
+ // Generate a new node if we have already created a new state.
+ MakeNode(Dst, B, *I2, state);
}
-
- state = state->BindExpr(B, Result);
-
- if (Result.isUndef()) {
- // The operands were *not* undefined, but the result is undefined.
- // This is a special node that should be flagged as an error.
- if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){
- UndefNode->markAsSink();
- UndefResults.insert(UndefNode);
- }
- continue;
+ else
+ Dst.Add(*I2);
+
+ continue;
+ }
+
+ state = state->BindExpr(B, Result);
+
+ if (Result.isUndef()) {
+ // The operands were *not* undefined, but the result is undefined.
+ // This is a special node that should be flagged as an error.
+ if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){
+ UndefNode->markAsSink();
+ UndefResults.insert(UndefNode);
}
-
- // Otherwise, create a new node.
- MakeNode(Dst, B, *I2, state);
continue;
}
+
+ // Otherwise, create a new node.
+ MakeNode(Dst, B, *I2, state);
+ continue;
}
assert (B->isCompoundAssignmentOp());
@@ -2875,7 +2863,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
for (ExplodedNodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3;
++I3) {
-
state = GetState(*I3);
SVal V = state->getSVal(LHS);
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index cc1ec4b..da24192 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -742,11 +742,11 @@ void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
}
}
-class VISIBILITY_HIDDEN CheckBadDiv : public CheckerVisitor<CheckBadDiv> {
+class VISIBILITY_HIDDEN CheckDivZero : public CheckerVisitor<CheckDivZero> {
DivZero *BT;
public:
- CheckBadDiv() : BT(0) {}
- ~CheckBadDiv() {}
+ CheckDivZero() : BT(0) {}
+ ~CheckDivZero() {}
const void *getTag() {
static int x;
@@ -756,8 +756,8 @@ public:
void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
};
-void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void CheckDivZero::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
BinaryOperator::Opcode Op = B->getOpcode();
if (Op != BinaryOperator::Div &&
Op != BinaryOperator::Rem &&
@@ -792,7 +792,8 @@ void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C,
return;
}
- // If we get here, then the denom should not be zero.
+ // If we get here, then the denom should not be zero. We abandon the implicit
+ // zero denom case for now.
if (stateNotZero != C.getState())
C.addTransition(C.GenerateNode(B, stateNotZero));
}
@@ -828,5 +829,5 @@ void GRExprEngine::RegisterInternalChecks() {
registerCheck(new CheckAttrNonNull());
registerCheck(new CheckUndefinedArg());
registerCheck(new CheckBadCall());
- registerCheck(new CheckBadDiv());
+ registerCheck(new CheckDivZero());
}
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 4d96c8f..ae78d1f 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -21,9 +21,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
-
-#include <string.h>
-#include <stdio.h>
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -341,20 +339,19 @@ void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
E = AD.end_decl(); I!=E; ++I)
if (V.getDeclBit(I->second)) {
- fprintf(stderr, " %s <", I->first->getIdentifier()->getName());
+ llvm::errs() << " " << I->first->getIdentifier()->getName() << " <";
I->first->getLocation().dump(SM);
- fprintf(stderr, ">\n");
+ llvm::errs() << ">\n";
}
}
void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
E = getBlockDataMap().end(); I!=E; ++I) {
- fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n",
- I->first->getBlockID());
-
+ llvm::errs() << "\n[ B" << I->first->getBlockID()
+ << " (live variables at block exit) ]\n";
dumpLiveness(I->second,M);
}
- fprintf(stderr,"\n");
+ llvm::errs() << "\n";
}
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 9456ab6..780772a 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -262,7 +262,8 @@ public:
//===-------------------------------------------------------------------===//
const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
- const Expr *E, unsigned Count);
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS);
private:
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
@@ -455,7 +456,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
const MemRegion *R,
const Expr *Ex,
- unsigned Count) {
+ unsigned Count,
+ InvalidatedSymbols *IS) {
ASTContext& Ctx = StateMgr.getContext();
// Strip away casts.
@@ -490,9 +492,21 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
if (Optional<SVal> V = getDirectBinding(B, R)) {
if (const MemRegion *RV = V->getAsRegion())
WorkList.push_back(RV);
+
+ // A symbol? Mark it touched by the invalidation.
+ if (IS) {
+ if (SymbolRef Sym = V->getAsSymbol())
+ IS->insert(Sym);
+ }
}
- // Handle region.
+ // Symbolic region? Mark that symbol touched by the invalidation.
+ if (IS) {
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ IS->insert(SR->getSymbol());
+ }
+
+ // Handle the region itself.
if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
isa<ObjCObjectRegion>(R)) {
// Invalidate the region by setting its default value to
@@ -1230,8 +1244,8 @@ SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state,
const MemRegion *superR = R->getSuperRegion();
- // Check if the super region has a binding.
- if (Optional<SVal> V = getDirectBinding(B, superR)) {
+ // Check if the super region has a default binding.
+ if (Optional<SVal> V = getDefaultBinding(B, superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1376,7 +1390,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
// For now, just invalidate the fields of the struct/union/class.
// FIXME: Precisely handle the fields of the record.
if (superTy->isRecordType())
- return InvalidateRegion(state, superR, NULL, 0);
+ return InvalidateRegion(state, superR, NULL, 0, NULL);
}
}
}
@@ -1588,36 +1602,13 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
//===----------------------------------------------------------------------===//
// State pruning.
//===----------------------------------------------------------------------===//
-
-namespace {
-class VISIBILITY_HIDDEN RBDNode
- : public std::pair<const GRState*, const MemRegion *> {
-public:
- RBDNode(const GRState *st, const MemRegion *r)
- : std::pair<const GRState*, const MemRegion*>(st, r) {}
-
- const GRState *getState() const { return first; }
- const MemRegion *getRegion() const { return second; }
-};
-
-enum VisitFlag { NotVisited = 0, VisitedFromSubRegion, VisitedFromSuperRegion };
-
-class RBDItem : public RBDNode {
-private:
- const VisitFlag VF;
-
-public:
- RBDItem(const GRState *st, const MemRegion *r, VisitFlag vf)
- : RBDNode(st, r), VF(vf) {}
-
- VisitFlag getVisitFlag() const { return VF; }
-};
-} // end anonymous namespace
void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
+ typedef std::pair<const GRState*, const MemRegion *> RBDNode;
+
Store store = state.getStore();
RegionBindings B = GetRegionBindings(store);
@@ -1638,27 +1629,26 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Process the "intermediate" roots to find if they are referenced by
// real roots.
- llvm::SmallVector<RBDItem, 10> WorkList;
- llvm::DenseMap<const MemRegion*,unsigned> IntermediateVisited;
+ llvm::SmallVector<RBDNode, 10> WorkList;
+ llvm::DenseSet<const MemRegion*> IntermediateVisited;
while (!IntermediateRoots.empty()) {
const MemRegion* R = IntermediateRoots.back();
IntermediateRoots.pop_back();
- unsigned &visited = IntermediateVisited[R];
- if (visited)
+ if (IntermediateVisited.count(R))
continue;
- visited = 1;
+ IntermediateVisited.insert(R);
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
if (SymReaper.isLive(Loc, VR->getDecl()))
- WorkList.push_back(RBDItem(&state, VR, VisitedFromSuperRegion));
+ WorkList.push_back(std::make_pair(&state, VR));
continue;
}
if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
if (SymReaper.isLive(SR->getSymbol()))
- WorkList.push_back(RBDItem(&state, SR, VisitedFromSuperRegion));
+ WorkList.push_back(std::make_pair(&state, SR));
continue;
}
@@ -1671,54 +1661,40 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Enqueue the RegionRoots onto WorkList.
for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(),
E=RegionRoots.end(); I!=E; ++I) {
- WorkList.push_back(RBDItem(&state, *I, VisitedFromSuperRegion));
+ WorkList.push_back(std::make_pair(&state, *I));
}
RegionRoots.clear();
- // Process the worklist.
- typedef llvm::DenseMap<std::pair<const GRState*, const MemRegion*>, VisitFlag>
- VisitMap;
-
- VisitMap Visited;
+ llvm::DenseSet<RBDNode> Visited;
while (!WorkList.empty()) {
- RBDItem N = WorkList.back();
+ RBDNode N = WorkList.back();
WorkList.pop_back();
// Have we visited this node before?
- VisitFlag &VF = Visited[N];
- if (VF >= N.getVisitFlag())
+ if (Visited.count(N))
continue;
+ Visited.insert(N);
+
+ const MemRegion *R = N.second;
+ const GRState *state_N = N.first;
- const MemRegion *R = N.getRegion();
- const GRState *state_N = N.getState();
-
- // Enqueue subregions?
- if (N.getVisitFlag() == VisitedFromSuperRegion) {
- RegionStoreSubRegionMap *M;
-
- if (&state == state_N)
- M = SubRegions.get();
- else {
- RegionStoreSubRegionMap *& SM = SC[state_N];
- if (!SM)
- SM = getRegionStoreSubRegionMap(state_N->getStore());
- M = SM;
- }
+ // Enqueue subregions.
+ RegionStoreSubRegionMap *M;
- RegionStoreSubRegionMap::iterator I, E;
- for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I)
- WorkList.push_back(RBDItem(state_N, *I, VisitedFromSuperRegion));
- }
-
- // At this point, if we have already visited this region before, we are
- // done.
- if (VF != NotVisited) {
- VF = N.getVisitFlag();
- continue;
+ if (&state == state_N)
+ M = SubRegions.get();
+ else {
+ RegionStoreSubRegionMap *& SM = SC[state_N];
+ if (!SM)
+ SM = getRegionStoreSubRegionMap(state_N->getStore());
+ M = SM;
}
- VF = N.getVisitFlag();
+ RegionStoreSubRegionMap::iterator I, E;
+ for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I)
+ WorkList.push_back(std::make_pair(state_N, *I));
+
// Enqueue the super region.
if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
const MemRegion *superR = SR->getSuperRegion();
@@ -1726,12 +1702,9 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// If 'R' is a field or an element, we want to keep the bindings
// for the other fields and elements around. The reason is that
// pointer arithmetic can get us to the other fields or elements.
- // FIXME: add an assertion that this is always true.
- VisitFlag NewVisit =
- isa<FieldRegion>(R) || isa<ElementRegion>(R) || isa<ObjCIvarRegion>(R)
- ? VisitedFromSuperRegion : VisitedFromSubRegion;
-
- WorkList.push_back(RBDItem(state_N, superR, NewVisit));
+ assert(isa<FieldRegion>(R) || isa<ElementRegion>(R)
+ || isa<ObjCIvarRegion>(R));
+ WorkList.push_back(std::make_pair(state_N, superR));
}
}
@@ -1752,8 +1725,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) {
const LazyCompoundValData *D = LCV->getCVData();
- WorkList.push_back(RBDItem(D->getState(), D->getRegion(),
- VisitedFromSuperRegion));
+ WorkList.push_back(std::make_pair(D->getState(), D->getRegion()));
}
else {
// Update the set of live symbols.
@@ -1763,7 +1735,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// If V is a region, then add it to the worklist.
if (const MemRegion *RX = V->getAsRegion())
- WorkList.push_back(RBDItem(state_N, RX, VisitedFromSuperRegion));
+ WorkList.push_back(std::make_pair(state_N, RX));
}
}
}
@@ -1774,7 +1746,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion* R = I.getKey();
// If this region live? Is so, none of its symbols are dead.
- if (Visited.find(std::make_pair(&state, R)) != Visited.end())
+ if (Visited.count(std::make_pair(&state, R)))
continue;
// Remove this dead region from the store.
@@ -1820,7 +1792,7 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
void RegionStoreManager::print(Store store, llvm::raw_ostream& OS,
const char* nl, const char *sep) {
RegionBindings B = GetRegionBindings(store);
- OS << "Store (direct bindings):" << nl;
+ OS << "Store (direct and default bindings):" << nl;
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
OS << ' ' << I.getKey() << " : " << I.getData() << nl;
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 636ce15..4487aa9 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -346,16 +346,29 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state,
nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs);
SymbolRef Sym = slhs->getSymbol();
- // Does the symbol simplify to a constant?
+ // Does the symbol simplify to a constant? If so, "fold" the constant
+ // by setting 'lhs' to a ConcreteInt and try again.
if (Sym->getType(ValMgr.getContext())->isIntegerType())
if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
- // What should we convert it to?
- if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){
- BasicValueFactory &BVF = ValMgr.getBasicValueFactory();
- lhs = nonloc::ConcreteInt(BVF.Convert(rhs_I->getValue(),
- *Constant));
+ // The symbol evaluates to a constant. If necessary, promote the
+ // folded constant (LHS) to the result type.
+ BasicValueFactory &BVF = ValMgr.getBasicValueFactory();
+ const llvm::APSInt &lhs_I = BVF.Convert(resultTy, *Constant);
+ lhs = nonloc::ConcreteInt(lhs_I);
+
+ // Also promote the RHS (if necessary).
+
+ // For shifts, it necessary promote the RHS to the result type.
+ if (BinaryOperator::isShiftOp(op))
continue;
+
+ // Other operators: do an implicit conversion. This shouldn't be
+ // necessary once we support truncation/extension of symbolic values.
+ if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){
+ rhs = nonloc::ConcreteInt(BVF.Convert(resultTy, rhs_I->getValue()));
}
+
+ continue;
}
if (isa<nonloc::ConcreteInt>(rhs)) {
OpenPOWER on IntegriCloud