diff options
Diffstat (limited to 'lib/Analysis')
-rw-r--r-- | lib/Analysis/AnalysisContext.cpp | 21 | ||||
-rw-r--r-- | lib/Analysis/BasicObjCFoundationChecks.cpp | 26 | ||||
-rw-r--r-- | lib/Analysis/BasicStore.cpp | 14 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 22 | ||||
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 83 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 105 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngineInternalChecks.cpp | 15 | ||||
-rw-r--r-- | lib/Analysis/LiveVariables.cpp | 15 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 140 | ||||
-rw-r--r-- | lib/Analysis/SimpleSValuator.cpp | 25 |
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)) { |