diff options
author | Ed Schouten <ed@FreeBSD.org> | 2009-06-27 10:45:02 +0000 |
---|---|---|
committer | Ed Schouten <ed@FreeBSD.org> | 2009-06-27 10:45:02 +0000 |
commit | 4ebdf5c4f587daef4e0be499802eac3a7a49bf2f (patch) | |
tree | 2c5a83521a20c02e7805581a174008aa9bc23579 /lib/Analysis | |
parent | f698f7e71940663e26a4806a96fb0bdfa160c886 (diff) |
Notes
Diffstat (limited to 'lib/Analysis')
-rw-r--r-- | lib/Analysis/BasicConstraintManager.cpp | 12 | ||||
-rw-r--r-- | lib/Analysis/BasicStore.cpp | 14 | ||||
-rw-r--r-- | lib/Analysis/BugReporter.cpp | 2 | ||||
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 33 | ||||
-rw-r--r-- | lib/Analysis/CMakeLists.txt | 3 | ||||
-rw-r--r-- | lib/Analysis/CheckObjCUnusedIVars.cpp | 5 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 101 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngineInternalChecks.cpp | 3 | ||||
-rw-r--r-- | lib/Analysis/GRSimpleVals.cpp | 415 | ||||
-rw-r--r-- | lib/Analysis/GRSimpleVals.h | 86 | ||||
-rw-r--r-- | lib/Analysis/GRState.cpp | 79 | ||||
-rw-r--r-- | lib/Analysis/GRTransferFuncs.cpp | 27 | ||||
-rw-r--r-- | lib/Analysis/PathDiagnostic.cpp | 2 | ||||
-rw-r--r-- | lib/Analysis/RangeConstraintManager.cpp | 8 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 219 | ||||
-rw-r--r-- | lib/Analysis/SVals.cpp | 29 | ||||
-rw-r--r-- | lib/Analysis/SimpleSValuator.cpp | 346 | ||||
-rw-r--r-- | lib/Analysis/SymbolManager.cpp | 6 |
18 files changed, 608 insertions, 782 deletions
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp index ffa8a8625bdf4..cb89d30651079 100644 --- a/lib/Analysis/BasicConstraintManager.cpp +++ b/lib/Analysis/BasicConstraintManager.cpp @@ -83,7 +83,7 @@ public: const GRState* RemoveDeadBindings(const GRState* state, SymbolReaper& SymReaper); - void print(const GRState* state, std::ostream& Out, + void print(const GRState* state, llvm::raw_ostream& Out, const char* nl, const char *sep); }; @@ -280,7 +280,7 @@ BasicConstraintManager::RemoveDeadBindings(const GRState* state, return state->set<ConstNotEq>(CNE); } -void BasicConstraintManager::print(const GRState* state, std::ostream& Out, +void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out, const char* nl, const char *sep) { // Print equality constraints. @@ -288,12 +288,8 @@ void BasicConstraintManager::print(const GRState* state, std::ostream& Out, if (!CE.isEmpty()) { Out << nl << sep << "'==' constraints:"; - - for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) { - Out << nl << " $" << I.getKey(); - llvm::raw_os_ostream OS(Out); - OS << " : " << *I.getData(); - } + for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) + Out << nl << " $" << I.getKey() << " : " << *I.getData(); } // Print != constraints. diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 6b346cd52557e..8fbce528fa9a6 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -112,7 +112,8 @@ public: return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store)); } - void print(Store store, std::ostream& Out, const char* nl, const char *sep); + void print(Store store, llvm::raw_ostream& Out, const char* nl, + const char *sep); private: ASTContext& getContext() { return StateMgr.getContext(); } @@ -535,7 +536,7 @@ Store BasicStoreManager::getInitialStore() { // Initialize globals and parameters to symbolic values. // Initialize local variables to undefined. - const MemRegion *R = StateMgr.getRegion(VD); + const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD); SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) || isa<ImplicitParamDecl>(VD)) ? ValMgr.getRegionValueSymbolVal(R) @@ -602,18 +603,19 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, return store; } -void BasicStoreManager::print(Store store, std::ostream& O, +void BasicStoreManager::print(Store store, llvm::raw_ostream& Out, const char* nl, const char *sep) { - llvm::raw_os_ostream Out(O); BindingsTy B = GetBindings(store); Out << "Variables:" << nl; bool isFirst = true; for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) { - if (isFirst) isFirst = false; - else Out << nl; + if (isFirst) + isFirst = false; + else + Out << nl; Out << ' ' << I.getKey() << " : "; I.getData().print(Out); diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index 9c9029cfff347..38ea458a65994 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines BugReporter, a utility class for generating -// PathDiagnostics for analyses based on GRSimpleVals. +// PathDiagnostics. // //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 46333a74f27d7..f4a28e0c19fd2 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "GRSimpleVals.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" @@ -22,6 +21,7 @@ #include "clang/Analysis/PathDiagnostic.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" #include "clang/AST/DeclObjC.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -30,7 +30,6 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Compiler.h" #include "llvm/ADT/STLExtras.h" -#include <ostream> #include <stdarg.h> using namespace clang; @@ -1674,10 +1673,10 @@ public: ID.Add(T); } - void print(std::ostream& Out) const; + void print(llvm::raw_ostream& Out) const; }; -void RefVal::print(std::ostream& Out) const { +void RefVal::print(llvm::raw_ostream& Out) const { if (!T.isNull()) Out << "Tracked Type:" << T.getAsString() << '\n'; @@ -1827,11 +1826,11 @@ static const GRState * SendAutorelease(const GRState *state, namespace { -class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals { +class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs { public: class BindingsPrinter : public GRState::Printer { public: - virtual void Print(std::ostream& Out, const GRState* state, + virtual void Print(llvm::raw_ostream& Out, const GRState* state, const char* nl, const char* sep); }; @@ -1959,7 +1958,8 @@ public: } // end anonymous namespace -static void PrintPool(std::ostream &Out, SymbolRef Sym, const GRState *state) { +static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym, + const GRState *state) { Out << ' '; if (Sym) Out << Sym->getSymbolID(); @@ -1975,10 +1975,9 @@ static void PrintPool(std::ostream &Out, SymbolRef Sym, const GRState *state) { Out << '}'; } -void CFRefCount::BindingsPrinter::Print(std::ostream& Out, const GRState* state, +void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out, + const GRState* state, const char* nl, const char* sep) { - - RefBindings B = state->get<RefBindings>(); @@ -2790,10 +2789,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, if (Summ.getArg(idx) == DoNothingByRef) continue; - // Invalidate the value of the variable passed by reference. - - // FIXME: Either this logic should also be replicated in GRSimpleVals - // or should be pulled into a separate "constraint engine." + // Invalidate the value of the variable passed by reference. // FIXME: We can have collisions on the conjured symbol if the // expression *I also creates conjured symbols. We probably want @@ -2942,11 +2938,10 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, default: assert (false && "Unhandled RetEffect."); break; - case RetEffect::NoRet: { - + case RetEffect::NoRet: { // Make up a symbol for the return value (not reference counted). - // FIXME: This is basically copy-and-paste from GRSimpleVals. We - // should compose behavior, not copy it. + // FIXME: Most of this logic is not specific to the retain/release + // checker. // FIXME: We eventually should handle structs and other compound types // that are returned by value. @@ -3091,7 +3086,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, if (Expr* Receiver = ME->getReceiver()) { SVal X = St->getSValAsScalarOrLoc(Receiver); if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X)) - if (L->getRegion() == Eng.getStateManager().getSelfRegion(St)) { + if (L->getRegion() == St->getSelfRegion()) { // Update the summary to make the default argument effect // 'StopTracking'. Summ = Summaries.copySummary(Summ); diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index e064e3c71a832..7d6a619736e0f 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -18,15 +18,14 @@ add_clang_library(clangAnalysis GRCoreEngine.cpp GRExprEngine.cpp GRExprEngineInternalChecks.cpp - GRSimpleVals.cpp GRState.cpp - GRTransferFuncs.cpp LiveVariables.cpp MemRegion.cpp PathDiagnostic.cpp RangeConstraintManager.cpp RegionStore.cpp SimpleConstraintManager.cpp + SimpleSValuator.cpp Store.cpp SVals.cpp SymbolManager.cpp diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp index 92c50e2a9185c..21dc658dfa1a5 100644 --- a/lib/Analysis/CheckObjCUnusedIVars.cpp +++ b/lib/Analysis/CheckObjCUnusedIVars.cpp @@ -20,7 +20,6 @@ #include "clang/AST/Expr.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/LangOptions.h" -#include <sstream> using namespace clang; @@ -97,8 +96,8 @@ void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) { // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) if (I->second == Unused) { - - std::ostringstream os; + std::string sbuf; + llvm::raw_string_ostream os(sbuf); os << "Instance variable '" << I->first->getNameAsString() << "' in class '" << ID->getNameAsString() << "' is never used by the methods in its @implementation " diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 7d56d108debe2..8b4f5c8f11c10 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -15,7 +15,6 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" @@ -29,7 +28,6 @@ #ifndef NDEBUG #include "llvm/Support/GraphWriter.h" -#include <sstream> #endif using namespace clang; @@ -126,6 +124,7 @@ GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, StateMgr(G.getContext(), SMC, CMC, G.getAllocator(), cfg, CD, L), SymMgr(StateMgr.getSymbolManager()), ValMgr(StateMgr.getValueManager()), + SVator(clang::CreateSimpleSValuator(ValMgr)), // FIXME: Generalize later. CurrentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", G.getContext())), @@ -176,7 +175,7 @@ const GRState* GRExprEngine::getInitialState() { const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); if (T->isIntegerType()) - if (const MemRegion *R = StateMgr.getRegion(PD)) { + if (const MemRegion *R = state->getRegion(PD)) { SVal V = state->getSVal(loc::MemRegionVal(R)); SVal Constraint = EvalBinOp(state, BinaryOperator::GT, V, ValMgr.makeZeroVal(T), @@ -1046,7 +1045,7 @@ void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred, else { // We are binding to a value other than 'unknown'. Perform the binding // using the StoreManager. - newState = StateMgr.BindLoc(state, cast<Loc>(location), Val); + newState = state->bindLoc(cast<Loc>(location), Val); } // The next thing to do is check if the GRTransferFuncs object wants to @@ -1296,9 +1295,8 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet<GRState>& Dst, SVal oldValueVal = stateLoad->getSVal(oldValueExpr); // Perform the comparison. - SVal Cmp = Engine.EvalBinOp(stateLoad, - BinaryOperator::EQ, theValueVal, oldValueVal, - Engine.getContext().IntTy); + SVal Cmp = Engine.EvalBinOp(stateLoad, BinaryOperator::EQ, theValueVal, + oldValueVal, Engine.getContext().IntTy); const GRState *stateEqual = stateLoad->assume(Cmp, true); @@ -2247,17 +2245,17 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) { InitVal = ValMgr.getConjuredSymbolVal(InitEx, Count); } - state = StateMgr.BindDecl(state, VD, InitVal); + state = state->bindDecl(VD, InitVal); // The next thing to do is check if the GRTransferFuncs object wants to // update the state based on the new binding. If the GRTransferFunc // object doesn't do anything, just auto-propagate the current state. GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true); - getTF().EvalBind(BuilderRef, loc::MemRegionVal(StateMgr.getRegion(VD)), + getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD)), InitVal); } else { - state = StateMgr.BindDeclWithNoInit(state, VD); + state = state->bindDeclWithNoInit(VD); MakeNode(Dst, DS, *I, state); } } @@ -2562,7 +2560,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, case UnaryOperator::Minus: // FIXME: Do we need to handle promotions? - state = state->bindExpr(U, EvalMinus(U, cast<NonLoc>(V))); + state = state->bindExpr(U, EvalMinus(cast<NonLoc>(V))); break; case UnaryOperator::LNot: @@ -2571,25 +2569,21 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, // // Note: technically we do "E == 0", but this is the same in the // transfer functions as "0 == E". + SVal Result; if (isa<Loc>(V)) { Loc X = ValMgr.makeNull(); - SVal Result = EvalBinOp(state,BinaryOperator::EQ, cast<Loc>(V), X, - U->getType()); - state = state->bindExpr(U, Result); + Result = EvalBinOp(state, BinaryOperator::EQ, cast<Loc>(V), X, + U->getType()); } else { nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType())); -#if 0 - SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X); - state = SetSVal(state, U, Result); -#else - EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I, - U->getType()); - continue; -#endif + Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X, + U->getType()); } + state = state->bindExpr(U, Result); + break; } @@ -2640,8 +2634,8 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, Builder->getCurrentBlockCount()); // If the value is a location, ++/-- should always preserve - // non-nullness. Check if the original value was non-null, and if so propagate - // that constraint. + // non-nullness. Check if the original value was non-null, and if so + // propagate that constraint. if (Loc::IsLocType(U->getType())) { SVal Constraint = EvalBinOp(state, BinaryOperator::EQ, V2, ValMgr.makeZeroVal(U->getType()), @@ -2907,9 +2901,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, if (B->isAssignmentOp()) break; - // Process non-assignements except commas or short-circuited - // logical expressions (LAnd and LOr). - + // 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()) { @@ -3024,7 +3017,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, } // Compute the result of the operation. - SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy), + SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy), B->getType()); if (Result.isUndef()) { @@ -3073,26 +3066,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // Transfer-function Helpers. //===----------------------------------------------------------------------===// -void GRExprEngine::EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex, - BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, - ExplodedNode<GRState>* Pred, QualType T) { - - GRStateSet OStates; - EvalBinOp(OStates, GetState(Pred), Ex, Op, L, R, T); - - for (GRStateSet::iterator I=OStates.begin(), E=OStates.end(); I!=E; ++I) - MakeNode(Dst, Ex, Pred, *I); -} - -void GRExprEngine::EvalBinOp(GRStateSet& OStates, const GRState* state, - Expr* Ex, BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, QualType T) { - - GRStateSet::AutoPopulate AP(OStates, state); - if (R.isValid()) getTF().EvalBinOpNN(OStates, *this, state, Ex, Op, L, R, T); -} - SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op, SVal L, SVal R, QualType T) { @@ -3104,9 +3077,9 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op, if (isa<Loc>(L)) { if (isa<Loc>(R)) - return getTF().EvalBinOp(*this, Op, cast<Loc>(L), cast<Loc>(R)); + return SVator->EvalBinOpLL(Op, cast<Loc>(L), cast<Loc>(R), T); else - return getTF().EvalBinOp(*this, state, Op, cast<Loc>(L), cast<NonLoc>(R)); + return SVator->EvalBinOpLN(state, Op, cast<Loc>(L), cast<NonLoc>(R), T); } if (isa<Loc>(R)) { @@ -3116,11 +3089,10 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op, assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub); // Commute the operands. - return getTF().EvalBinOp(*this, state, Op, cast<Loc>(R), cast<NonLoc>(L)); + return SVator->EvalBinOpLN(state, Op, cast<Loc>(R), cast<NonLoc>(L), T); } else - return getTF().DetermEvalBinOpNN(*this, Op, cast<NonLoc>(L), - cast<NonLoc>(R), T); + return SVator->EvalBinOpNN(Op, cast<NonLoc>(L), cast<NonLoc>(R), T); } //===----------------------------------------------------------------------===// @@ -3156,8 +3128,11 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> : return ""; } - static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) { - std::ostringstream Out; + static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*, + bool ShortNames) { + + std::string sbuf; + llvm::raw_string_ostream Out(sbuf); // Program Location. ProgramPoint Loc = N->getLocation(); @@ -3179,9 +3154,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> : SourceLocation SLoc = S->getLocStart(); Out << S->getStmtClassName() << ' ' << (void*) S << ' '; - llvm::raw_os_ostream OutS(Out); - S->printPretty(OutS); - OutS.flush(); + S->printPretty(Out); if (SLoc.isFileID()) { Out << "\\lline=" @@ -3235,10 +3208,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> : SourceLocation SLoc = T->getLocStart(); Out << "\\|Terminator: "; - - llvm::raw_os_ostream OutS(Out); - E.getSrc()->printTerminator(OutS); - OutS.flush(); + E.getSrc()->printTerminator(Out); if (SLoc.isFileID()) { Out << "\\lline=" @@ -3253,14 +3223,11 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> : if (Label) { if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) { Out << "\\lcase "; - llvm::raw_os_ostream OutS(Out); - C->getLHS()->printPretty(OutS); - OutS.flush(); + C->getLHS()->printPretty(Out); if (Stmt* RHS = C->getRHS()) { Out << " .. "; - RHS->printPretty(OutS); - OutS.flush(); + RHS->printPretty(Out); } Out << ":"; diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index 13df89ebbfdc4..76d26dd9f02af 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -672,7 +672,6 @@ public: return NULL; if (!StoreSite) { - GRStateManager &StateMgr = BRC.getStateManager(); const ExplodedNode<GRState> *Node = N, *Last = NULL; for ( ; Node ; Last = Node, Node = Node->getFirstPred()) { @@ -686,7 +685,7 @@ public: } } - if (StateMgr.GetSVal(Node->getState(), R) != V) + if (Node->getState()->getSVal(R) != V) break; } diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp deleted file mode 100644 index 480612113d10e..0000000000000 --- a/lib/Analysis/GRSimpleVals.cpp +++ /dev/null @@ -1,415 +0,0 @@ -// GRSimpleVals.cpp - Transfer functions for tracking simple values -*- C++ -*-- -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRSimpleVals, a sub-class of GRTransferFuncs that -// provides transfer functions for performing simple value tracking with -// limited support for symbolics. -// -//===----------------------------------------------------------------------===// - -#include "GRSimpleVals.h" -#include "BasicObjCFoundationChecks.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "llvm/Support/Compiler.h" -#include <sstream> - -using namespace clang; - -//===----------------------------------------------------------------------===// -// Transfer Function creation for External clients. -//===----------------------------------------------------------------------===// - -GRTransferFuncs* clang::MakeGRSimpleValsTF() { return new GRSimpleVals(); } - -//===----------------------------------------------------------------------===// -// Transfer function for Casts. -//===----------------------------------------------------------------------===// - -SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLoc X, QualType T) { - - if (!isa<nonloc::ConcreteInt>(X)) - return UnknownVal(); - - bool isLocType = Loc::IsLocType(T); - - // Only handle casts from integers to integers. - if (!isLocType && !T->isIntegerType()) - return UnknownVal(); - - BasicValueFactory& BasicVals = Eng.getBasicVals(); - - llvm::APSInt V = cast<nonloc::ConcreteInt>(X).getValue(); - V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T)); - V.extOrTrunc(Eng.getContext().getTypeSize(T)); - - if (isLocType) - return loc::ConcreteInt(BasicVals.getValue(V)); - else - return nonloc::ConcreteInt(BasicVals.getValue(V)); -} - -// Casts. - -SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, Loc X, QualType T) { - - // Casts from pointers -> pointers, just return the lval. - // - // Casts from pointers -> references, just return the lval. These - // can be introduced by the frontend for corner cases, e.g - // casting from va_list* to __builtin_va_list&. - // - assert (!X.isUnknownOrUndef()); - - if (Loc::IsLocType(T) || T->isReferenceType()) - return X; - - // FIXME: Handle transparent unions where a value can be "transparently" - // lifted into a union type. - if (T->isUnionType()) - return UnknownVal(); - - assert (T->isIntegerType()); - BasicValueFactory& BasicVals = Eng.getBasicVals(); - unsigned BitWidth = Eng.getContext().getTypeSize(T); - - if (!isa<loc::ConcreteInt>(X)) - return Eng.getValueManager().makeLocAsInteger(X, BitWidth); - - llvm::APSInt V = cast<loc::ConcreteInt>(X).getValue(); - V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T)); - V.extOrTrunc(BitWidth); - return nonloc::ConcreteInt(BasicVals.getValue(V)); -} - -// Unary operators. - -SVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLoc X){ - - switch (X.getSubKind()) { - - case nonloc::ConcreteIntKind: - return cast<nonloc::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U); - - default: - return UnknownVal(); - } -} - -SVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLoc X) { - - switch (X.getSubKind()) { - - case nonloc::ConcreteIntKind: - return cast<nonloc::ConcreteInt>(X).EvalComplement(Eng.getBasicVals()); - - default: - return UnknownVal(); - } -} - -// Binary operators. - -static unsigned char LNotOpMap[] = { - (unsigned char) BinaryOperator::GE, /* LT => GE */ - (unsigned char) BinaryOperator::LE, /* GT => LE */ - (unsigned char) BinaryOperator::GT, /* LE => GT */ - (unsigned char) BinaryOperator::LT, /* GE => LT */ - (unsigned char) BinaryOperator::NE, /* EQ => NE */ - (unsigned char) BinaryOperator::EQ /* NE => EQ */ -}; - -SVal GRSimpleVals::DetermEvalBinOpNN(GRExprEngine& Eng, - BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, - QualType T) { - BasicValueFactory& BasicVals = Eng.getBasicVals(); - ValueManager& ValMgr = Eng.getValueManager(); - unsigned subkind = L.getSubKind(); - - while (1) { - - switch (subkind) { - default: - return UnknownVal(); - - case nonloc::LocAsIntegerKind: { - Loc LL = cast<nonloc::LocAsInteger>(L).getLoc(); - - switch (R.getSubKind()) { - case nonloc::LocAsIntegerKind: - return EvalBinOp(Eng, Op, LL, - cast<nonloc::LocAsInteger>(R).getLoc()); - - case nonloc::ConcreteIntKind: { - // Transform the integer into a location and compare. - ASTContext& Ctx = Eng.getContext(); - llvm::APSInt V = cast<nonloc::ConcreteInt>(R).getValue(); - V.setIsUnsigned(true); - V.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy)); - return EvalBinOp(Eng, Op, LL, ValMgr.makeLoc(V)); - } - - default: - switch (Op) { - case BinaryOperator::EQ: - return ValMgr.makeTruthVal(false); - case BinaryOperator::NE: - return ValMgr.makeTruthVal(true); - default: - // This case also handles pointer arithmetic. - return UnknownVal(); - } - } - } - - case nonloc::SymExprValKind: { - // Logical not? - if (!(Op == BinaryOperator::EQ && R.isZeroConstant())) - return UnknownVal(); - - const SymExpr &SE=*cast<nonloc::SymExprVal>(L).getSymbolicExpression(); - - // Only handle ($sym op constant) for now. - if (const SymIntExpr *E = dyn_cast<SymIntExpr>(&SE)) { - BinaryOperator::Opcode Opc = E->getOpcode(); - - if (Opc < BinaryOperator::LT || Opc > BinaryOperator::NE) - return UnknownVal(); - - // For comparison operators, translate the constraint by - // changing the opcode. - int idx = (unsigned) Opc - (unsigned) BinaryOperator::LT; - - assert (idx >= 0 && - (unsigned) idx < sizeof(LNotOpMap)/sizeof(unsigned char)); - - Opc = (BinaryOperator::Opcode) LNotOpMap[idx]; - assert(E->getType(Eng.getContext()) == T); - E = Eng.getSymbolManager().getSymIntExpr(E->getLHS(), Opc, - E->getRHS(), T); - return nonloc::SymExprVal(E); - } - - return UnknownVal(); - } - - case nonloc::ConcreteIntKind: - - if (isa<nonloc::ConcreteInt>(R)) { - const nonloc::ConcreteInt& L_CI = cast<nonloc::ConcreteInt>(L); - const nonloc::ConcreteInt& R_CI = cast<nonloc::ConcreteInt>(R); - return L_CI.EvalBinOp(BasicVals, Op, R_CI); - } - else { - subkind = R.getSubKind(); - NonLoc tmp = R; - R = L; - L = tmp; - - // Swap the operators. - switch (Op) { - case BinaryOperator::LT: Op = BinaryOperator::GT; break; - case BinaryOperator::GT: Op = BinaryOperator::LT; break; - case BinaryOperator::LE: Op = BinaryOperator::GE; break; - case BinaryOperator::GE: Op = BinaryOperator::LE; break; - default: break; - } - - continue; - } - - case nonloc::SymbolValKind: - if (isa<nonloc::ConcreteInt>(R)) { - ValueManager &ValMgr = Eng.getValueManager(); - return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(L).getSymbol(), Op, - cast<nonloc::ConcreteInt>(R).getValue(), T); - } - else - return UnknownVal(); - } - } -} - - -// Binary Operators (except assignments and comma). - -SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op, - Loc L, Loc R) { - - switch (Op) { - default: - return UnknownVal(); - case BinaryOperator::EQ: - case BinaryOperator::NE: - return EvalEquality(Eng, L, R, Op == BinaryOperator::EQ); - } -} - -SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, const GRState *state, - BinaryOperator::Opcode Op, Loc L, NonLoc R) { - - // Special case: 'R' is an integer that has the same width as a pointer and - // we are using the integer location in a comparison. Normally this cannot be - // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32 - // can generate comparisons that trigger this code. - // FIXME: Are all locations guaranteed to have pointer width? - if (BinaryOperator::isEqualityOp(Op)) { - if (nonloc::ConcreteInt *RInt = dyn_cast<nonloc::ConcreteInt>(&R)) { - const llvm::APSInt *X = &RInt->getValue(); - ASTContext &C = Eng.getContext(); - if (C.getTypeSize(C.VoidPtrTy) == X->getBitWidth()) { - // Convert the signedness of the integer (if necessary). - if (X->isSigned()) - X = &Eng.getBasicVals().getValue(*X, true); - - return EvalBinOp(Eng, Op, L, loc::ConcreteInt(*X)); - } - } - } - - // Delegate pointer arithmetic to store manager. - return Eng.getStoreManager().EvalBinOp(state, Op, L, R); -} - -// Equality operators for Locs. -// FIXME: All this logic will be revamped when we have MemRegion::getLocation() -// implemented. - -SVal GRSimpleVals::EvalEquality(GRExprEngine& Eng, Loc L, Loc R, bool isEqual) { - - ValueManager& ValMgr = Eng.getValueManager(); - - switch (L.getSubKind()) { - - default: - assert(false && "EQ/NE not implemented for this Loc."); - return UnknownVal(); - - case loc::ConcreteIntKind: - - if (isa<loc::ConcreteInt>(R)) { - bool b = cast<loc::ConcreteInt>(L).getValue() == - cast<loc::ConcreteInt>(R).getValue(); - - // Are we computing '!='? Flip the result. - if (!isEqual) - b = !b; - - return ValMgr.makeTruthVal(b); - } - else if (SymbolRef Sym = R.getAsSymbol()) { - const SymIntExpr * SE = - Eng.getSymbolManager().getSymIntExpr(Sym, - isEqual ? BinaryOperator::EQ - : BinaryOperator::NE, - cast<loc::ConcreteInt>(L).getValue(), - Eng.getContext().IntTy); - return nonloc::SymExprVal(SE); - } - - break; - - case loc::MemRegionKind: { - if (SymbolRef LSym = L.getAsLocSymbol()) { - if (isa<loc::ConcreteInt>(R)) { - const SymIntExpr *SE = - Eng.getSymbolManager().getSymIntExpr(LSym, - isEqual ? BinaryOperator::EQ - : BinaryOperator::NE, - cast<loc::ConcreteInt>(R).getValue(), - Eng.getContext().IntTy); - - return nonloc::SymExprVal(SE); - } - } - } - - // Fall-through. - - case loc::GotoLabelKind: - return ValMgr.makeTruthVal(isEqual ? L == R : L != R); - } - - return ValMgr.makeTruthVal(isEqual ? false : true); -} - -//===----------------------------------------------------------------------===// -// Transfer function for function calls. -//===----------------------------------------------------------------------===// - -void GRSimpleVals::EvalCall(ExplodedNodeSet<GRState>& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder<GRState>& Builder, - CallExpr* CE, SVal L, - ExplodedNode<GRState>* Pred) { - - GRStateManager& StateMgr = Eng.getStateManager(); - const GRState* St = Builder.GetState(Pred); - - // Invalidate all arguments passed in by reference (Locs). - - for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { - - SVal V = St->getSVal(*I); - - if (isa<loc::MemRegionVal>(V)) { - const MemRegion *R = cast<loc::MemRegionVal>(V).getRegion(); - if (R->isBoundable()) - St = StateMgr.BindLoc(St, cast<Loc>(V), UnknownVal()); - } else if (isa<nonloc::LocAsInteger>(V)) - St = StateMgr.BindLoc(St, cast<nonloc::LocAsInteger>(V).getLoc(), - UnknownVal()); - - } - - // Make up a symbol for the return value of this function. - // FIXME: We eventually should handle structs and other compound types - // that are returned by value. - QualType T = CE->getType(); - if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) { - unsigned Count = Builder.getCurrentBlockCount(); - SVal X = Eng.getValueManager().getConjuredSymbolVal(CE, Count); - St = St->bindExpr(CE, X, Eng.getCFG().isBlkExpr(CE), false); - } - - Builder.MakeNode(Dst, CE, Pred, St); -} - -//===----------------------------------------------------------------------===// -// Transfer function for Objective-C message expressions. -//===----------------------------------------------------------------------===// - -void GRSimpleVals::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder<GRState>& Builder, - ObjCMessageExpr* ME, - ExplodedNode<GRState>* Pred) { - - - // The basic transfer function logic for message expressions does nothing. - // We just invalidate all arguments passed in by references. - const GRState *St = Builder.GetState(Pred); - - for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end(); - I != E; ++I) { - - SVal V = St->getSVal(*I); - - if (isa<Loc>(V)) - St = St->bindLoc(cast<Loc>(V), UnknownVal()); - } - - Builder.MakeNode(Dst, ME, Pred, St); -} diff --git a/lib/Analysis/GRSimpleVals.h b/lib/Analysis/GRSimpleVals.h deleted file mode 100644 index 6ef49dcdd22ee..0000000000000 --- a/lib/Analysis/GRSimpleVals.h +++ /dev/null @@ -1,86 +0,0 @@ -// GRSimpleVals.h - Transfer functions for tracking simple values -*- C++ -*--// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRSimpleVals, a sub-class of GRTransferFuncs that -// provides transfer functions for performing simple value tracking with -// limited support for symbolics. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRSIMPLEVALS -#define LLVM_CLANG_ANALYSIS_GRSIMPLEVALS - -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" - -namespace clang { - -class PathDiagnostic; -class ASTContext; - -class GRSimpleVals : public GRTransferFuncs { -protected: - - virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng, - BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, QualType T); - -public: - GRSimpleVals() {} - virtual ~GRSimpleVals() {} - - // Casts. - - virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT); - virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT); - - // Unary Operators. - - virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X); - - virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X); - - // Binary Operators. - - virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, - Loc L, Loc R); - - // Pointer arithmetic. - - virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state, - BinaryOperator::Opcode Op, Loc L, NonLoc R); - - // Calls. - - virtual void EvalCall(ExplodedNodeSet<GRState>& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, - CallExpr* CE, SVal L, - ExplodedNode<GRState>* Pred); - - virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, - ObjCMessageExpr* ME, - ExplodedNode<GRState>* Pred); - - - - static void GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx, - ExplodedNode<GRState>* N); - -protected: - - // Equality (==, !=) operators for Locs. - SVal EvalEquality(GRExprEngine& Engine, Loc L, Loc R, bool isEqual); -}; - -} // end clang namespace - -#endif diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index a64b2d7f5f493..493edc37bacbb 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -1,4 +1,4 @@ -//= GRState*cpp - Path-Sens. "State" for tracking valuues -----*- C++ -*--=// +//= GRState.cpp - Path-Sensitive "State" for tracking values -----*- C++ -*--=// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines SymbolRef, ExprBindKey, and GRState* +// This file implements GRState and GRStateManager. // //===----------------------------------------------------------------------===// @@ -20,6 +20,7 @@ using namespace clang; // Give the vtable for ConstraintManager somewhere to live. +// FIXME: Move this elsewhere. ConstraintManager::~ConstraintManager() {} GRStateManager::~GRStateManager() { @@ -56,16 +57,63 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, SymReaper); } -const GRState* GRStateManager::Unbind(const GRState* St, Loc LV) { - Store OldStore = St->getStore(); - Store NewStore = StoreMgr->Remove(OldStore, LV); +const GRState *GRState::unbindLoc(Loc LV) const { + Store OldStore = getStore(); + Store NewStore = Mgr->StoreMgr->Remove(OldStore, LV); if (NewStore == OldStore) - return St; + return this; - GRState NewSt = *St; + GRState NewSt = *this; NewSt.St = NewStore; - return getPersistentState(NewSt); + return Mgr->getPersistentState(NewSt); +} + +SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { + // We only want to do fetches from regions that we can actually bind + // values. For example, SymbolicRegions of type 'id<...>' cannot + // have direct bindings (but their can be bindings on their subregions). + if (!R->isBoundable()) + return UnknownVal(); + + if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) { + QualType T = TR->getValueType(Mgr->getContext()); + if (Loc::IsLocType(T) || T->isIntegerType()) + return getSVal(R); + } + + return UnknownVal(); +} + + +const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr, + bool Invalidate) const { + + Environment NewEnv = Mgr->EnvMgr.BindExpr(Env, Ex, V, isBlkExpr, Invalidate); + + if (NewEnv == Env) + return this; + + GRState NewSt = *this; + NewSt.Env = NewEnv; + return Mgr->getPersistentState(NewSt); +} + +const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, + bool Invalidate) const { + + bool isBlkExpr = false; + + if (Ex == Mgr->CurrentStmt) { + // FIXME: Should this just be an assertion? When would we want to set + // the value of a block-level expression if it wasn't CurrentStmt? + isBlkExpr = Mgr->cfg.isBlkExpr(Ex); + + if (!isBlkExpr) + return this; + } + + return bindExpr(Ex, V, isBlkExpr, Invalidate); } const GRState* GRStateManager::getInitialState() { @@ -101,7 +149,8 @@ const GRState* GRState::makeWithStore(Store store) const { // State pretty-printing. //===----------------------------------------------------------------------===// -void GRState::print(std::ostream& Out, const char* nl, const char* sep) const { +void GRState::print(llvm::raw_ostream& Out, const char* nl, + const char* sep) const { // Print the store. Mgr->getStoreManager().print(getStore(), Out, nl, sep); @@ -117,9 +166,7 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const { else { Out << nl; } Out << " (" << (void*) I.getKey() << ") "; - llvm::raw_os_ostream OutS(Out); - I.getKey()->printPretty(OutS); - OutS.flush(); + I.getKey()->printPretty(Out); Out << " : "; I.getData().print(Out); } @@ -136,9 +183,7 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const { else { Out << nl; } Out << " (" << (void*) I.getKey() << ") "; - llvm::raw_os_ostream OutS(Out); - I.getKey()->printPretty(OutS); - OutS.flush(); + I.getKey()->printPretty(Out); Out << " : "; I.getData().print(Out); } @@ -152,12 +197,12 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const { } } -void GRState::printDOT(std::ostream& Out) const { +void GRState::printDOT(llvm::raw_ostream& Out) const { print(Out, "\\l", "\\|"); } void GRState::printStdErr() const { - print(*llvm::cerr); + print(llvm::errs()); } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/GRTransferFuncs.cpp b/lib/Analysis/GRTransferFuncs.cpp deleted file mode 100644 index 3c14ee9ab5c2d..0000000000000 --- a/lib/Analysis/GRTransferFuncs.cpp +++ /dev/null @@ -1,27 +0,0 @@ -//== GRTransferFuncs.cpp - Path-Sens. Transfer Functions Interface -*- C++ -*--= -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRTransferFuncs, which provides a base-class that -// defines an interface for transfer functions used by GRExprEngine. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" - -using namespace clang; - -void GRTransferFuncs::EvalBinOpNN(GRStateSet& OStates, - GRExprEngine& Eng, - const GRState *St, Expr* Ex, - BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, QualType T) { - - OStates.Add(St->bindExpr(Ex, DetermEvalBinOpNN(Eng, Op, L, R, T))); -} diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp index ec96329852d48..a608ce0d5884c 100644 --- a/lib/Analysis/PathDiagnostic.cpp +++ b/lib/Analysis/PathDiagnostic.cpp @@ -18,7 +18,7 @@ #include "clang/AST/StmtCXX.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Casting.h" -#include <sstream> + using namespace clang; using llvm::dyn_cast; using llvm::isa; diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp index 73c68bcaea033..079462e8d19f4 100644 --- a/lib/Analysis/RangeConstraintManager.cpp +++ b/lib/Analysis/RangeConstraintManager.cpp @@ -200,7 +200,7 @@ public: return newRanges; } - void Print(std::ostream &os) const { + void print(llvm::raw_ostream &os) const { bool isFirst = true; os << "{ "; for (iterator i = begin(), e = end(); i != e; ++i) { @@ -265,7 +265,7 @@ public: const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper); - void print(const GRState* St, std::ostream& Out, + void print(const GRState* St, llvm::raw_ostream& Out, const char* nl, const char *sep); private: @@ -341,7 +341,7 @@ AssumeX(GE) // Pretty-printing. //===------------------------------------------------------------------------===/ -void RangeConstraintManager::print(const GRState* St, std::ostream& Out, +void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out, const char* nl, const char *sep) { ConstraintRangeTy Ranges = St->get<ConstraintRange>(); @@ -353,6 +353,6 @@ void RangeConstraintManager::print(const GRState* St, std::ostream& Out, for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){ Out << nl << ' ' << I.getKey() << " : "; - I.getData().Print(Out); + I.getData().print(Out); } } diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 77f5b7cb39bbd..d45048de1a42f 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -103,25 +103,6 @@ namespace clang { } //===----------------------------------------------------------------------===// -// Region "killsets". -//===----------------------------------------------------------------------===// -// -// RegionStore lazily adds value bindings to regions when the analyzer handles -// assignment statements. Killsets track which default values have been -// killed, thus distinguishing between "unknown" values and default -// values. Regions are added to killset only when they are assigned "unknown" -// directly, otherwise we should have their value in the region bindings. -// -namespace { class VISIBILITY_HIDDEN RegionKills {}; } -static int RegionKillsIndex = 0; -namespace clang { - template<> struct GRStateTrait<RegionKills> - : public GRStatePartialTrait< llvm::ImmutableSet<const MemRegion*> > { - static void* GDMIndex() { return &RegionKillsIndex; } - }; -} - -//===----------------------------------------------------------------------===// // Regions with default values. //===----------------------------------------------------------------------===// // @@ -238,10 +219,8 @@ public: CastResult CastRegion(const GRState *state, const MemRegion* R, QualType CastToTy); - SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,NonLoc R); - - - + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L, + NonLoc R, QualType resultTy); Store getInitialStore() { return RBFactory.GetEmptyMap().getRoot(); } @@ -260,8 +239,6 @@ public: return SelfRegion; } - - //===-------------------------------------------------------------------===// // Binding values to regions. @@ -306,7 +283,11 @@ public: /// else /// return symbolic SVal Retrieve(const GRState *state, Loc L, QualType T = QualType()); - + + SVal RetrieveElement(const GRState* state, const ElementRegion* R); + + SVal RetrieveField(const GRState* state, const FieldRegion* R); + /// Retrieve the values in a struct and return a CompoundVal, used when doing /// struct copy: /// struct s x, y; @@ -352,7 +333,8 @@ public: return RegionBindingsTy(static_cast<const RegionBindingsTy::TreeTy*>(store)); } - void print(Store store, std::ostream& Out, const char* nl, const char *sep); + void print(Store store, llvm::raw_ostream& Out, const char* nl, + const char *sep); void iterBindings(Store store, BindingsHandler& f) { // FIXME: Implement. @@ -740,7 +722,8 @@ RegionStoreManager::CastRegion(const GRState *state, const MemRegion* R, //===----------------------------------------------------------------------===// SVal RegionStoreManager::EvalBinOp(const GRState *state, - BinaryOperator::Opcode Op, Loc L, NonLoc R) { + BinaryOperator::Opcode Op, Loc L, NonLoc R, + QualType resultTy) { // Assume the base location is MemRegionVal. if (!isa<loc::MemRegionVal>(L)) return UnknownVal(); @@ -798,7 +781,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // nonloc::ConcreteInt OffConverted(getBasicVals().Convert(Base->getValue(), Offset->getValue())); - SVal NewIdx = Base->EvalBinOp(getBasicVals(), Op, OffConverted); + SVal NewIdx = Base->evalBinOp(ValMgr, Op, OffConverted); const MemRegion* NewER = MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion(), getContext()); @@ -839,6 +822,12 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { const TypedRegion *R = cast<TypedRegion>(MR); assert(R && "bad region"); + if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) + return RetrieveField(state, FR); + + if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) + return RetrieveElement(state, ER); + // FIXME: We should eventually handle funny addressing. e.g.: // // int x = ...; @@ -867,42 +856,6 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { if (V) return *V; - // Check if the region is in killset. - if (state->contains<RegionKills>(R)) - return UnknownVal(); - - // Check if the region is an element region of a string literal. - if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - if (const StringRegion *StrR=dyn_cast<StringRegion>(ER->getSuperRegion())) { - const StringLiteral *Str = StrR->getStringLiteral(); - SVal Idx = ER->getIndex(); - if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) { - int64_t i = CI->getValue().getSExtValue(); - char c; - if (i == Str->getByteLength()) - c = '\0'; - else - c = Str->getStrData()[i]; - const llvm::APSInt &V = getBasicVals().getValue(c, getContext().CharTy); - return nonloc::ConcreteInt(V); - } - } - } - - // If the region is an element or field, it may have a default value. - if (isa<ElementRegion>(R) || isa<FieldRegion>(R)) { - const MemRegion* SuperR = cast<SubRegion>(R)->getSuperRegion(); - GRStateTrait<RegionDefaultValue>::lookup_type D = - state->get<RegionDefaultValue>(SuperR); - if (D) { - // If the default value is symbolic, we need to create a new symbol. - if (D->hasConjuredSymbol()) - return ValMgr.getRegionValueSymbolVal(R); - else - return *D; - } - } - if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) { const MemRegion *SR = IVR->getSuperRegion(); @@ -961,6 +914,97 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { return UnknownVal(); } +SVal RegionStoreManager::RetrieveElement(const GRState* state, + const ElementRegion* R) { + // Check if the region has a binding. + RegionBindingsTy B = GetRegionBindings(state->getStore()); + const SVal* V = B.lookup(R); + if (V) + return *V; + + // Check if the region is an element region of a string literal. + if (const StringRegion *StrR=dyn_cast<StringRegion>(R->getSuperRegion())) { + const StringLiteral *Str = StrR->getStringLiteral(); + SVal Idx = R->getIndex(); + if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) { + int64_t i = CI->getValue().getSExtValue(); + char c; + if (i == Str->getByteLength()) + c = '\0'; + else + c = Str->getStrData()[i]; + return ValMgr.makeIntVal(c, getContext().CharTy); + } + } + + const MemRegion* SuperR = R->getSuperRegion(); + const SVal* D = state->get<RegionDefaultValue>(SuperR); + + if (D) { + if (D->hasConjuredSymbol()) + return ValMgr.getRegionValueSymbolVal(R); + else + return *D; + } + + if (R->hasHeapOrStackStorage()) + return UndefinedVal(); + + QualType Ty = R->getValueType(getContext()); + + // If the region is already cast to another type, use that type to create the + // symbol value. + if (const QualType *p = state->get<RegionCasts>(R)) + Ty = (*p)->getAsPointerType()->getPointeeType(); + + if (Loc::IsLocType(Ty) || Ty->isIntegerType()) + return ValMgr.getRegionValueSymbolVal(R, Ty); + else + return UnknownVal(); +} + +SVal RegionStoreManager::RetrieveField(const GRState* state, + const FieldRegion* R) { + QualType Ty = R->getValueType(getContext()); + + // Check if the region has a binding. + RegionBindingsTy B = GetRegionBindings(state->getStore()); + const SVal* V = B.lookup(R); + if (V) + return *V; + + const MemRegion* SuperR = R->getSuperRegion(); + const SVal* D = state->get<RegionDefaultValue>(SuperR); + if (D) { + if (D->hasConjuredSymbol()) + return ValMgr.getRegionValueSymbolVal(R); + + if (D->isZeroConstant()) + return ValMgr.makeZeroVal(Ty); + + if (D->isUnknown()) + return *D; + + assert(0 && "Unknown default value"); + } + + if (R->hasHeapOrStackStorage()) + return UndefinedVal(); + + // If the region is already cast to another type, use that type to create the + // symbol value. + if (const QualType *p = state->get<RegionCasts>(R)) { + QualType tmp = *p; + Ty = tmp->getAsPointerType()->getPointeeType(); + } + + // All other integer values are symbolic. + if (Loc::IsLocType(Ty) || Ty->isIntegerType()) + return ValMgr.getRegionValueSymbolVal(R, Ty); + else + return UnknownVal(); +} + SVal RegionStoreManager::RetrieveStruct(const GRState *state, const TypedRegion* R){ QualType T = R->getValueType(getContext()); @@ -1040,12 +1084,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { RegionBindingsTy B = GetRegionBindings(state->getStore()); - if (V.isUnknown()) { - B = RBFactory.Remove(B, R); // Remove the binding. - state = state->add<RegionKills>(R); // Add the region to the killset. - } - else - B = RBFactory.Add(B, R, V); + B = RBFactory.Add(B, R, V); return state->makeWithStore(B.getRoot()); } @@ -1127,15 +1166,12 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, state = Bind(state, ValMgr.makeLoc(ER), *VI); } - // If the init list is shorter than the array length, bind the rest elements - // to 0. - if (ElementTy->isIntegerType()) { - while (i < Size) { - SVal Idx = ValMgr.makeIntVal(i); - ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx,R,getContext()); + // If the init list is shorter than the array length, set the array default + // value. + if (i < Size) { + if (ElementTy->isIntegerType()) { SVal V = ValMgr.makeZeroVal(ElementTy); - state = Bind(state, ValMgr.makeLoc(ER), V); - ++i; + state = setDefaultValue(state, R, V); } } @@ -1186,15 +1222,8 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, } // There may be fewer values in the initialize list than the fields of struct. - while (FI != FE) { - QualType FTy = (*FI)->getType(); - if (FTy->isIntegerType()) { - FieldRegion* FR = MRMgr.getFieldRegion(*FI, R); - state = Bind(state, ValMgr.makeLoc(FR), ValMgr.makeZeroVal(FTy)); - } - - ++FI; - } + if (FI != FE) + state = setDefaultValue(state, R, ValMgr.makeIntVal(0, false)); return state; } @@ -1202,20 +1231,17 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, const GRState *RegionStoreManager::KillStruct(const GRState *state, const TypedRegion* R){ - // (1) Kill the struct region because it is assigned "unknown". - // (2) Set the default value of the struct region to "unknown". - state = state->add<RegionKills>(R)->set<RegionDefaultValue>(R, UnknownVal()); - Store store = state->getStore(); - RegionBindingsTy B = GetRegionBindings(store); + // Set the default value of the struct region to "unknown". + state = state->set<RegionDefaultValue>(R, UnknownVal()); // Remove all bindings for the subregions of the struct. + Store store = state->getStore(); + RegionBindingsTy B = GetRegionBindings(store); for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { const MemRegion* R = I.getKey(); if (const SubRegion* subRegion = dyn_cast<SubRegion>(R)) if (subRegion->isSubRegionOf(R)) store = Remove(store, ValMgr.makeLoc(subRegion)); - // FIXME: Maybe we should also remove the bindings for the "views" of the - // subregions. } return state->makeWithStore(store); @@ -1427,9 +1453,8 @@ Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc, // Utility methods. //===----------------------------------------------------------------------===// -void RegionStoreManager::print(Store store, std::ostream& Out, +void RegionStoreManager::print(Store store, llvm::raw_ostream& OS, const char* nl, const char *sep) { - llvm::raw_os_ostream OS(Out); RegionBindingsTy B = GetRegionBindings(store); OS << "Store:" << nl; diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp index dd9490bebb960..7d1850d730957 100644 --- a/lib/Analysis/SVals.cpp +++ b/lib/Analysis/SVals.cpp @@ -188,12 +188,11 @@ bool SVal::isZeroConstant() const { // Transfer function dispatch for Non-Locs. //===----------------------------------------------------------------------===// -SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, - BinaryOperator::Opcode Op, - const nonloc::ConcreteInt& R) const { - +SVal nonloc::ConcreteInt::evalBinOp(ValueManager &ValMgr, + BinaryOperator::Opcode Op, + const nonloc::ConcreteInt& R) const { const llvm::APSInt* X = - BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue()); + ValMgr.getBasicValueFactory().EvaluateAPSInt(Op, getValue(), R.getValue()); if (X) return nonloc::ConcreteInt(*X); @@ -201,20 +200,13 @@ SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, return UndefinedVal(); } - // Bitwise-Complement. - nonloc::ConcreteInt -nonloc::ConcreteInt::EvalComplement(BasicValueFactory& BasicVals) const { - return BasicVals.getValue(~getValue()); +nonloc::ConcreteInt::evalComplement(ValueManager &ValMgr) const { + return ValMgr.makeIntVal(~getValue()); } - // Unary Minus. - -nonloc::ConcreteInt -nonloc::ConcreteInt::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const { - assert (U->getType() == U->getSubExpr()->getType()); - assert (U->getType()->isIntegerType()); - return BasicVals.getValue(-getValue()); +nonloc::ConcreteInt nonloc::ConcreteInt::evalMinus(ValueManager &ValMgr) const { + return ValMgr.makeIntVal(-getValue()); } //===----------------------------------------------------------------------===// @@ -242,11 +234,6 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, void SVal::printStdErr() const { print(llvm::errs()); } -void SVal::print(std::ostream& Out) const { - llvm::raw_os_ostream out(Out); - print(out); -} - void SVal::print(llvm::raw_ostream& Out) const { switch (getBaseKind()) { diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp new file mode 100644 index 0000000000000..76a8bc782eb57 --- /dev/null +++ b/lib/Analysis/SimpleSValuator.cpp @@ -0,0 +1,346 @@ +// SimpleSValuator.cpp - A basic SValuator ------------------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SimpleSValuator, a basic implementation of SValuator. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/SValuator.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN SimpleSValuator : public SValuator { +public: + SimpleSValuator(ValueManager &valMgr) : SValuator(valMgr) {} + virtual ~SimpleSValuator() {} + + virtual SVal EvalCast(NonLoc val, QualType castTy); + virtual SVal EvalCast(Loc val, QualType castTy); + virtual SVal EvalMinus(NonLoc val); + virtual SVal EvalComplement(NonLoc val); + virtual SVal EvalBinOpNN(BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, + QualType resultTy); + virtual SVal EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs, + QualType resultTy); + virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op, + Loc lhs, NonLoc rhs, QualType resultTy); +}; +} // end anonymous namespace + +SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) { + return new SimpleSValuator(valMgr); +} + +//===----------------------------------------------------------------------===// +// Transfer function for Casts. +//===----------------------------------------------------------------------===// + +SVal SimpleSValuator::EvalCast(NonLoc val, QualType castTy) { + if (!isa<nonloc::ConcreteInt>(val)) + return UnknownVal(); + + bool isLocType = Loc::IsLocType(castTy); + + // Only handle casts from integers to integers. + if (!isLocType && !castTy->isIntegerType()) + return UnknownVal(); + + llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue(); + i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); + i.extOrTrunc(ValMgr.getContext().getTypeSize(castTy)); + + if (isLocType) + return ValMgr.makeIntLocVal(i); + else + return ValMgr.makeIntVal(i); +} + +SVal SimpleSValuator::EvalCast(Loc val, QualType castTy) { + + // Casts from pointers -> pointers, just return the lval. + // + // Casts from pointers -> references, just return the lval. These + // can be introduced by the frontend for corner cases, e.g + // casting from va_list* to __builtin_va_list&. + // + assert(!val.isUnknownOrUndef()); + + if (Loc::IsLocType(castTy) || castTy->isReferenceType()) + return val; + + // FIXME: Handle transparent unions where a value can be "transparently" + // lifted into a union type. + if (castTy->isUnionType()) + return UnknownVal(); + + assert(castTy->isIntegerType()); + unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy); + + if (!isa<loc::ConcreteInt>(val)) + return ValMgr.makeLocAsInteger(val, BitWidth); + + llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue(); + i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); + i.extOrTrunc(BitWidth); + return ValMgr.makeIntVal(i); +} + +//===----------------------------------------------------------------------===// +// Transfer function for unary operators. +//===----------------------------------------------------------------------===// + +SVal SimpleSValuator::EvalMinus(NonLoc val) { + switch (val.getSubKind()) { + case nonloc::ConcreteIntKind: + return cast<nonloc::ConcreteInt>(val).evalMinus(ValMgr); + default: + return UnknownVal(); + } +} + +SVal SimpleSValuator::EvalComplement(NonLoc X) { + switch (X.getSubKind()) { + case nonloc::ConcreteIntKind: + return cast<nonloc::ConcreteInt>(X).evalComplement(ValMgr); + default: + return UnknownVal(); + } +} + +//===----------------------------------------------------------------------===// +// Transfer function for binary operators. +//===----------------------------------------------------------------------===// + +static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { + switch (op) { + default: + assert(false && "Invalid opcode."); + case BinaryOperator::LT: return BinaryOperator::GE; + case BinaryOperator::GT: return BinaryOperator::LE; + case BinaryOperator::LE: return BinaryOperator::GT; + case BinaryOperator::GE: return BinaryOperator::LT; + case BinaryOperator::EQ: return BinaryOperator::NE; + case BinaryOperator::NE: return BinaryOperator::EQ; + } +} + +// Equality operators for Locs. +// FIXME: All this logic will be revamped when we have MemRegion::getLocation() +// implemented. + +static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual, + QualType resultTy) { + + switch (lhs.getSubKind()) { + default: + assert(false && "EQ/NE not implemented for this Loc."); + return UnknownVal(); + + case loc::ConcreteIntKind: { + if (SymbolRef rSym = rhs.getAsSymbol()) + return ValMgr.makeNonLoc(rSym, + isEqual ? BinaryOperator::EQ + : BinaryOperator::NE, + cast<loc::ConcreteInt>(lhs).getValue(), + resultTy); + break; + } + case loc::MemRegionKind: { + if (SymbolRef lSym = lhs.getAsLocSymbol()) { + if (isa<loc::ConcreteInt>(rhs)) { + return ValMgr.makeNonLoc(lSym, + isEqual ? BinaryOperator::EQ + : BinaryOperator::NE, + cast<loc::ConcreteInt>(rhs).getValue(), + resultTy); + } + } + break; + } + + case loc::GotoLabelKind: + break; + } + + return ValMgr.makeTruthVal(isEqual ? lhs == rhs : lhs != rhs, resultTy); +} + +SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, + NonLoc lhs, NonLoc rhs, + QualType resultTy) { + while (1) { + switch (lhs.getSubKind()) { + default: + return UnknownVal(); + case nonloc::LocAsIntegerKind: { + Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc(); + switch (rhs.getSubKind()) { + case nonloc::LocAsIntegerKind: + return EvalBinOpLL(op, lhsL, cast<nonloc::LocAsInteger>(rhs).getLoc(), + resultTy); + case nonloc::ConcreteIntKind: { + // Transform the integer into a location and compare. + ASTContext& Ctx = ValMgr.getContext(); + llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue(); + i.setIsUnsigned(true); + i.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy)); + return EvalBinOpLL(op, lhsL, ValMgr.makeLoc(i), resultTy); + } + default: + switch (op) { + case BinaryOperator::EQ: + return ValMgr.makeTruthVal(false, resultTy); + case BinaryOperator::NE: + return ValMgr.makeTruthVal(true, resultTy); + default: + // This case also handles pointer arithmetic. + return UnknownVal(); + } + } + } + case nonloc::SymExprValKind: { + // Logical not? + if (!(op == BinaryOperator::EQ && rhs.isZeroConstant())) + return UnknownVal(); + + const SymExpr *symExpr = + cast<nonloc::SymExprVal>(lhs).getSymbolicExpression(); + + // Only handle ($sym op constant) for now. + if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(symExpr)) { + BinaryOperator::Opcode opc = symIntExpr->getOpcode(); + switch (opc) { + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + assert(false && "Logical operators handled by branching logic."); + return UnknownVal(); + case BinaryOperator::Assign: + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + case BinaryOperator::RemAssign: + case BinaryOperator::AddAssign: + case BinaryOperator::SubAssign: + case BinaryOperator::ShlAssign: + case BinaryOperator::ShrAssign: + case BinaryOperator::AndAssign: + case BinaryOperator::XorAssign: + case BinaryOperator::OrAssign: + case BinaryOperator::Comma: + assert(false && "'=' and ',' operators handled by GRExprEngine."); + return UnknownVal(); + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + assert(false && "Pointer arithmetic not handled here."); + return UnknownVal(); + case BinaryOperator::Mul: + case BinaryOperator::Div: + case BinaryOperator::Rem: + case BinaryOperator::Add: + case BinaryOperator::Sub: + case BinaryOperator::Shl: + case BinaryOperator::Shr: + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + // Not handled yet. + return UnknownVal(); + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + opc = NegateComparison(opc); + assert(symIntExpr->getType(ValMgr.getContext()) == resultTy); + return ValMgr.makeNonLoc(symIntExpr->getLHS(), opc, + symIntExpr->getRHS(), resultTy); + } + } + } + case nonloc::ConcreteIntKind: { + if (isa<nonloc::ConcreteInt>(rhs)) { + const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs); + return lhsInt.evalBinOp(ValMgr, op, cast<nonloc::ConcreteInt>(rhs)); + } + else { + // Swap the left and right sides and flip the operator if doing so + // allows us to better reason about the expression (this is a form + // of expression canonicalization). + NonLoc tmp = rhs; + rhs = lhs; + lhs = tmp; + + switch (op) { + case BinaryOperator::LT: op = BinaryOperator::GT; continue; + case BinaryOperator::GT: op = BinaryOperator::LT; continue; + case BinaryOperator::LE: op = BinaryOperator::GE; continue; + case BinaryOperator::GE: op = BinaryOperator::LE; continue; + case BinaryOperator::EQ: + case BinaryOperator::NE: + case BinaryOperator::Add: + case BinaryOperator::Mul: + continue; + default: + return UnknownVal(); + } + } + } + case nonloc::SymbolValKind: { + if (isa<nonloc::ConcreteInt>(rhs)) { + return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(lhs).getSymbol(), op, + cast<nonloc::ConcreteInt>(rhs).getValue(), + resultTy); + } + + return UnknownVal(); + } + } + } +} + +SVal SimpleSValuator::EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs, + QualType resultTy) { + switch (op) { + default: + return UnknownVal(); + case BinaryOperator::EQ: + case BinaryOperator::NE: + return EvalEquality(ValMgr, lhs, rhs, op == BinaryOperator::EQ, resultTy); + } +} + +SVal SimpleSValuator::EvalBinOpLN(const GRState *state, + BinaryOperator::Opcode op, + Loc lhs, NonLoc rhs, QualType resultTy) { + // Special case: 'rhs' is an integer that has the same width as a pointer and + // we are using the integer location in a comparison. Normally this cannot be + // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32 + // can generate comparisons that trigger this code. + // FIXME: Are all locations guaranteed to have pointer width? + if (BinaryOperator::isEqualityOp(op)) { + if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) { + const llvm::APSInt *x = &rhsInt->getValue(); + ASTContext &ctx = ValMgr.getContext(); + if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) { + // Convert the signedness of the integer (if necessary). + if (x->isSigned()) + x = &ValMgr.getBasicValueFactory().getValue(*x, true); + + return EvalBinOpLL(op, lhs, loc::ConcreteInt(*x), resultTy); + } + } + } + + // Delegate pointer arithmetic to the StoreManager. + return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs, + rhs, resultTy); +} diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp index 4e38a3492c79a..275f30a2963e0 100644 --- a/lib/Analysis/SymbolManager.cpp +++ b/lib/Analysis/SymbolManager.cpp @@ -85,12 +85,6 @@ llvm::raw_ostream& llvm::operator<<(llvm::raw_ostream& os, const SymExpr *SE) { return os; } -std::ostream& std::operator<<(std::ostream& os, const SymExpr *SE) { - llvm::raw_os_ostream O(os); - print(O, SE); - return os; -} - const SymbolRegionValue* SymbolManager::getRegionValueSymbol(const MemRegion* R, QualType T) { llvm::FoldingSetNodeID profile; |