From 1696f508e2fe95793ca8bb70d78b88023b6b8625 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Wed, 22 Dec 2010 18:53:44 +0000 Subject: [analyzer] Refactoring: Drop the 'GR' prefix. llvm-svn: 122424 --- clang/lib/GR/AggExprVisitor.cpp | 12 +- clang/lib/GR/AnalysisConsumer.cpp | 20 +- clang/lib/GR/AnalyzerStatsChecker.cpp | 12 +- clang/lib/GR/BasicConstraintManager.cpp | 6 +- clang/lib/GR/BasicStore.cpp | 2 +- clang/lib/GR/BasicValueFactory.cpp | 2 +- clang/lib/GR/BlockCounter.cpp | 86 + clang/lib/GR/BugReporter.cpp | 2 +- clang/lib/GR/CFRefCount.cpp | 90 +- clang/lib/GR/CMakeLists.txt | 8 +- clang/lib/GR/CXXExprEngine.cpp | 328 ++ .../lib/GR/Checkers/AdjustedReturnValueChecker.cpp | 6 +- clang/lib/GR/Checkers/ArrayBoundChecker.cpp | 6 +- clang/lib/GR/Checkers/AttrNonNullChecker.cpp | 6 +- .../lib/GR/Checkers/BasicObjCFoundationChecks.cpp | 4 +- clang/lib/GR/Checkers/BasicObjCFoundationChecks.h | 6 +- clang/lib/GR/Checkers/BuiltinFunctionChecker.cpp | 4 +- clang/lib/GR/Checkers/CMakeLists.txt | 2 +- clang/lib/GR/Checkers/CStringChecker.cpp | 4 +- clang/lib/GR/Checkers/CallAndMessageChecker.cpp | 4 +- clang/lib/GR/Checkers/CastSizeChecker.cpp | 4 +- clang/lib/GR/Checkers/CastToStructChecker.cpp | 4 +- clang/lib/GR/Checkers/CheckDeadStores.cpp | 2 +- clang/lib/GR/Checkers/ChrootChecker.cpp | 4 +- clang/lib/GR/Checkers/DereferenceChecker.cpp | 10 +- clang/lib/GR/Checkers/DivZeroChecker.cpp | 6 +- .../GR/Checkers/ExprEngineExperimentalChecks.cpp | 46 + .../lib/GR/Checkers/ExprEngineExperimentalChecks.h | 37 + clang/lib/GR/Checkers/ExprEngineInternalChecks.h | 58 + clang/lib/GR/Checkers/FixedAddressChecker.cpp | 4 +- .../GR/Checkers/GRExprEngineExperimentalChecks.cpp | 46 - .../GR/Checkers/GRExprEngineExperimentalChecks.h | 37 - clang/lib/GR/Checkers/GRExprEngineInternalChecks.h | 58 - .../lib/GR/Checkers/IdempotentOperationChecker.cpp | 20 +- clang/lib/GR/Checkers/MacOSXAPIChecker.cpp | 4 +- clang/lib/GR/Checkers/MallocChecker.cpp | 10 +- clang/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp | 4 +- clang/lib/GR/Checkers/NSErrorChecker.cpp | 8 +- clang/lib/GR/Checkers/NoReturnFunctionChecker.cpp | 4 +- clang/lib/GR/Checkers/OSAtomicChecker.cpp | 6 +- clang/lib/GR/Checkers/ObjCAtSyncChecker.cpp | 6 +- clang/lib/GR/Checkers/PointerArithChecker.cpp | 4 +- clang/lib/GR/Checkers/PointerSubChecker.cpp | 4 +- clang/lib/GR/Checkers/PthreadLockChecker.cpp | 6 +- .../lib/GR/Checkers/ReturnPointerRangeChecker.cpp | 6 +- clang/lib/GR/Checkers/ReturnUndefChecker.cpp | 6 +- clang/lib/GR/Checkers/StackAddrLeakChecker.cpp | 10 +- clang/lib/GR/Checkers/StreamChecker.cpp | 10 +- clang/lib/GR/Checkers/UndefBranchChecker.cpp | 10 +- .../GR/Checkers/UndefCapturedBlockVarChecker.cpp | 6 +- clang/lib/GR/Checkers/UndefResultChecker.cpp | 8 +- .../GR/Checkers/UndefinedArraySubscriptChecker.cpp | 6 +- .../lib/GR/Checkers/UndefinedAssignmentChecker.cpp | 6 +- clang/lib/GR/Checkers/UnixAPIChecker.cpp | 6 +- clang/lib/GR/Checkers/UnreachableCodeChecker.cpp | 8 +- clang/lib/GR/Checkers/VLASizeChecker.cpp | 8 +- clang/lib/GR/CoreEngine.cpp | 809 +++++ clang/lib/GR/ExprEngine.cpp | 3513 ++++++++++++++++++++ clang/lib/GR/GRBlockCounter.cpp | 86 - clang/lib/GR/GRCXXExprEngine.cpp | 328 -- clang/lib/GR/GRCoreEngine.cpp | 809 ----- clang/lib/GR/GRExprEngine.cpp | 3513 -------------------- clang/lib/GR/GRState.cpp | 6 +- clang/lib/GR/RangeConstraintManager.cpp | 6 +- clang/lib/GR/RegionStore.cpp | 4 +- clang/lib/GR/SimpleConstraintManager.cpp | 2 +- clang/lib/GR/SimpleConstraintManager.h | 4 +- clang/lib/GR/SimpleSValBuilder.cpp | 2 +- clang/lib/GR/SymbolManager.cpp | 2 +- 69 files changed, 5088 insertions(+), 5088 deletions(-) create mode 100644 clang/lib/GR/BlockCounter.cpp create mode 100644 clang/lib/GR/CXXExprEngine.cpp create mode 100644 clang/lib/GR/Checkers/ExprEngineExperimentalChecks.cpp create mode 100644 clang/lib/GR/Checkers/ExprEngineExperimentalChecks.h create mode 100644 clang/lib/GR/Checkers/ExprEngineInternalChecks.h delete mode 100644 clang/lib/GR/Checkers/GRExprEngineExperimentalChecks.cpp delete mode 100644 clang/lib/GR/Checkers/GRExprEngineExperimentalChecks.h delete mode 100644 clang/lib/GR/Checkers/GRExprEngineInternalChecks.h create mode 100644 clang/lib/GR/CoreEngine.cpp create mode 100644 clang/lib/GR/ExprEngine.cpp delete mode 100644 clang/lib/GR/GRBlockCounter.cpp delete mode 100644 clang/lib/GR/GRCXXExprEngine.cpp delete mode 100644 clang/lib/GR/GRCoreEngine.cpp delete mode 100644 clang/lib/GR/GRExprEngine.cpp (limited to 'clang/lib') diff --git a/clang/lib/GR/AggExprVisitor.cpp b/clang/lib/GR/AggExprVisitor.cpp index 7f873bc14d5..45022986de7 100644 --- a/clang/lib/GR/AggExprVisitor.cpp +++ b/clang/lib/GR/AggExprVisitor.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/AST/StmtVisitor.h" using namespace clang; @@ -23,18 +23,18 @@ namespace { /// is used for evaluating exprs of C++ object type. Evaluating such exprs /// requires a destination pointer pointing to the object being evaluated /// into. Passing such a pointer around would pollute the Visit* interface of -/// GRExprEngine. AggExprVisitor encapsulates code that goes through various +/// ExprEngine. AggExprVisitor encapsulates code that goes through various /// cast and construct exprs (and others), and at the final point, dispatches -/// back to the GRExprEngine to let the real evaluation logic happen. +/// back to the ExprEngine to let the real evaluation logic happen. class AggExprVisitor : public StmtVisitor { const MemRegion *Dest; ExplodedNode *Pred; ExplodedNodeSet &DstSet; - GRExprEngine &Eng; + ExprEngine &Eng; public: AggExprVisitor(const MemRegion *dest, ExplodedNode *N, ExplodedNodeSet &dst, - GRExprEngine &eng) + ExprEngine &eng) : Dest(dest), Pred(N), DstSet(dst), Eng(eng) {} void VisitCastExpr(CastExpr *E); @@ -57,7 +57,7 @@ void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) { Eng.VisitCXXConstructExpr(E, Dest, Pred, DstSet); } -void GRExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest, +void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst) { AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast(E)); } diff --git a/clang/lib/GR/AnalysisConsumer.cpp b/clang/lib/GR/AnalysisConsumer.cpp index 0b2845119ab..f8a433943a1 100644 --- a/clang/lib/GR/AnalysisConsumer.cpp +++ b/clang/lib/GR/AnalysisConsumer.cpp @@ -25,13 +25,13 @@ #include "clang/GR/BugReporter/PathDiagnostic.h" #include "clang/GR/PathSensitive/AnalysisManager.h" #include "clang/GR/BugReporter/BugReporter.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" -#include "clang/GR/PathSensitive/GRTransferFuncs.h" +#include "clang/GR/PathSensitive/ExprEngine.h" +#include "clang/GR/PathSensitive/TransferFuncs.h" #include "clang/GR/PathDiagnosticClients.h" // FIXME: Restructure checker registration. -#include "Checkers/GRExprEngineExperimentalChecks.h" -#include "Checkers/GRExprEngineInternalChecks.h" +#include "Checkers/ExprEngineExperimentalChecks.h" +#include "Checkers/ExprEngineInternalChecks.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" @@ -328,18 +328,18 @@ static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, } -static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, +static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D, - GRTransferFuncs* tf) { + TransferFuncs* tf) { - llvm::OwningPtr TF(tf); + llvm::OwningPtr TF(tf); // Construct the analysis engine. We first query for the LiveVariables // information to see if the CFG is valid. // FIXME: Inter-procedural analysis will need to handle invalid CFGs. if (!mgr.getLiveVariables(D)) return; - GRExprEngine Eng(mgr, TF.take()); + ExprEngine Eng(mgr, TF.take()); if (C.Opts.EnableExperimentalInternalChecks) RegisterExperimentalInternalChecks(Eng); @@ -384,11 +384,11 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D, bool GCEnabled) { - GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), + TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), GCEnabled, mgr.getLangOptions()); - ActionGRExprEngine(C, mgr, D, TF); + ActionExprEngine(C, mgr, D, TF); } static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, diff --git a/clang/lib/GR/AnalyzerStatsChecker.cpp b/clang/lib/GR/AnalyzerStatsChecker.cpp index cc9fcb7a472..c60b4504b2a 100644 --- a/clang/lib/GR/AnalyzerStatsChecker.cpp +++ b/clang/lib/GR/AnalyzerStatsChecker.cpp @@ -14,7 +14,7 @@ #include "clang/GR/BugReporter/BugReporter.h" // FIXME: Restructure checker registration. -#include "Checkers/GRExprEngineExperimentalChecks.h" +#include "Checkers/ExprEngineExperimentalChecks.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" @@ -26,7 +26,7 @@ namespace { class AnalyzerStatsChecker : public CheckerVisitor { public: static void *getTag(); - void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, GRExprEngine &Eng); + void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng); private: llvm::SmallPtrSet reachable; @@ -38,13 +38,13 @@ void *AnalyzerStatsChecker::getTag() { return &x; } -void GR::RegisterAnalyzerStatsChecker(GRExprEngine &Eng) { +void GR::RegisterAnalyzerStatsChecker(ExprEngine &Eng) { Eng.registerCheck(new AnalyzerStatsChecker()); } void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, - GRExprEngine &Eng) { + ExprEngine &Eng) { const CFG *C = 0; const Decl *D = 0; const LocationContext *LC = 0; @@ -109,8 +109,8 @@ void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G, D->getLocation()); // Emit warning for each block we bailed out on - typedef GRCoreEngine::BlocksAborted::const_iterator AbortedIterator; - const GRCoreEngine &CE = Eng.getCoreEngine(); + typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator; + const CoreEngine &CE = Eng.getCoreEngine(); for (AbortedIterator I = CE.blocks_aborted_begin(), E = CE.blocks_aborted_end(); I != E; ++I) { const BlockEdge &BE = I->first; diff --git a/clang/lib/GR/BasicConstraintManager.cpp b/clang/lib/GR/BasicConstraintManager.cpp index ac289b89c2e..2de0d9a23cc 100644 --- a/clang/lib/GR/BasicConstraintManager.cpp +++ b/clang/lib/GR/BasicConstraintManager.cpp @@ -15,7 +15,7 @@ #include "SimpleConstraintManager.h" #include "clang/GR/PathSensitive/GRState.h" #include "clang/GR/PathSensitive/GRStateTrait.h" -#include "clang/GR/PathSensitive/GRTransferFuncs.h" +#include "clang/GR/PathSensitive/TransferFuncs.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -52,7 +52,7 @@ class BasicConstraintManager : public SimpleConstraintManager { GRState::IntSetTy::Factory ISetFactory; public: - BasicConstraintManager(GRStateManager &statemgr, GRSubEngine &subengine) + BasicConstraintManager(GRStateManager &statemgr, SubEngine &subengine) : SimpleConstraintManager(subengine), ISetFactory(statemgr.getAllocator()) {} @@ -99,7 +99,7 @@ public: } // end anonymous namespace ConstraintManager* GR::CreateBasicConstraintManager(GRStateManager& statemgr, - GRSubEngine &subengine) { + SubEngine &subengine) { return new BasicConstraintManager(statemgr, subengine); } diff --git a/clang/lib/GR/BasicStore.cpp b/clang/lib/GR/BasicStore.cpp index 2a673e24966..1c8ab11a96b 100644 --- a/clang/lib/GR/BasicStore.cpp +++ b/clang/lib/GR/BasicStore.cpp @@ -68,7 +68,7 @@ public: return store; } - /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit + /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit /// conversions between arrays and pointers. SVal ArrayToPointer(Loc Array) { return Array; } diff --git a/clang/lib/GR/BasicValueFactory.cpp b/clang/lib/GR/BasicValueFactory.cpp index 6e94a2a91e1..7e45a15a9c0 100644 --- a/clang/lib/GR/BasicValueFactory.cpp +++ b/clang/lib/GR/BasicValueFactory.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines BasicValueFactory, a class that manages the lifetime -// of APSInt objects and symbolic constraints used by GRExprEngine +// of APSInt objects and symbolic constraints used by ExprEngine // and related classes. // //===----------------------------------------------------------------------===// diff --git a/clang/lib/GR/BlockCounter.cpp b/clang/lib/GR/BlockCounter.cpp new file mode 100644 index 00000000000..ee76e7a2bc1 --- /dev/null +++ b/clang/lib/GR/BlockCounter.cpp @@ -0,0 +1,86 @@ +//==- BlockCounter.h - ADT for counting block visits -------------*- 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 BlockCounter, an abstract data type used to count +// the number of times a given block has been visited along a path +// analyzed by CoreEngine. +// +//===----------------------------------------------------------------------===// + +#include "clang/GR/PathSensitive/BlockCounter.h" +#include "llvm/ADT/ImmutableMap.h" + +using namespace clang; +using namespace GR; + +namespace { + +class CountKey { + const StackFrameContext *CallSite; + unsigned BlockID; + +public: + CountKey(const StackFrameContext *CS, unsigned ID) + : CallSite(CS), BlockID(ID) {} + + bool operator==(const CountKey &RHS) const { + return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID); + } + + bool operator<(const CountKey &RHS) const { + return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID) + : (CallSite < RHS.CallSite); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(CallSite); + ID.AddInteger(BlockID); + } +}; + +} + +typedef llvm::ImmutableMap CountMap; + +static inline CountMap GetMap(void* D) { + return CountMap(static_cast(D)); +} + +static inline CountMap::Factory& GetFactory(void* F) { + return *static_cast(F); +} + +unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite, + unsigned BlockID) const { + CountMap M = GetMap(Data); + CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID)); + return T ? *T : 0; +} + +BlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) { + F = new CountMap::Factory(Alloc); +} + +BlockCounter::Factory::~Factory() { + delete static_cast(F); +} + +BlockCounter +BlockCounter::Factory::IncrementCount(BlockCounter BC, + const StackFrameContext *CallSite, + unsigned BlockID) { + return BlockCounter(GetFactory(F).add(GetMap(BC.Data), + CountKey(CallSite, BlockID), + BC.getNumVisited(CallSite, BlockID)+1).getRoot()); +} + +BlockCounter +BlockCounter::Factory::GetEmptyCounter() { + return BlockCounter(GetFactory(F).getEmptyMap().getRoot()); +} diff --git a/clang/lib/GR/BugReporter.cpp b/clang/lib/GR/BugReporter.cpp index 432182313b1..dedbd702bc8 100644 --- a/clang/lib/GR/BugReporter.cpp +++ b/clang/lib/GR/BugReporter.cpp @@ -14,7 +14,7 @@ #include "clang/GR/BugReporter/BugReporter.h" #include "clang/GR/BugReporter/BugType.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/AST/ASTContext.h" #include "clang/Analysis/CFG.h" #include "clang/AST/Expr.h" diff --git a/clang/lib/GR/CFRefCount.cpp b/clang/lib/GR/CFRefCount.cpp index 55d11a57b43..a99019cf373 100644 --- a/clang/lib/GR/CFRefCount.cpp +++ b/clang/lib/GR/CFRefCount.cpp @@ -21,9 +21,9 @@ #include "clang/GR/Checkers/LocalCheckers.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngineBuilders.h" +#include "clang/GR/PathSensitive/ExprEngineBuilders.h" #include "clang/GR/PathSensitive/GRStateTrait.h" -#include "clang/GR/PathSensitive/GRTransferFuncs.h" +#include "clang/GR/PathSensitive/TransferFuncs.h" #include "clang/GR/PathSensitive/SymbolManager.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -92,16 +92,16 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { namespace { class GenericNodeBuilder { - GRStmtNodeBuilder *SNB; + StmtNodeBuilder *SNB; const Stmt *S; const void *tag; - GREndPathNodeBuilder *ENB; + EndPathNodeBuilder *ENB; public: - GenericNodeBuilder(GRStmtNodeBuilder &snb, const Stmt *s, + GenericNodeBuilder(StmtNodeBuilder &snb, const Stmt *s, const void *t) : SNB(&snb), S(s), tag(t), ENB(0) {} - GenericNodeBuilder(GREndPathNodeBuilder &enb) + GenericNodeBuilder(EndPathNodeBuilder &enb) : SNB(0), S(0), tag(0), ENB(&enb) {} ExplodedNode *MakeNode(const GRState *state, ExplodedNode *Pred) { @@ -1620,7 +1620,7 @@ static const GRState * SendAutorelease(const GRState *state, namespace { -class CFRefCount : public GRTransferFuncs { +class CFRefCount : public TransferFuncs { public: class BindingsPrinter : public GRState::Printer { public: @@ -1648,7 +1648,7 @@ private: RefVal::Kind& hasErr); void ProcessNonLeakError(ExplodedNodeSet& Dst, - GRStmtNodeBuilder& Builder, + StmtNodeBuilder& Builder, const Expr* NodeExpr, SourceRange ErrorRange, ExplodedNode* Pred, const GRState* St, @@ -1660,7 +1660,7 @@ private: ExplodedNode* ProcessLeaks(const GRState * state, llvm::SmallVectorImpl &Leaked, GenericNodeBuilder &Builder, - GRExprEngine &Eng, + ExprEngine &Eng, ExplodedNode *Pred = 0); public: @@ -1673,7 +1673,7 @@ public: virtual ~CFRefCount() {} - void RegisterChecks(GRExprEngine &Eng); + void RegisterChecks(ExprEngine &Eng); virtual void RegisterPrinters(std::vector& Printers) { Printers.push_back(new BindingsPrinter()); @@ -1690,8 +1690,8 @@ public: // Calls. void evalSummary(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + ExprEngine& Eng, + StmtNodeBuilder& Builder, const Expr* Ex, InstanceReceiver Receiver, const RetainSummary& Summ, @@ -1700,42 +1700,42 @@ public: ExplodedNode* Pred, const GRState *state); virtual void evalCall(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + ExprEngine& Eng, + StmtNodeBuilder& Builder, const CallExpr* CE, SVal L, ExplodedNode* Pred); virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + ExprEngine& Engine, + StmtNodeBuilder& Builder, const ObjCMessageExpr* ME, ExplodedNode* Pred, const GRState *state); // Stores. - virtual void evalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val); + virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val); // End-of-path. - virtual void evalEndPath(GRExprEngine& Engine, - GREndPathNodeBuilder& Builder); + virtual void evalEndPath(ExprEngine& Engine, + EndPathNodeBuilder& Builder); virtual void evalDeadSymbols(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + ExprEngine& Engine, + StmtNodeBuilder& Builder, ExplodedNode* Pred, const GRState* state, SymbolReaper& SymReaper); std::pair HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, - ExplodedNode* Pred, GRExprEngine &Eng, + ExplodedNode* Pred, ExprEngine &Eng, SymbolRef Sym, RefVal V, bool &stop); // Return statements. virtual void evalReturn(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + ExprEngine& Engine, + StmtNodeBuilder& Builder, const ReturnStmt* S, ExplodedNode* Pred); @@ -1949,7 +1949,7 @@ namespace { public: CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, ExplodedNode *n, SymbolRef sym, - GRExprEngine& Eng); + ExprEngine& Eng); PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, const ExplodedNode* N); @@ -2407,7 +2407,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, ExplodedNode *n, - SymbolRef sym, GRExprEngine& Eng) + SymbolRef sym, ExprEngine& Eng) : CFRefReport(D, tf, n, sym) { // Most bug reports are cached at the location where they occured. @@ -2474,8 +2474,8 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { } void CFRefCount::evalSummary(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + ExprEngine& Eng, + StmtNodeBuilder& Builder, const Expr* Ex, InstanceReceiver Receiver, const RetainSummary& Summ, @@ -2736,8 +2736,8 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, void CFRefCount::evalCall(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + ExprEngine& Eng, + StmtNodeBuilder& Builder, const CallExpr* CE, SVal L, ExplodedNode* Pred) { @@ -2761,8 +2761,8 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst, } void CFRefCount::evalObjCMessageExpr(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + ExprEngine& Eng, + StmtNodeBuilder& Builder, const ObjCMessageExpr* ME, ExplodedNode* Pred, const GRState *state) { @@ -2792,7 +2792,7 @@ public: } // end anonymous namespace -void CFRefCount::evalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { +void CFRefCount::evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) { // Are we storing to something that causes the value to "escape"? bool escapes = false; @@ -2832,8 +2832,8 @@ void CFRefCount::evalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { // Return statements. void CFRefCount::evalReturn(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + ExprEngine& Eng, + StmtNodeBuilder& Builder, const ReturnStmt* S, ExplodedNode* Pred) { @@ -3141,7 +3141,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, std::pair CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, ExplodedNode* Pred, - GRExprEngine &Eng, + ExprEngine &Eng, SymbolRef Sym, RefVal V, bool &stop) { unsigned ACnt = V.getAutoreleaseCount(); @@ -3225,7 +3225,7 @@ ExplodedNode* CFRefCount::ProcessLeaks(const GRState * state, llvm::SmallVectorImpl &Leaked, GenericNodeBuilder &Builder, - GRExprEngine& Eng, + ExprEngine& Eng, ExplodedNode *Pred) { if (Leaked.empty()) @@ -3249,8 +3249,8 @@ CFRefCount::ProcessLeaks(const GRState * state, return N; } -void CFRefCount::evalEndPath(GRExprEngine& Eng, - GREndPathNodeBuilder& Builder) { +void CFRefCount::evalEndPath(ExprEngine& Eng, + EndPathNodeBuilder& Builder) { const GRState *state = Builder.getState(); GenericNodeBuilder Bd(Builder); @@ -3277,8 +3277,8 @@ void CFRefCount::evalEndPath(GRExprEngine& Eng, } void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + ExprEngine& Eng, + StmtNodeBuilder& Builder, ExplodedNode* Pred, const GRState* state, SymbolReaper& SymReaper) { @@ -3331,7 +3331,7 @@ void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst, } void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, - GRStmtNodeBuilder& Builder, + StmtNodeBuilder& Builder, const Expr* NodeExpr, SourceRange ErrorRange, ExplodedNode* Pred, @@ -3430,7 +3430,7 @@ void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, // Transfer function creation for external clients. //===----------------------------------------------------------------------===// -void CFRefCount::RegisterChecks(GRExprEngine& Eng) { +void CFRefCount::RegisterChecks(ExprEngine& Eng) { BugReporter &BR = Eng.getBugReporter(); useAfterRelease = new UseAfterRelease(this); @@ -3488,13 +3488,13 @@ void CFRefCount::RegisterChecks(GRExprEngine& Eng) { // Save the reference to the BugReporter. this->BR = &BR; - // Register the RetainReleaseChecker with the GRExprEngine object. + // Register the RetainReleaseChecker with the ExprEngine object. // Functionality in CFRefCount will be migrated to RetainReleaseChecker // over time. Eng.registerCheck(new RetainReleaseChecker(this)); } -GRTransferFuncs* GR::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, +TransferFuncs* GR::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, const LangOptions& lopts) { return new CFRefCount(Ctx, GCEnabled, lopts); } diff --git a/clang/lib/GR/CMakeLists.txt b/clang/lib/GR/CMakeLists.txt index 9cf7a3dcb2e..3b44fe3e465 100644 --- a/clang/lib/GR/CMakeLists.txt +++ b/clang/lib/GR/CMakeLists.txt @@ -19,10 +19,10 @@ add_clang_library(clangGRCore ExplodedGraph.cpp FlatStore.cpp FrontendActions.cpp - GRBlockCounter.cpp - GRCXXExprEngine.cpp - GRCoreEngine.cpp - GRExprEngine.cpp + BlockCounter.cpp + CXXExprEngine.cpp + CoreEngine.cpp + ExprEngine.cpp GRState.cpp HTMLDiagnostics.cpp ManagerRegistry.cpp diff --git a/clang/lib/GR/CXXExprEngine.cpp b/clang/lib/GR/CXXExprEngine.cpp new file mode 100644 index 00000000000..b1111c90fe5 --- /dev/null +++ b/clang/lib/GR/CXXExprEngine.cpp @@ -0,0 +1,328 @@ +//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- 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 the C++ expression evaluation engine. +// +//===----------------------------------------------------------------------===// + +#include "clang/GR/PathSensitive/AnalysisManager.h" +#include "clang/GR/PathSensitive/ExprEngine.h" +#include "clang/AST/DeclCXX.h" + +using namespace clang; +using namespace GR; + +namespace { +class CallExprWLItem { +public: + CallExpr::const_arg_iterator I; + ExplodedNode *N; + + CallExprWLItem(const CallExpr::const_arg_iterator &i, ExplodedNode *n) + : I(i), N(n) {} +}; +} + +void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE, + const FunctionProtoType *FnType, + ExplodedNode *Pred, ExplodedNodeSet &Dst, + bool FstArgAsLValue) { + + + llvm::SmallVector WorkList; + WorkList.reserve(AE - AI); + WorkList.push_back(CallExprWLItem(AI, Pred)); + + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + Dst.insert(Item.N); + continue; + } + + // Evaluate the argument. + ExplodedNodeSet Tmp; + bool VisitAsLvalue = FstArgAsLValue; + if (FstArgAsLValue) { + FstArgAsLValue = false; + } else { + const unsigned ParamIdx = Item.I - AI; + VisitAsLvalue = FnType && ParamIdx < FnType->getNumArgs() + ? FnType->getArgType(ParamIdx)->isReferenceType() + : false; + } + + Visit(*Item.I, Item.N, Tmp); + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); + } +} + +const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D, + const StackFrameContext *SFC) { + Type *T = D->getTypeForDecl(); + QualType PT = getContext().getPointerType(QualType(T, 0)); + return svalBuilder.getRegionManager().getCXXThisRegion(PT, SFC); +} + +const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl, + const StackFrameContext *frameCtx) { + return svalBuilder.getRegionManager(). + getCXXThisRegion(decl->getThisType(getContext()), frameCtx); +} + +void ExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + // Bind the temporary object to the value of the expression. Then bind + // the expression to the location of the object. + SVal V = state->getSVal(Ex); + + const MemRegion *R = + svalBuilder.getRegionManager().getCXXTempObjectRegion(Ex, + Pred->getLocationContext()); + + state = state->bindLoc(loc::MemRegionVal(R), V); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); + } +} + +void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, + const MemRegion *Dest, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (!Dest) + Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E, + Pred->getLocationContext()); + + if (E->isElidable()) { + VisitAggExpr(E->getArg(0), Dest, Pred, Dst); + return; + } + + const CXXConstructorDecl *CD = E->getConstructor(); + assert(CD); + + if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) + // FIXME: invalidate the object. + return; + + + // Evaluate other arguments. + ExplodedNodeSet argsEvaluated; + const FunctionProtoType *FnType = CD->getType()->getAs(); + evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated); + // The callee stack frame context used to create the 'this' parameter region. + const StackFrameContext *SFC = AMgr.getStackFrame(CD, + Pred->getLocationContext(), + E, Builder->getBlock(), + Builder->getIndex()); + + const CXXThisRegion *ThisR =getCXXThisRegion(E->getConstructor()->getParent(), + SFC); + + CallEnter Loc(E, SFC, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), + NE = argsEvaluated.end(); NI != NE; ++NI) { + const GRState *state = GetState(*NI); + // Setup 'this' region, so that the ctor is evaluated on the object pointed + // by 'Dest'. + state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + if (N) + Dst.Add(N); + } +} + +void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, + const MemRegion *Dest, + const Stmt *S, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (!(DD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) + return; + // Create the context for 'this' region. + const StackFrameContext *SFC = AMgr.getStackFrame(DD, + Pred->getLocationContext(), + S, Builder->getBlock(), + Builder->getIndex()); + + const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC); + + CallEnter PP(S, SFC, Pred->getLocationContext()); + + const GRState *state = Pred->getState(); + state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); + ExplodedNode *N = Builder->generateNode(PP, state, Pred); + if (N) + Dst.Add(N); +} + +void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the method type. + const FunctionProtoType *FnType = + MCE->getCallee()->getType()->getAs(); + assert(FnType && "Method type not available"); + + // Evaluate explicit arguments with a worklist. + ExplodedNodeSet argsEvaluated; + evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated); + + // Evaluate the implicit object argument. + ExplodedNodeSet AllargsEvaluated; + const MemberExpr *ME = dyn_cast(MCE->getCallee()->IgnoreParens()); + if (!ME) + return; + Expr *ObjArgExpr = ME->getBase(); + for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), + E = argsEvaluated.end(); I != E; ++I) { + Visit(ObjArgExpr, *I, AllargsEvaluated); + } + + // Now evaluate the call itself. + const CXXMethodDecl *MD = cast(ME->getMemberDecl()); + assert(MD && "not a CXXMethodDecl?"); + evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst); +} + +void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + const CXXMethodDecl *MD = dyn_cast_or_null(C->getCalleeDecl()); + if (!MD) { + // If the operator doesn't represent a method call treat as regural call. + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + return; + } + + // Determine the type of function we're calling (if available). + const FunctionProtoType *Proto = NULL; + QualType FnType = C->getCallee()->IgnoreParens()->getType(); + if (const PointerType *FnTypePtr = FnType->getAs()) + Proto = FnTypePtr->getPointeeType()->getAs(); + + // Evaluate arguments treating the first one (object method is called on) + // as alvalue. + ExplodedNodeSet argsEvaluated; + evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true); + + // Now evaluate the call itself. + evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst); +} + +void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, + const Expr *ThisExpr, ExplodedNode *Pred, + ExplodedNodeSet &Src, ExplodedNodeSet &Dst) { + // Allow checkers to pre-visit the member call. + ExplodedNodeSet PreVisitChecks; + CheckerVisit(MCE, PreVisitChecks, Src, PreVisitStmtCallback); + + if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) { + // FIXME: conservative method call evaluation. + CheckerVisit(MCE, Dst, PreVisitChecks, PostVisitStmtCallback); + return; + } + + const StackFrameContext *SFC = AMgr.getStackFrame(MD, + Pred->getLocationContext(), + MCE, + Builder->getBlock(), + Builder->getIndex()); + const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); + CallEnter Loc(MCE, SFC, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(), + E = PreVisitChecks.end(); I != E; ++I) { + // Set up 'this' region. + const GRState *state = GetState(*I); + state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr)); + Dst.Add(Builder->generateNode(Loc, state, *I)); + } +} + +void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (CNE->isArray()) { + // FIXME: allocating an array has not been handled. + return; + } + + unsigned Count = Builder->getCurrentBlockCount(); + DefinedOrUnknownSVal symVal = + svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), Count); + const MemRegion *NewReg = cast(symVal).getRegion(); + + QualType ObjTy = CNE->getType()->getAs()->getPointeeType(); + + const ElementRegion *EleReg = + getStoreManager().GetElementZeroRegion(NewReg, ObjTy); + + // Evaluate constructor arguments. + const FunctionProtoType *FnType = NULL; + const CXXConstructorDecl *CD = CNE->getConstructor(); + if (CD) + FnType = CD->getType()->getAs(); + ExplodedNodeSet argsEvaluated; + evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), + FnType, Pred, argsEvaluated); + + // Initialize the object region and bind the 'new' expression. + for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), + E = argsEvaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + if (ObjTy->isRecordType()) { + state = state->InvalidateRegion(EleReg, CNE, Count); + } else { + if (CNE->hasInitializer()) { + SVal V = state->getSVal(*CNE->constructor_arg_begin()); + state = state->bindLoc(loc::MemRegionVal(EleReg), V); + } else { + // Explicitly set to undefined, because currently we retrieve symbolic + // value from symbolic region. + state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); + } + } + state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); + MakeNode(Dst, CNE, *I, state); + } +} + +void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, + ExplodedNode *Pred,ExplodedNodeSet &Dst) { + // Should do more checking. + ExplodedNodeSet Argevaluated; + Visit(CDE->getArgument(), Pred, Argevaluated); + for (ExplodedNodeSet::iterator I = Argevaluated.begin(), + E = Argevaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + MakeNode(Dst, CDE, *I, state); + } +} + +void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the this object region from StoreManager. + const MemRegion *R = + svalBuilder.getRegionManager().getCXXThisRegion( + getContext().getCanonicalType(TE->getType()), + Pred->getLocationContext()); + + const GRState *state = GetState(Pred); + SVal V = state->getSVal(loc::MemRegionVal(R)); + MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); +} diff --git a/clang/lib/GR/Checkers/AdjustedReturnValueChecker.cpp b/clang/lib/GR/Checkers/AdjustedReturnValueChecker.cpp index d9cfd3cac84..3c78b39d207 100644 --- a/clang/lib/GR/Checkers/AdjustedReturnValueChecker.cpp +++ b/clang/lib/GR/Checkers/AdjustedReturnValueChecker.cpp @@ -13,9 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugReporter.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" using namespace clang; @@ -35,7 +35,7 @@ public: }; } -void GR::RegisterAdjustedReturnValueChecker(GRExprEngine &Eng) { +void GR::RegisterAdjustedReturnValueChecker(ExprEngine &Eng) { Eng.registerCheck(new AdjustedReturnValueChecker()); } diff --git a/clang/lib/GR/Checkers/ArrayBoundChecker.cpp b/clang/lib/GR/Checkers/ArrayBoundChecker.cpp index f97adf3d145..9dc53a2360b 100644 --- a/clang/lib/GR/Checkers/ArrayBoundChecker.cpp +++ b/clang/lib/GR/Checkers/ArrayBoundChecker.cpp @@ -12,10 +12,10 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" using namespace clang; using namespace GR; @@ -31,7 +31,7 @@ public: }; } -void GR::RegisterArrayBoundChecker(GRExprEngine &Eng) { +void GR::RegisterArrayBoundChecker(ExprEngine &Eng) { Eng.registerCheck(new ArrayBoundChecker()); } diff --git a/clang/lib/GR/Checkers/AttrNonNullChecker.cpp b/clang/lib/GR/Checkers/AttrNonNullChecker.cpp index baf209e3c86..74eb882d545 100644 --- a/clang/lib/GR/Checkers/AttrNonNullChecker.cpp +++ b/clang/lib/GR/Checkers/AttrNonNullChecker.cpp @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// // -// This defines AttrNonNullChecker, a builtin check in GRExprEngine that +// This defines AttrNonNullChecker, a builtin check in ExprEngine that // performs checks for arguments declared to have nonnull attribute. // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -33,7 +33,7 @@ public: }; } // end anonymous namespace -void GR::RegisterAttrNonNullChecker(GRExprEngine &Eng) { +void GR::RegisterAttrNonNullChecker(ExprEngine &Eng) { Eng.registerCheck(new AttrNonNullChecker()); } diff --git a/clang/lib/GR/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/GR/Checkers/BasicObjCFoundationChecks.cpp index 93c8babde13..33a58bdec9a 100644 --- a/clang/lib/GR/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/GR/Checkers/BasicObjCFoundationChecks.cpp @@ -17,7 +17,7 @@ #include "clang/GR/PathSensitive/ExplodedGraph.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/GR/PathSensitive/GRState.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/MemRegion.h" @@ -511,7 +511,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, // Check registration. //===----------------------------------------------------------------------===// -void GR::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { +void GR::RegisterAppleChecks(ExprEngine& Eng, const Decl &D) { Eng.registerCheck(new NilArgChecker()); Eng.registerCheck(new CFNumberCreateChecker()); RegisterNSErrorChecks(Eng.getBugReporter(), Eng, D); diff --git a/clang/lib/GR/Checkers/BasicObjCFoundationChecks.h b/clang/lib/GR/Checkers/BasicObjCFoundationChecks.h index 7fdccdcacb8..63143ebe252 100644 --- a/clang/lib/GR/Checkers/BasicObjCFoundationChecks.h +++ b/clang/lib/GR/Checkers/BasicObjCFoundationChecks.h @@ -24,10 +24,10 @@ class Decl; namespace GR { class BugReporter; -class GRExprEngine; +class ExprEngine; -void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D); -void RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng); +void RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng, const Decl &D); +void RegisterNSAutoreleasePoolChecks(ExprEngine &Eng); } // end GR namespace diff --git a/clang/lib/GR/Checkers/BuiltinFunctionChecker.cpp b/clang/lib/GR/Checkers/BuiltinFunctionChecker.cpp index dc55a65ff5a..27162e40af9 100644 --- a/clang/lib/GR/Checkers/BuiltinFunctionChecker.cpp +++ b/clang/lib/GR/Checkers/BuiltinFunctionChecker.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/PathSensitive/Checker.h" #include "clang/Basic/Builtins.h" @@ -28,7 +28,7 @@ public: } -void GR::RegisterBuiltinFunctionChecker(GRExprEngine &Eng) { +void GR::RegisterBuiltinFunctionChecker(ExprEngine &Eng) { Eng.registerCheck(new BuiltinFunctionChecker()); } diff --git a/clang/lib/GR/Checkers/CMakeLists.txt b/clang/lib/GR/Checkers/CMakeLists.txt index 700adb544b8..cae050d94cb 100644 --- a/clang/lib/GR/Checkers/CMakeLists.txt +++ b/clang/lib/GR/Checkers/CMakeLists.txt @@ -17,7 +17,7 @@ add_clang_library(clangGRCheckers DereferenceChecker.cpp DivZeroChecker.cpp FixedAddressChecker.cpp - GRExprEngineExperimentalChecks.cpp + ExprEngineExperimentalChecks.cpp IdempotentOperationChecker.cpp LLVMConventionsChecker.cpp MacOSXAPIChecker.cpp diff --git a/clang/lib/GR/Checkers/CStringChecker.cpp b/clang/lib/GR/Checkers/CStringChecker.cpp index da0bba37416..a9d3064fcaf 100644 --- a/clang/lib/GR/Checkers/CStringChecker.cpp +++ b/clang/lib/GR/Checkers/CStringChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineExperimentalChecks.h" +#include "ExprEngineExperimentalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" #include "clang/GR/PathSensitive/GRStateTrait.h" @@ -109,7 +109,7 @@ namespace GR { } } -void GR::RegisterCStringChecker(GRExprEngine &Eng) { +void GR::RegisterCStringChecker(ExprEngine &Eng) { Eng.registerCheck(new CStringChecker()); } diff --git a/clang/lib/GR/Checkers/CallAndMessageChecker.cpp b/clang/lib/GR/Checkers/CallAndMessageChecker.cpp index 8b8f75faf68..f3306d136bc 100644 --- a/clang/lib/GR/Checkers/CallAndMessageChecker.cpp +++ b/clang/lib/GR/Checkers/CallAndMessageChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/AST/ParentMap.h" #include "clang/Basic/TargetInfo.h" #include "clang/GR/BugReporter/BugType.h" @@ -62,7 +62,7 @@ private: }; } // end anonymous namespace -void GR::RegisterCallAndMessageChecker(GRExprEngine &Eng) { +void GR::RegisterCallAndMessageChecker(ExprEngine &Eng) { Eng.registerCheck(new CallAndMessageChecker()); } diff --git a/clang/lib/GR/Checkers/CastSizeChecker.cpp b/clang/lib/GR/Checkers/CastSizeChecker.cpp index bcbb89441f4..c17dc7a266e 100644 --- a/clang/lib/GR/Checkers/CastSizeChecker.cpp +++ b/clang/lib/GR/Checkers/CastSizeChecker.cpp @@ -14,7 +14,7 @@ #include "clang/AST/CharUnits.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" using namespace clang; using namespace GR; @@ -86,6 +86,6 @@ void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) { } -void GR::RegisterCastSizeChecker(GRExprEngine &Eng) { +void GR::RegisterCastSizeChecker(ExprEngine &Eng) { Eng.registerCheck(new CastSizeChecker()); } diff --git a/clang/lib/GR/Checkers/CastToStructChecker.cpp b/clang/lib/GR/Checkers/CastToStructChecker.cpp index 0bcba284b86..7b0732938c1 100644 --- a/clang/lib/GR/Checkers/CastToStructChecker.cpp +++ b/clang/lib/GR/Checkers/CastToStructChecker.cpp @@ -15,7 +15,7 @@ #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" using namespace clang; using namespace GR; @@ -74,6 +74,6 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, } } -void GR::RegisterCastToStructChecker(GRExprEngine &Eng) { +void GR::RegisterCastToStructChecker(ExprEngine &Eng) { Eng.registerCheck(new CastToStructChecker()); } diff --git a/clang/lib/GR/Checkers/CheckDeadStores.cpp b/clang/lib/GR/Checkers/CheckDeadStores.cpp index 44fdb3afbba..edcf57ceca2 100644 --- a/clang/lib/GR/Checkers/CheckDeadStores.cpp +++ b/clang/lib/GR/Checkers/CheckDeadStores.cpp @@ -16,7 +16,7 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" #include "clang/GR/BugReporter/BugReporter.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Basic/Diagnostic.h" #include "clang/AST/ASTContext.h" diff --git a/clang/lib/GR/Checkers/ChrootChecker.cpp b/clang/lib/GR/Checkers/ChrootChecker.cpp index f93ee7b9416..58b34d08520 100644 --- a/clang/lib/GR/Checkers/ChrootChecker.cpp +++ b/clang/lib/GR/Checkers/ChrootChecker.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineExperimentalChecks.h" +#include "ExprEngineExperimentalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" #include "clang/GR/PathSensitive/GRState.h" @@ -59,7 +59,7 @@ private: } // end anonymous namespace -void GR::RegisterChrootChecker(GRExprEngine &Eng) { +void GR::RegisterChrootChecker(ExprEngine &Eng) { Eng.registerCheck(new ChrootChecker()); } diff --git a/clang/lib/GR/Checkers/DereferenceChecker.cpp b/clang/lib/GR/Checkers/DereferenceChecker.cpp index 62b1f86fb48..dbe0ab3262e 100644 --- a/clang/lib/GR/Checkers/DereferenceChecker.cpp +++ b/clang/lib/GR/Checkers/DereferenceChecker.cpp @@ -7,16 +7,16 @@ // //===----------------------------------------------------------------------===// // -// This defines NullDerefChecker, a builtin check in GRExprEngine that performs +// This defines NullDerefChecker, a builtin check in ExprEngine that performs // checks for null pointers at loads and stores. // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/Checkers/DereferenceChecker.h" #include "clang/GR/PathSensitive/Checker.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" using namespace clang; using namespace GR; @@ -43,12 +43,12 @@ public: }; } // end anonymous namespace -void GR::RegisterDereferenceChecker(GRExprEngine &Eng) { +void GR::RegisterDereferenceChecker(ExprEngine &Eng) { Eng.registerCheck(new DereferenceChecker()); } std::pair -GR::GetImplicitNullDereferences(GRExprEngine &Eng) { +GR::GetImplicitNullDereferences(ExprEngine &Eng) { DereferenceChecker *checker = Eng.getChecker(); if (!checker) return std::make_pair((ExplodedNode * const *) 0, diff --git a/clang/lib/GR/Checkers/DivZeroChecker.cpp b/clang/lib/GR/Checkers/DivZeroChecker.cpp index a4cb1a4a130..1475a9e1cd3 100644 --- a/clang/lib/GR/Checkers/DivZeroChecker.cpp +++ b/clang/lib/GR/Checkers/DivZeroChecker.cpp @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// // -// This defines DivZeroChecker, a builtin check in GRExprEngine that performs +// This defines DivZeroChecker, a builtin check in ExprEngine that performs // checks for division by zeros. // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -29,7 +29,7 @@ public: }; } // end anonymous namespace -void GR::RegisterDivZeroChecker(GRExprEngine &Eng) { +void GR::RegisterDivZeroChecker(ExprEngine &Eng) { Eng.registerCheck(new DivZeroChecker()); } diff --git a/clang/lib/GR/Checkers/ExprEngineExperimentalChecks.cpp b/clang/lib/GR/Checkers/ExprEngineExperimentalChecks.cpp new file mode 100644 index 00000000000..d7ad99ffc22 --- /dev/null +++ b/clang/lib/GR/Checkers/ExprEngineExperimentalChecks.cpp @@ -0,0 +1,46 @@ +//=-- ExprEngineExperimentalChecks.h ------------------------------*- 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 functions to instantiate and register experimental +// checks in ExprEngine. +// +//===----------------------------------------------------------------------===// + +#include "ExprEngineInternalChecks.h" +#include "ExprEngineExperimentalChecks.h" +#include "clang/GR/Checkers/LocalCheckers.h" + +using namespace clang; +using namespace GR; + +void GR::RegisterExperimentalChecks(ExprEngine &Eng) { + // These are checks that never belong as internal checks + // within ExprEngine. + RegisterCStringChecker(Eng); + RegisterChrootChecker(Eng); + RegisterMallocChecker(Eng); + RegisterPthreadLockChecker(Eng); + RegisterStreamChecker(Eng); + RegisterUnreachableCodeChecker(Eng); +} + +void GR::RegisterExperimentalInternalChecks(ExprEngine &Eng) { + // These are internal checks that should eventually migrate to + // RegisterInternalChecks() once they have been further tested. + + // Note that this must be registered after ReturnStackAddresEngsChecker. + RegisterReturnPointerRangeChecker(Eng); + + RegisterArrayBoundChecker(Eng); + RegisterCastSizeChecker(Eng); + RegisterCastToStructChecker(Eng); + RegisterFixedAddressChecker(Eng); + RegisterPointerArithChecker(Eng); + RegisterPointerSubChecker(Eng); +} diff --git a/clang/lib/GR/Checkers/ExprEngineExperimentalChecks.h b/clang/lib/GR/Checkers/ExprEngineExperimentalChecks.h new file mode 100644 index 00000000000..4a04fb9b2f7 --- /dev/null +++ b/clang/lib/GR/Checkers/ExprEngineExperimentalChecks.h @@ -0,0 +1,37 @@ +//=-- ExprEngineExperimentalChecks.h ------------------------------*- 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 functions to instantiate and register experimental +// checks in ExprEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS +#define LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS + +namespace clang { + +namespace GR { + +class ExprEngine; + +void RegisterAnalyzerStatsChecker(ExprEngine &Eng); +void RegisterChrootChecker(ExprEngine &Eng); +void RegisterCStringChecker(ExprEngine &Eng); +void RegisterIdempotentOperationChecker(ExprEngine &Eng); +void RegisterMallocChecker(ExprEngine &Eng); +void RegisterPthreadLockChecker(ExprEngine &Eng); +void RegisterStreamChecker(ExprEngine &Eng); +void RegisterUnreachableCodeChecker(ExprEngine &Eng); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/lib/GR/Checkers/ExprEngineInternalChecks.h b/clang/lib/GR/Checkers/ExprEngineInternalChecks.h new file mode 100644 index 00000000000..aa2f99b1a11 --- /dev/null +++ b/clang/lib/GR/Checkers/ExprEngineInternalChecks.h @@ -0,0 +1,58 @@ +//=-- ExprEngineInternalChecks.h- Builtin ExprEngine Checks -----*- 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 functions to instantiate and register the "built-in" +// checks in ExprEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS +#define LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS + +namespace clang { + +namespace GR { + +class ExprEngine; + +// Foundational checks that handle basic semantics. +void RegisterAdjustedReturnValueChecker(ExprEngine &Eng); +void RegisterArrayBoundChecker(ExprEngine &Eng); +void RegisterAttrNonNullChecker(ExprEngine &Eng); +void RegisterBuiltinFunctionChecker(ExprEngine &Eng); +void RegisterCallAndMessageChecker(ExprEngine &Eng); +void RegisterCastToStructChecker(ExprEngine &Eng); +void RegisterCastSizeChecker(ExprEngine &Eng); +void RegisterDereferenceChecker(ExprEngine &Eng); +void RegisterDivZeroChecker(ExprEngine &Eng); +void RegisterFixedAddressChecker(ExprEngine &Eng); +void RegisterNoReturnFunctionChecker(ExprEngine &Eng); +void RegisterObjCAtSyncChecker(ExprEngine &Eng); +void RegisterPointerArithChecker(ExprEngine &Eng); +void RegisterPointerSubChecker(ExprEngine &Eng); +void RegisterReturnPointerRangeChecker(ExprEngine &Eng); +void RegisterReturnUndefChecker(ExprEngine &Eng); +void RegisterStackAddrLeakChecker(ExprEngine &Eng); +void RegisterUndefBranchChecker(ExprEngine &Eng); +void RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng); +void RegisterUndefResultChecker(ExprEngine &Eng); +void RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng); +void RegisterUndefinedAssignmentChecker(ExprEngine &Eng); +void RegisterVLASizeChecker(ExprEngine &Eng); + +// API checks. +void RegisterMacOSXAPIChecker(ExprEngine &Eng); +void RegisterOSAtomicChecker(ExprEngine &Eng); +void RegisterUnixAPIChecker(ExprEngine &Eng); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/lib/GR/Checkers/FixedAddressChecker.cpp b/clang/lib/GR/Checkers/FixedAddressChecker.cpp index 4c7086f4f1e..d7caad17dab 100644 --- a/clang/lib/GR/Checkers/FixedAddressChecker.cpp +++ b/clang/lib/GR/Checkers/FixedAddressChecker.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -67,6 +67,6 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C, } } -void GR::RegisterFixedAddressChecker(GRExprEngine &Eng) { +void GR::RegisterFixedAddressChecker(ExprEngine &Eng) { Eng.registerCheck(new FixedAddressChecker()); } diff --git a/clang/lib/GR/Checkers/GRExprEngineExperimentalChecks.cpp b/clang/lib/GR/Checkers/GRExprEngineExperimentalChecks.cpp deleted file mode 100644 index fd9bf5dd520..00000000000 --- a/clang/lib/GR/Checkers/GRExprEngineExperimentalChecks.cpp +++ /dev/null @@ -1,46 +0,0 @@ -//=-- GRExprEngineExperimentalChecks.h ------------------------------*- 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 functions to instantiate and register experimental -// checks in GRExprEngine. -// -//===----------------------------------------------------------------------===// - -#include "GRExprEngineInternalChecks.h" -#include "GRExprEngineExperimentalChecks.h" -#include "clang/GR/Checkers/LocalCheckers.h" - -using namespace clang; -using namespace GR; - -void GR::RegisterExperimentalChecks(GRExprEngine &Eng) { - // These are checks that never belong as internal checks - // within GRExprEngine. - RegisterCStringChecker(Eng); - RegisterChrootChecker(Eng); - RegisterMallocChecker(Eng); - RegisterPthreadLockChecker(Eng); - RegisterStreamChecker(Eng); - RegisterUnreachableCodeChecker(Eng); -} - -void GR::RegisterExperimentalInternalChecks(GRExprEngine &Eng) { - // These are internal checks that should eventually migrate to - // RegisterInternalChecks() once they have been further tested. - - // Note that this must be registered after ReturnStackAddresEngsChecker. - RegisterReturnPointerRangeChecker(Eng); - - RegisterArrayBoundChecker(Eng); - RegisterCastSizeChecker(Eng); - RegisterCastToStructChecker(Eng); - RegisterFixedAddressChecker(Eng); - RegisterPointerArithChecker(Eng); - RegisterPointerSubChecker(Eng); -} diff --git a/clang/lib/GR/Checkers/GRExprEngineExperimentalChecks.h b/clang/lib/GR/Checkers/GRExprEngineExperimentalChecks.h deleted file mode 100644 index 54a61256590..00000000000 --- a/clang/lib/GR/Checkers/GRExprEngineExperimentalChecks.h +++ /dev/null @@ -1,37 +0,0 @@ -//=-- GRExprEngineExperimentalChecks.h ------------------------------*- 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 functions to instantiate and register experimental -// checks in GRExprEngine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_GR_GREXPRENGINE_EXPERIMENTAL_CHECKS -#define LLVM_CLANG_GR_GREXPRENGINE_EXPERIMENTAL_CHECKS - -namespace clang { - -namespace GR { - -class GRExprEngine; - -void RegisterAnalyzerStatsChecker(GRExprEngine &Eng); -void RegisterChrootChecker(GRExprEngine &Eng); -void RegisterCStringChecker(GRExprEngine &Eng); -void RegisterIdempotentOperationChecker(GRExprEngine &Eng); -void RegisterMallocChecker(GRExprEngine &Eng); -void RegisterPthreadLockChecker(GRExprEngine &Eng); -void RegisterStreamChecker(GRExprEngine &Eng); -void RegisterUnreachableCodeChecker(GRExprEngine &Eng); - -} // end GR namespace - -} // end clang namespace - -#endif diff --git a/clang/lib/GR/Checkers/GRExprEngineInternalChecks.h b/clang/lib/GR/Checkers/GRExprEngineInternalChecks.h deleted file mode 100644 index cba419a9b60..00000000000 --- a/clang/lib/GR/Checkers/GRExprEngineInternalChecks.h +++ /dev/null @@ -1,58 +0,0 @@ -//=-- GRExprEngineInternalChecks.h- Builtin GRExprEngine Checks -----*- 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 functions to instantiate and register the "built-in" -// checks in GRExprEngine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_GR_GREXPRENGINE_INTERNAL_CHECKS -#define LLVM_CLANG_GR_GREXPRENGINE_INTERNAL_CHECKS - -namespace clang { - -namespace GR { - -class GRExprEngine; - -// Foundational checks that handle basic semantics. -void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng); -void RegisterArrayBoundChecker(GRExprEngine &Eng); -void RegisterAttrNonNullChecker(GRExprEngine &Eng); -void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); -void RegisterCallAndMessageChecker(GRExprEngine &Eng); -void RegisterCastToStructChecker(GRExprEngine &Eng); -void RegisterCastSizeChecker(GRExprEngine &Eng); -void RegisterDereferenceChecker(GRExprEngine &Eng); -void RegisterDivZeroChecker(GRExprEngine &Eng); -void RegisterFixedAddressChecker(GRExprEngine &Eng); -void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); -void RegisterObjCAtSyncChecker(GRExprEngine &Eng); -void RegisterPointerArithChecker(GRExprEngine &Eng); -void RegisterPointerSubChecker(GRExprEngine &Eng); -void RegisterReturnPointerRangeChecker(GRExprEngine &Eng); -void RegisterReturnUndefChecker(GRExprEngine &Eng); -void RegisterStackAddrLeakChecker(GRExprEngine &Eng); -void RegisterUndefBranchChecker(GRExprEngine &Eng); -void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng); -void RegisterUndefResultChecker(GRExprEngine &Eng); -void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); -void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); -void RegisterVLASizeChecker(GRExprEngine &Eng); - -// API checks. -void RegisterMacOSXAPIChecker(GRExprEngine &Eng); -void RegisterOSAtomicChecker(GRExprEngine &Eng); -void RegisterUnixAPIChecker(GRExprEngine &Eng); - -} // end GR namespace - -} // end clang namespace - -#endif diff --git a/clang/lib/GR/Checkers/IdempotentOperationChecker.cpp b/clang/lib/GR/Checkers/IdempotentOperationChecker.cpp index b28edc3b12d..15e9be95804 100644 --- a/clang/lib/GR/Checkers/IdempotentOperationChecker.cpp +++ b/clang/lib/GR/Checkers/IdempotentOperationChecker.cpp @@ -42,14 +42,14 @@ // - Finer grained false positive control (levels) // - Handling ~0 values -#include "GRExprEngineExperimentalChecks.h" +#include "ExprEngineExperimentalChecks.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" #include "clang/GR/BugReporter/BugReporter.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerHelpers.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRCoreEngine.h" +#include "clang/GR/PathSensitive/CoreEngine.h" #include "clang/GR/PathSensitive/SVals.h" #include "clang/AST/Stmt.h" #include "llvm/ADT/DenseMap.h" @@ -67,7 +67,7 @@ public: static void *getTag(); void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); - void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, GRExprEngine &Eng); + void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng); private: // Our assumption about a particular operation. @@ -84,7 +84,7 @@ private: bool PathWasCompletelyAnalyzed(const CFG *C, const CFGBlock *CB, const CFGStmtMap *CBM, - const GRCoreEngine &CE); + const CoreEngine &CE); static bool CanVary(const Expr *Ex, AnalysisContext *AC); static bool isConstantOrPseudoConstant(const DeclRefExpr *DR, @@ -130,7 +130,7 @@ void *IdempotentOperationChecker::getTag() { return &x; } -void GR::RegisterIdempotentOperationChecker(GRExprEngine &Eng) { +void GR::RegisterIdempotentOperationChecker(ExprEngine &Eng) { Eng.registerCheck(new IdempotentOperationChecker()); } @@ -364,7 +364,7 @@ void IdempotentOperationChecker::PostVisitBinaryOperator( void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G, BugReporter &BR, - GRExprEngine &Eng) { + ExprEngine &Eng) { BugType *BT = new BugType("Idempotent operation", "Dead code"); // Iterate over the hash to see if we have any paths with definite // idempotent operations. @@ -553,9 +553,9 @@ bool IdempotentOperationChecker::PathWasCompletelyAnalyzed( const CFG *C, const CFGBlock *CB, const CFGStmtMap *CBM, - const GRCoreEngine &CE) { + const CoreEngine &CE) { // Test for reachability from any aborted blocks to this block - typedef GRCoreEngine::BlocksAborted::const_iterator AbortedIterator; + typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator; for (AbortedIterator I = CE.blocks_aborted_begin(), E = CE.blocks_aborted_end(); I != E; ++I) { const BlockEdge &BE = I->first; @@ -569,7 +569,7 @@ bool IdempotentOperationChecker::PathWasCompletelyAnalyzed( // For the items still on the worklist, see if they are in blocks that // can eventually reach 'CB'. - class VisitWL : public GRWorkList::Visitor { + class VisitWL : public WorkList::Visitor { const CFGStmtMap *CBM; const CFGBlock *TargetBlock; CFGReachabilityAnalysis &CRA; @@ -577,7 +577,7 @@ bool IdempotentOperationChecker::PathWasCompletelyAnalyzed( VisitWL(const CFGStmtMap *cbm, const CFGBlock *targetBlock, CFGReachabilityAnalysis &cra) : CBM(cbm), TargetBlock(targetBlock), CRA(cra) {} - virtual bool Visit(const GRWorkListUnit &U) { + virtual bool Visit(const WorkListUnit &U) { ProgramPoint P = U.getNode()->getLocation(); const CFGBlock *B = 0; if (StmtPoint *SP = dyn_cast(&P)) { diff --git a/clang/lib/GR/Checkers/MacOSXAPIChecker.cpp b/clang/lib/GR/Checkers/MacOSXAPIChecker.cpp index 316e37a40f4..d7728713f88 100644 --- a/clang/lib/GR/Checkers/MacOSXAPIChecker.cpp +++ b/clang/lib/GR/Checkers/MacOSXAPIChecker.cpp @@ -15,7 +15,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/Basic/TargetInfo.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -45,7 +45,7 @@ public: }; } //end anonymous namespace -void GR::RegisterMacOSXAPIChecker(GRExprEngine &Eng) { +void GR::RegisterMacOSXAPIChecker(ExprEngine &Eng) { if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple) Eng.registerCheck(new MacOSXAPIChecker()); } diff --git a/clang/lib/GR/Checkers/MallocChecker.cpp b/clang/lib/GR/Checkers/MallocChecker.cpp index cd5f636e961..bbfc7b076d3 100644 --- a/clang/lib/GR/Checkers/MallocChecker.cpp +++ b/clang/lib/GR/Checkers/MallocChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineExperimentalChecks.h" +#include "ExprEngineExperimentalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" #include "clang/GR/PathSensitive/GRState.h" @@ -78,7 +78,7 @@ public: static void *getTag(); bool evalCallExpr(CheckerContext &C, const CallExpr *CE); void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper); - void evalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); + void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); const GRState *evalAssume(const GRState *state, SVal Cond, bool Assumption, bool *respondsToCallback); @@ -126,7 +126,7 @@ namespace GR { } } -void GR::RegisterMallocChecker(GRExprEngine &Eng) { +void GR::RegisterMallocChecker(ExprEngine &Eng) { Eng.registerCheck(new MallocChecker()); } @@ -593,8 +593,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) C.generateNode(state->set(RS)); } -void MallocChecker::evalEndPath(GREndPathNodeBuilder &B, void *tag, - GRExprEngine &Eng) { +void MallocChecker::evalEndPath(EndPathNodeBuilder &B, void *tag, + ExprEngine &Eng) { SaveAndRestore OldHasGen(B.HasGeneratedNode); const GRState *state = B.getState(); RegionStateTy M = state->get(); diff --git a/clang/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp b/clang/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp index d6701c7142c..beb4a81743b 100644 --- a/clang/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp +++ b/clang/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp @@ -16,7 +16,7 @@ //===----------------------------------------------------------------------===// #include "clang/GR/BugReporter/BugReporter.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" #include "BasicObjCFoundationChecks.h" #include "clang/AST/DeclObjC.h" @@ -45,7 +45,7 @@ public: } // end anonymous namespace -void GR::RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng) { +void GR::RegisterNSAutoreleasePoolChecks(ExprEngine &Eng) { ASTContext &Ctx = Eng.getContext(); if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) { Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release", diff --git a/clang/lib/GR/Checkers/NSErrorChecker.cpp b/clang/lib/GR/Checkers/NSErrorChecker.cpp index 44715bf9f94..3cfb044d6f8 100644 --- a/clang/lib/GR/Checkers/NSErrorChecker.cpp +++ b/clang/lib/GR/Checkers/NSErrorChecker.cpp @@ -17,7 +17,7 @@ #include "clang/GR/Checkers/LocalCheckers.h" #include "clang/GR/BugReporter/BugType.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/GR/Checkers/DereferenceChecker.h" #include "BasicObjCFoundationChecks.h" #include "clang/AST/DeclObjC.h" @@ -32,7 +32,7 @@ class NSErrorChecker : public BugType { const Decl &CodeDecl; const bool isNSErrorWarning; IdentifierInfo * const II; - GRExprEngine &Eng; + ExprEngine &Eng; void CheckSignature(const ObjCMethodDecl& MD, QualType& ResultTy, llvm::SmallVectorImpl& ErrorParams); @@ -49,7 +49,7 @@ class NSErrorChecker : public BugType { void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl); public: - NSErrorChecker(const Decl &D, bool isNSError, GRExprEngine& eng) + NSErrorChecker(const Decl &D, bool isNSError, ExprEngine& eng) : BugType(isNSError ? "NSError** null dereference" : "CFErrorRef* null dereference", "Coding conventions (Apple)"), @@ -63,7 +63,7 @@ public: } // end anonymous namespace -void GR::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, +void GR::RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng, const Decl &D) { BR.Register(new NSErrorChecker(D, true, Eng)); BR.Register(new NSErrorChecker(D, false, Eng)); diff --git a/clang/lib/GR/Checkers/NoReturnFunctionChecker.cpp b/clang/lib/GR/Checkers/NoReturnFunctionChecker.cpp index 739460f781d..f6d33dbda8d 100644 --- a/clang/lib/GR/Checkers/NoReturnFunctionChecker.cpp +++ b/clang/lib/GR/Checkers/NoReturnFunctionChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" #include "llvm/ADT/StringSwitch.h" @@ -29,7 +29,7 @@ public: } -void GR::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) { +void GR::RegisterNoReturnFunctionChecker(ExprEngine &Eng) { Eng.registerCheck(new NoReturnFunctionChecker()); } diff --git a/clang/lib/GR/Checkers/OSAtomicChecker.cpp b/clang/lib/GR/Checkers/OSAtomicChecker.cpp index 7df7a9eec04..c27e50880e1 100644 --- a/clang/lib/GR/Checkers/OSAtomicChecker.cpp +++ b/clang/lib/GR/Checkers/OSAtomicChecker.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/PathSensitive/Checker.h" #include "clang/Basic/Builtins.h" @@ -31,7 +31,7 @@ private: } -void GR::RegisterOSAtomicChecker(GRExprEngine &Eng) { +void GR::RegisterOSAtomicChecker(ExprEngine &Eng) { Eng.registerCheck(new OSAtomicChecker()); } @@ -97,7 +97,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, const void *OSAtomicStoreTag = &magic_store; // Load 'theValue'. - GRExprEngine &Engine = C.getEngine(); + ExprEngine &Engine = C.getEngine(); const GRState *state = C.getState(); ExplodedNodeSet Tmp; SVal location = state->getSVal(theValueExpr); diff --git a/clang/lib/GR/Checkers/ObjCAtSyncChecker.cpp b/clang/lib/GR/Checkers/ObjCAtSyncChecker.cpp index a3938627b1f..40619a2a853 100644 --- a/clang/lib/GR/Checkers/ObjCAtSyncChecker.cpp +++ b/clang/lib/GR/Checkers/ObjCAtSyncChecker.cpp @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/Checkers/DereferenceChecker.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" using namespace clang; using namespace GR; @@ -33,7 +33,7 @@ public: }; } // end anonymous namespace -void GR::RegisterObjCAtSyncChecker(GRExprEngine &Eng) { +void GR::RegisterObjCAtSyncChecker(ExprEngine &Eng) { // @synchronized is an Objective-C 2 feature. if (Eng.getContext().getLangOptions().ObjC2) Eng.registerCheck(new ObjCAtSyncChecker()); diff --git a/clang/lib/GR/Checkers/PointerArithChecker.cpp b/clang/lib/GR/Checkers/PointerArithChecker.cpp index 485144a1421..1f870052c16 100644 --- a/clang/lib/GR/Checkers/PointerArithChecker.cpp +++ b/clang/lib/GR/Checkers/PointerArithChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -67,6 +67,6 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C, } } -void GR::RegisterPointerArithChecker(GRExprEngine &Eng) { +void GR::RegisterPointerArithChecker(ExprEngine &Eng) { Eng.registerCheck(new PointerArithChecker()); } diff --git a/clang/lib/GR/Checkers/PointerSubChecker.cpp b/clang/lib/GR/Checkers/PointerSubChecker.cpp index 44e3d9f0090..57ab31803ce 100644 --- a/clang/lib/GR/Checkers/PointerSubChecker.cpp +++ b/clang/lib/GR/Checkers/PointerSubChecker.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -74,6 +74,6 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C, } } -void GR::RegisterPointerSubChecker(GRExprEngine &Eng) { +void GR::RegisterPointerSubChecker(ExprEngine &Eng) { Eng.registerCheck(new PointerSubChecker()); } diff --git a/clang/lib/GR/Checkers/PthreadLockChecker.cpp b/clang/lib/GR/Checkers/PthreadLockChecker.cpp index d880b066bc8..ae58b78fb8a 100644 --- a/clang/lib/GR/Checkers/PthreadLockChecker.cpp +++ b/clang/lib/GR/Checkers/PthreadLockChecker.cpp @@ -8,14 +8,14 @@ //===----------------------------------------------------------------------===// // // This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually -// this shouldn't be registered with GRExprEngineInternalChecks. +// this shouldn't be registered with ExprEngineInternalChecks. // //===----------------------------------------------------------------------===// #include "clang/GR/PathSensitive/CheckerVisitor.h" #include "clang/GR/BugReporter/BugReporter.h" #include "clang/GR/PathSensitive/GRStateTrait.h" -#include "GRExprEngineExperimentalChecks.h" +#include "ExprEngineExperimentalChecks.h" #include "llvm/ADT/ImmutableSet.h" using namespace clang; @@ -53,7 +53,7 @@ template <> struct GRStateTrait : } // end GR namespace } // end clang namespace -void GR::RegisterPthreadLockChecker(GRExprEngine &Eng) { +void GR::RegisterPthreadLockChecker(ExprEngine &Eng) { Eng.registerCheck(new PthreadLockChecker()); } diff --git a/clang/lib/GR/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/GR/Checkers/ReturnPointerRangeChecker.cpp index 98b4ea544d7..4ef5737f354 100644 --- a/clang/lib/GR/Checkers/ReturnPointerRangeChecker.cpp +++ b/clang/lib/GR/Checkers/ReturnPointerRangeChecker.cpp @@ -12,10 +12,10 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" using namespace clang; using namespace GR; @@ -31,7 +31,7 @@ public: }; } -void GR::RegisterReturnPointerRangeChecker(GRExprEngine &Eng) { +void GR::RegisterReturnPointerRangeChecker(ExprEngine &Eng) { Eng.registerCheck(new ReturnPointerRangeChecker()); } diff --git a/clang/lib/GR/Checkers/ReturnUndefChecker.cpp b/clang/lib/GR/Checkers/ReturnUndefChecker.cpp index addae5b1c01..2a1027a9301 100644 --- a/clang/lib/GR/Checkers/ReturnUndefChecker.cpp +++ b/clang/lib/GR/Checkers/ReturnUndefChecker.cpp @@ -13,10 +13,10 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" using namespace clang; using namespace GR; @@ -32,7 +32,7 @@ public: }; } -void GR::RegisterReturnUndefChecker(GRExprEngine &Eng) { +void GR::RegisterReturnUndefChecker(ExprEngine &Eng) { Eng.registerCheck(new ReturnUndefChecker()); } diff --git a/clang/lib/GR/Checkers/StackAddrLeakChecker.cpp b/clang/lib/GR/Checkers/StackAddrLeakChecker.cpp index 87f5819cf7e..3ef78a46fb1 100644 --- a/clang/lib/GR/Checkers/StackAddrLeakChecker.cpp +++ b/clang/lib/GR/Checkers/StackAddrLeakChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" #include "clang/GR/PathSensitive/GRState.h" @@ -33,7 +33,7 @@ public: return &x; } void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS); - void evalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); + void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng); private: void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE); SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R, @@ -41,7 +41,7 @@ private: }; } -void GR::RegisterStackAddrLeakChecker(GRExprEngine &Eng) { +void GR::RegisterStackAddrLeakChecker(ExprEngine &Eng) { Eng.registerCheck(new StackAddrLeakChecker()); } @@ -130,8 +130,8 @@ void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C, } } -void StackAddrLeakChecker::evalEndPath(GREndPathNodeBuilder &B, void *tag, - GRExprEngine &Eng) { +void StackAddrLeakChecker::evalEndPath(EndPathNodeBuilder &B, void *tag, + ExprEngine &Eng) { SaveAndRestore OldHasGen(B.HasGeneratedNode); const GRState *state = B.getState(); diff --git a/clang/lib/GR/Checkers/StreamChecker.cpp b/clang/lib/GR/Checkers/StreamChecker.cpp index 01186b52dfc..73c2920ad94 100644 --- a/clang/lib/GR/Checkers/StreamChecker.cpp +++ b/clang/lib/GR/Checkers/StreamChecker.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineExperimentalChecks.h" +#include "ExprEngineExperimentalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" #include "clang/GR/PathSensitive/GRState.h" @@ -75,7 +75,7 @@ public: virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE); void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper); - void evalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); + void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); private: @@ -114,7 +114,7 @@ namespace GR { } } -void GR::RegisterStreamChecker(GRExprEngine &Eng) { +void GR::RegisterStreamChecker(ExprEngine &Eng) { Eng.registerCheck(new StreamChecker()); } @@ -421,8 +421,8 @@ void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) { } } -void StreamChecker::evalEndPath(GREndPathNodeBuilder &B, void *tag, - GRExprEngine &Eng) { +void StreamChecker::evalEndPath(EndPathNodeBuilder &B, void *tag, + ExprEngine &Eng) { SaveAndRestore OldHasGen(B.HasGeneratedNode); const GRState *state = B.getState(); typedef llvm::ImmutableMap SymMap; diff --git a/clang/lib/GR/Checkers/UndefBranchChecker.cpp b/clang/lib/GR/Checkers/UndefBranchChecker.cpp index fa3dfa59351..e999d8bc132 100644 --- a/clang/lib/GR/Checkers/UndefBranchChecker.cpp +++ b/clang/lib/GR/Checkers/UndefBranchChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/Checker.h" @@ -50,13 +50,13 @@ class UndefBranchChecker : public Checker { public: UndefBranchChecker() : BT(0) {} static void *getTag(); - void VisitBranchCondition(GRBranchNodeBuilder &Builder, GRExprEngine &Eng, + void VisitBranchCondition(BranchNodeBuilder &Builder, ExprEngine &Eng, const Stmt *Condition, void *tag); }; } -void GR::RegisterUndefBranchChecker(GRExprEngine &Eng) { +void GR::RegisterUndefBranchChecker(ExprEngine &Eng) { Eng.registerCheck(new UndefBranchChecker()); } @@ -65,8 +65,8 @@ void *UndefBranchChecker::getTag() { return &x; } -void UndefBranchChecker::VisitBranchCondition(GRBranchNodeBuilder &Builder, - GRExprEngine &Eng, +void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder, + ExprEngine &Eng, const Stmt *Condition, void *tag){ const GRState *state = Builder.getState(); SVal X = state->getSVal(Condition); diff --git a/clang/lib/GR/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/GR/Checkers/UndefCapturedBlockVarChecker.cpp index 8a1c285c173..2b45c95843e 100644 --- a/clang/lib/GR/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/clang/lib/GR/Checkers/UndefCapturedBlockVarChecker.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/GR/BugReporter/BugType.h" #include "llvm/Support/raw_ostream.h" @@ -32,7 +32,7 @@ public: }; } // end anonymous namespace -void GR::RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng) { +void GR::RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng) { Eng.registerCheck(new UndefCapturedBlockVarChecker()); } diff --git a/clang/lib/GR/Checkers/UndefResultChecker.cpp b/clang/lib/GR/Checkers/UndefResultChecker.cpp index f4d30354e83..348573d21c6 100644 --- a/clang/lib/GR/Checkers/UndefResultChecker.cpp +++ b/clang/lib/GR/Checkers/UndefResultChecker.cpp @@ -7,15 +7,15 @@ // //===----------------------------------------------------------------------===// // -// This defines UndefResultChecker, a builtin check in GRExprEngine that +// This defines UndefResultChecker, a builtin check in ExprEngine that // performs checks for undefined results of non-assignment binary operators. // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" using namespace clang; using namespace GR; @@ -33,7 +33,7 @@ public: }; } // end anonymous namespace -void GR::RegisterUndefResultChecker(GRExprEngine &Eng) { +void GR::RegisterUndefResultChecker(ExprEngine &Eng) { Eng.registerCheck(new UndefResultChecker()); } diff --git a/clang/lib/GR/Checkers/UndefinedArraySubscriptChecker.cpp b/clang/lib/GR/Checkers/UndefinedArraySubscriptChecker.cpp index 8946de39981..0a3cee43a12 100644 --- a/clang/lib/GR/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/clang/lib/GR/Checkers/UndefinedArraySubscriptChecker.cpp @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// // -// This defines UndefinedArraySubscriptChecker, a builtin check in GRExprEngine +// This defines UndefinedArraySubscriptChecker, a builtin check in ExprEngine // that performs checks for undefined array subscripts. // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -34,7 +34,7 @@ public: }; } // end anonymous namespace -void GR::RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng) { +void GR::RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng) { Eng.registerCheck(new UndefinedArraySubscriptChecker()); } diff --git a/clang/lib/GR/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/GR/Checkers/UndefinedAssignmentChecker.cpp index b1eb38704bc..fa43350da8f 100644 --- a/clang/lib/GR/Checkers/UndefinedAssignmentChecker.cpp +++ b/clang/lib/GR/Checkers/UndefinedAssignmentChecker.cpp @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// // -// This defines UndefinedAssginmentChecker, a builtin check in GRExprEngine that +// This defines UndefinedAssginmentChecker, a builtin check in ExprEngine that // checks for assigning undefined values. // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -31,7 +31,7 @@ public: }; } -void GR::RegisterUndefinedAssignmentChecker(GRExprEngine &Eng){ +void GR::RegisterUndefinedAssignmentChecker(ExprEngine &Eng){ Eng.registerCheck(new UndefinedAssignmentChecker()); } diff --git a/clang/lib/GR/Checkers/UnixAPIChecker.cpp b/clang/lib/GR/Checkers/UnixAPIChecker.cpp index f4c75f76ab6..c365e3042dd 100644 --- a/clang/lib/GR/Checkers/UnixAPIChecker.cpp +++ b/clang/lib/GR/Checkers/UnixAPIChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/Basic/TargetInfo.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" @@ -46,7 +46,7 @@ public: }; } //end anonymous namespace -void GR::RegisterUnixAPIChecker(GRExprEngine &Eng) { +void GR::RegisterUnixAPIChecker(ExprEngine &Eng) { Eng.registerCheck(new UnixAPIChecker()); } @@ -74,7 +74,7 @@ static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC, else { // FIXME: We need a more general way of getting the O_CREAT value. // We could possibly grovel through the preprocessor state, but - // that would require passing the Preprocessor object to the GRExprEngine. + // that would require passing the Preprocessor object to the ExprEngine. return; } } diff --git a/clang/lib/GR/Checkers/UnreachableCodeChecker.cpp b/clang/lib/GR/Checkers/UnreachableCodeChecker.cpp index 0ab97c27d9c..97a2ff56af1 100644 --- a/clang/lib/GR/Checkers/UnreachableCodeChecker.cpp +++ b/clang/lib/GR/Checkers/UnreachableCodeChecker.cpp @@ -21,7 +21,7 @@ #include "clang/GR/PathSensitive/SVals.h" #include "clang/GR/PathSensitive/CheckerHelpers.h" #include "clang/GR/BugReporter/BugReporter.h" -#include "GRExprEngineExperimentalChecks.h" +#include "ExprEngineExperimentalChecks.h" #include "llvm/ADT/SmallPtrSet.h" // The number of CFGBlock pointers we want to reserve memory for. This is used @@ -37,7 +37,7 @@ public: static void *getTag(); void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, - GRExprEngine &Eng); + ExprEngine &Eng); private: static inline const Stmt *getUnreachableStmt(const CFGBlock *CB); void FindUnreachableEntryPoints(const CFGBlock *CB); @@ -54,13 +54,13 @@ void *UnreachableCodeChecker::getTag() { return &x; } -void GR::RegisterUnreachableCodeChecker(GRExprEngine &Eng) { +void GR::RegisterUnreachableCodeChecker(ExprEngine &Eng) { Eng.registerCheck(new UnreachableCodeChecker()); } void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, - GRExprEngine &Eng) { + ExprEngine &Eng) { // Bail out if we didn't cover all paths if (Eng.hasWorkRemaining()) return; diff --git a/clang/lib/GR/Checkers/VLASizeChecker.cpp b/clang/lib/GR/Checkers/VLASizeChecker.cpp index d4e9d353398..b2ca2db02f2 100644 --- a/clang/lib/GR/Checkers/VLASizeChecker.cpp +++ b/clang/lib/GR/Checkers/VLASizeChecker.cpp @@ -7,18 +7,18 @@ // //===----------------------------------------------------------------------===// // -// This defines VLASizeChecker, a builtin check in GRExprEngine that +// This defines VLASizeChecker, a builtin check in ExprEngine that // performs checks for declaration of VLA of undefined or zero size. // In addition, VLASizeChecker is responsible for defining the extent // of the MemRegion that represents a VLA. // //===----------------------------------------------------------------------===// -#include "GRExprEngineInternalChecks.h" +#include "ExprEngineInternalChecks.h" #include "clang/AST/CharUnits.h" #include "clang/GR/BugReporter/BugType.h" #include "clang/GR/PathSensitive/CheckerVisitor.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" using namespace clang; using namespace GR; @@ -35,7 +35,7 @@ public: }; } // end anonymous namespace -void GR::RegisterVLASizeChecker(GRExprEngine &Eng) { +void GR::RegisterVLASizeChecker(ExprEngine &Eng) { Eng.registerCheck(new VLASizeChecker()); } diff --git a/clang/lib/GR/CoreEngine.cpp b/clang/lib/GR/CoreEngine.cpp new file mode 100644 index 00000000000..a086c912351 --- /dev/null +++ b/clang/lib/GR/CoreEngine.cpp @@ -0,0 +1,809 @@ +//==- CoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- 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 a generic engine for intraprocedural, path-sensitive, +// dataflow analysis via graph reachability engine. +// +//===----------------------------------------------------------------------===// + +#include "clang/GR/PathSensitive/AnalysisManager.h" +#include "clang/GR/PathSensitive/CoreEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" +#include "clang/Index/TranslationUnit.h" +#include "clang/AST/Expr.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/DenseMap.h" +#include +#include + +using llvm::cast; +using llvm::isa; +using namespace clang; +using namespace GR; + +// This should be removed in the future. +namespace clang { +namespace GR { +TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, + const LangOptions& lopts); +} +} + +//===----------------------------------------------------------------------===// +// Worklist classes for exploration of reachable states. +//===----------------------------------------------------------------------===// + +WorkList::Visitor::~Visitor() {} + +namespace { +class DFS : public WorkList { + llvm::SmallVector Stack; +public: + virtual bool hasWork() const { + return !Stack.empty(); + } + + virtual void Enqueue(const WorkListUnit& U) { + Stack.push_back(U); + } + + virtual WorkListUnit Dequeue() { + assert (!Stack.empty()); + const WorkListUnit& U = Stack.back(); + Stack.pop_back(); // This technically "invalidates" U, but we are fine. + return U; + } + + virtual bool VisitItemsInWorkList(Visitor &V) { + for (llvm::SmallVectorImpl::iterator + I = Stack.begin(), E = Stack.end(); I != E; ++I) { + if (V.Visit(*I)) + return true; + } + return false; + } +}; + +class BFS : public WorkList { + std::deque Queue; +public: + virtual bool hasWork() const { + return !Queue.empty(); + } + + virtual void Enqueue(const WorkListUnit& U) { + Queue.push_front(U); + } + + virtual WorkListUnit Dequeue() { + WorkListUnit U = Queue.front(); + Queue.pop_front(); + return U; + } + + virtual bool VisitItemsInWorkList(Visitor &V) { + for (std::deque::iterator + I = Queue.begin(), E = Queue.end(); I != E; ++I) { + if (V.Visit(*I)) + return true; + } + return false; + } +}; + +} // end anonymous namespace + +// Place the dstor for WorkList here because it contains virtual member +// functions, and we the code for the dstor generated in one compilation unit. +WorkList::~WorkList() {} + +WorkList *WorkList::MakeDFS() { return new DFS(); } +WorkList *WorkList::MakeBFS() { return new BFS(); } + +namespace { + class BFSBlockDFSContents : public WorkList { + std::deque Queue; + llvm::SmallVector Stack; + public: + virtual bool hasWork() const { + return !Queue.empty() || !Stack.empty(); + } + + virtual void Enqueue(const WorkListUnit& U) { + if (isa(U.getNode()->getLocation())) + Queue.push_front(U); + else + Stack.push_back(U); + } + + virtual WorkListUnit Dequeue() { + // Process all basic blocks to completion. + if (!Stack.empty()) { + const WorkListUnit& U = Stack.back(); + Stack.pop_back(); // This technically "invalidates" U, but we are fine. + return U; + } + + assert(!Queue.empty()); + // Don't use const reference. The subsequent pop_back() might make it + // unsafe. + WorkListUnit U = Queue.front(); + Queue.pop_front(); + return U; + } + virtual bool VisitItemsInWorkList(Visitor &V) { + for (llvm::SmallVectorImpl::iterator + I = Stack.begin(), E = Stack.end(); I != E; ++I) { + if (V.Visit(*I)) + return true; + } + for (std::deque::iterator + I = Queue.begin(), E = Queue.end(); I != E; ++I) { + if (V.Visit(*I)) + return true; + } + return false; + } + + }; +} // end anonymous namespace + +WorkList* WorkList::MakeBFSBlockDFSContents() { + return new BFSBlockDFSContents(); +} + +//===----------------------------------------------------------------------===// +// Core analysis engine. +//===----------------------------------------------------------------------===// + +/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. +bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, + const GRState *InitState) { + + if (G->num_roots() == 0) { // Initialize the analysis by constructing + // the root if none exists. + + const CFGBlock* Entry = &(L->getCFG()->getEntry()); + + assert (Entry->empty() && + "Entry block must be empty."); + + assert (Entry->succ_size() == 1 && + "Entry block must have 1 successor."); + + // Get the solitary successor. + const CFGBlock* Succ = *(Entry->succ_begin()); + + // Construct an edge representing the + // starting location in the function. + BlockEdge StartLoc(Entry, Succ, L); + + // Set the current block counter to being empty. + WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); + + if (!InitState) + // Generate the root. + generateNode(StartLoc, getInitialState(L), 0); + else + generateNode(StartLoc, InitState, 0); + } + + // Check if we have a steps limit + bool UnlimitedSteps = Steps == 0; + + while (WList->hasWork()) { + if (!UnlimitedSteps) { + if (Steps == 0) + break; + --Steps; + } + + const WorkListUnit& WU = WList->Dequeue(); + + // Set the current block counter. + WList->setBlockCounter(WU.getBlockCounter()); + + // Retrieve the node. + ExplodedNode* Node = WU.getNode(); + + // Dispatch on the location type. + switch (Node->getLocation().getKind()) { + case ProgramPoint::BlockEdgeKind: + HandleBlockEdge(cast(Node->getLocation()), Node); + break; + + case ProgramPoint::BlockEntranceKind: + HandleBlockEntrance(cast(Node->getLocation()), Node); + break; + + case ProgramPoint::BlockExitKind: + assert (false && "BlockExit location never occur in forward analysis."); + break; + + case ProgramPoint::CallEnterKind: + HandleCallEnter(cast(Node->getLocation()), WU.getBlock(), + WU.getIndex(), Node); + break; + + case ProgramPoint::CallExitKind: + HandleCallExit(cast(Node->getLocation()), Node); + break; + + default: + assert(isa(Node->getLocation()) || + isa(Node->getLocation())); + HandlePostStmt(WU.getBlock(), WU.getIndex(), Node); + break; + } + } + + SubEng.ProcessEndWorklist(hasWorkRemaining()); + return WList->hasWork(); +} + +void CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, + unsigned Steps, + const GRState *InitState, + ExplodedNodeSet &Dst) { + ExecuteWorkList(L, Steps, InitState); + for (llvm::SmallVectorImpl::iterator I = G->EndNodes.begin(), + E = G->EndNodes.end(); I != E; ++I) { + Dst.Add(*I); + } +} + +void CoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, + unsigned Index, ExplodedNode *Pred) { + CallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), + L.getCalleeContext(), Block, Index); + ProcessCallEnter(Builder); +} + +void CoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { + CallExitNodeBuilder Builder(*this, Pred); + ProcessCallExit(Builder); +} + +void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { + + const CFGBlock* Blk = L.getDst(); + + // Check if we are entering the EXIT block. + if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { + + assert (L.getLocationContext()->getCFG()->getExit().size() == 0 + && "EXIT block cannot contain Stmts."); + + // Process the final state transition. + EndPathNodeBuilder Builder(Blk, Pred, this); + ProcessEndPath(Builder); + + // This path is done. Don't enqueue any more nodes. + return; + } + + // FIXME: Should we allow ProcessBlockEntrance to also manipulate state? + + if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter())) + generateNode(BlockEntrance(Blk, Pred->getLocationContext()), + Pred->State, Pred); + else { + blocksAborted.push_back(std::make_pair(L, Pred)); + } +} + +void CoreEngine::HandleBlockEntrance(const BlockEntrance& L, + ExplodedNode* Pred) { + + // Increment the block counter. + BlockCounter Counter = WList->getBlockCounter(); + Counter = BCounterFactory.IncrementCount(Counter, + Pred->getLocationContext()->getCurrentStackFrame(), + L.getBlock()->getBlockID()); + WList->setBlockCounter(Counter); + + // Process the entrance of the block. + if (CFGElement E = L.getFirstElement()) { + StmtNodeBuilder Builder(L.getBlock(), 0, Pred, this, + SubEng.getStateManager()); + ProcessElement(E, Builder); + } + else + HandleBlockExit(L.getBlock(), Pred); +} + +void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) { + + if (const Stmt* Term = B->getTerminator()) { + switch (Term->getStmtClass()) { + default: + assert(false && "Analysis for this terminator not implemented."); + break; + + case Stmt::BinaryOperatorClass: // '&&' and '||' + HandleBranch(cast(Term)->getLHS(), Term, B, Pred); + return; + + case Stmt::ConditionalOperatorClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + // FIXME: Use constant-folding in CFG construction to simplify this + // case. + + case Stmt::ChooseExprClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + case Stmt::DoStmtClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + case Stmt::ForStmtClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + case Stmt::ContinueStmtClass: + case Stmt::BreakStmtClass: + case Stmt::GotoStmtClass: + break; + + case Stmt::IfStmtClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + case Stmt::IndirectGotoStmtClass: { + // Only 1 successor: the indirect goto dispatch block. + assert (B->succ_size() == 1); + + IndirectGotoNodeBuilder + builder(Pred, B, cast(Term)->getTarget(), + *(B->succ_begin()), this); + + ProcessIndirectGoto(builder); + return; + } + + case Stmt::ObjCForCollectionStmtClass: { + // In the case of ObjCForCollectionStmt, it appears twice in a CFG: + // + // (1) inside a basic block, which represents the binding of the + // 'element' variable to a value. + // (2) in a terminator, which represents the branch. + // + // For (1), subengines will bind a value (i.e., 0 or 1) indicating + // whether or not collection contains any more elements. We cannot + // just test to see if the element is nil because a container can + // contain nil elements. + HandleBranch(Term, Term, B, Pred); + return; + } + + case Stmt::SwitchStmtClass: { + SwitchNodeBuilder builder(Pred, B, cast(Term)->getCond(), + this); + + ProcessSwitch(builder); + return; + } + + case Stmt::WhileStmtClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + } + } + + assert (B->succ_size() == 1 && + "Blocks with no terminator should have at most 1 successor."); + + generateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()), + Pred->State, Pred); +} + +void CoreEngine::HandleBranch(const Stmt* Cond, const Stmt* Term, + const CFGBlock * B, ExplodedNode* Pred) { + assert (B->succ_size() == 2); + + BranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), + Pred, this); + + ProcessBranch(Cond, Term, Builder); +} + +void CoreEngine::HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, + ExplodedNode* Pred) { + assert (!B->empty()); + + if (StmtIdx == B->size()) + HandleBlockExit(B, Pred); + else { + StmtNodeBuilder Builder(B, StmtIdx, Pred, this, + SubEng.getStateManager()); + ProcessElement((*B)[StmtIdx], Builder); + } +} + +/// generateNode - Utility method to generate nodes, hook up successors, +/// and add nodes to the worklist. +void CoreEngine::generateNode(const ProgramPoint& Loc, + const GRState* State, ExplodedNode* Pred) { + + bool IsNew; + ExplodedNode* Node = G->getNode(Loc, State, &IsNew); + + if (Pred) + Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor. + else { + assert (IsNew); + G->addRoot(Node); // 'Node' has no predecessor. Make it a root. + } + + // Only add 'Node' to the worklist if it was freshly generated. + if (IsNew) WList->Enqueue(Node); +} + +StmtNodeBuilder::StmtNodeBuilder(const CFGBlock* b, unsigned idx, + ExplodedNode* N, CoreEngine* e, + GRStateManager &mgr) + : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr), + PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false), + PointKind(ProgramPoint::PostStmtKind), Tag(0) { + Deferred.insert(N); + CleanedState = Pred->getState(); +} + +StmtNodeBuilder::~StmtNodeBuilder() { + for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) + if (!(*I)->isSink()) + GenerateAutoTransition(*I); +} + +void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { + assert (!N->isSink()); + + // Check if this node entered a callee. + if (isa(N->getLocation())) { + // Still use the index of the CallExpr. It's needed to create the callee + // StackFrameContext. + Eng.WList->Enqueue(N, &B, Idx); + return; + } + + // Do not create extra nodes. Move to the next CFG element. + if (isa(N->getLocation())) { + Eng.WList->Enqueue(N, &B, Idx+1); + return; + } + + PostStmt Loc(getStmt(), N->getLocationContext()); + + if (Loc == N->getLocation()) { + // Note: 'N' should be a fresh node because otherwise it shouldn't be + // a member of Deferred. + Eng.WList->Enqueue(N, &B, Idx+1); + return; + } + + bool IsNew; + ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew); + Succ->addPredecessor(N, *Eng.G); + + if (IsNew) + Eng.WList->Enqueue(Succ, &B, Idx+1); +} + +ExplodedNode* StmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, + ExplodedNode* Pred, const GRState* St, + ProgramPoint::Kind K) { + + ExplodedNode* N = generateNode(S, St, Pred, K); + + if (N) { + if (BuildSinks) + N->markAsSink(); + else + Dst.Add(N); + } + + return N; +} + +static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K, + const LocationContext *LC, const void *tag){ + switch (K) { + default: + assert(false && "Unhandled ProgramPoint kind"); + case ProgramPoint::PreStmtKind: + return PreStmt(S, LC, tag); + case ProgramPoint::PostStmtKind: + return PostStmt(S, LC, tag); + case ProgramPoint::PreLoadKind: + return PreLoad(S, LC, tag); + case ProgramPoint::PostLoadKind: + return PostLoad(S, LC, tag); + case ProgramPoint::PreStoreKind: + return PreStore(S, LC, tag); + case ProgramPoint::PostStoreKind: + return PostStore(S, LC, tag); + case ProgramPoint::PostLValueKind: + return PostLValue(S, LC, tag); + case ProgramPoint::PostPurgeDeadSymbolsKind: + return PostPurgeDeadSymbols(S, LC, tag); + } +} + +ExplodedNode* +StmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state, + ExplodedNode* Pred, + ProgramPoint::Kind K, + const void *tag) { + + const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag); + return generateNodeInternal(L, state, Pred); +} + +ExplodedNode* +StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc, + const GRState* State, + ExplodedNode* Pred) { + bool IsNew; + ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew); + N->addPredecessor(Pred, *Eng.G); + Deferred.erase(Pred); + + if (IsNew) { + Deferred.insert(N); + return N; + } + + return NULL; +} + +ExplodedNode* BranchNodeBuilder::generateNode(const GRState* State, + bool branch) { + + // If the branch has been marked infeasible we should not generate a node. + if (!isFeasible(branch)) + return NULL; + + bool IsNew; + + ExplodedNode* Succ = + Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()), + State, &IsNew); + + Succ->addPredecessor(Pred, *Eng.G); + + if (branch) + GeneratedTrue = true; + else + GeneratedFalse = true; + + if (IsNew) { + Deferred.push_back(Succ); + return Succ; + } + + return NULL; +} + +BranchNodeBuilder::~BranchNodeBuilder() { + if (!GeneratedTrue) generateNode(Pred->State, true); + if (!GeneratedFalse) generateNode(Pred->State, false); + + for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) + if (!(*I)->isSink()) Eng.WList->Enqueue(*I); +} + + +ExplodedNode* +IndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St, + bool isSink) { + bool IsNew; + + ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), + Pred->getLocationContext()), St, &IsNew); + + Succ->addPredecessor(Pred, *Eng.G); + + if (IsNew) { + + if (isSink) + Succ->markAsSink(); + else + Eng.WList->Enqueue(Succ); + + return Succ; + } + + return NULL; +} + + +ExplodedNode* +SwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){ + + bool IsNew; + + ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), + Pred->getLocationContext()), St, &IsNew); + Succ->addPredecessor(Pred, *Eng.G); + + if (IsNew) { + Eng.WList->Enqueue(Succ); + return Succ; + } + + return NULL; +} + + +ExplodedNode* +SwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) { + + // Get the block for the default case. + assert (Src->succ_rbegin() != Src->succ_rend()); + CFGBlock* DefaultBlock = *Src->succ_rbegin(); + + bool IsNew; + + ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, + Pred->getLocationContext()), St, &IsNew); + Succ->addPredecessor(Pred, *Eng.G); + + if (IsNew) { + if (isSink) + Succ->markAsSink(); + else + Eng.WList->Enqueue(Succ); + + return Succ; + } + + return NULL; +} + +EndPathNodeBuilder::~EndPathNodeBuilder() { + // Auto-generate an EOP node if one has not been generated. + if (!HasGeneratedNode) { + // If we are in an inlined call, generate CallExit node. + if (Pred->getLocationContext()->getParent()) + GenerateCallExitNode(Pred->State); + else + generateNode(Pred->State); + } +} + +ExplodedNode* +EndPathNodeBuilder::generateNode(const GRState* State, const void *tag, + ExplodedNode* P) { + HasGeneratedNode = true; + bool IsNew; + + ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B, + Pred->getLocationContext(), tag), State, &IsNew); + + Node->addPredecessor(P ? P : Pred, *Eng.G); + + if (IsNew) { + Eng.G->addEndOfPath(Node); + return Node; + } + + return NULL; +} + +void EndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { + HasGeneratedNode = true; + // Create a CallExit node and enqueue it. + const StackFrameContext *LocCtx + = cast(Pred->getLocationContext()); + const Stmt *CE = LocCtx->getCallSite(); + + // Use the the callee location context. + CallExit Loc(CE, LocCtx); + + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(Pred, *Eng.G); + + if (isNew) + Eng.WList->Enqueue(Node); +} + + +void CallEnterNodeBuilder::generateNode(const GRState *state) { + // Check if the callee is in the same translation unit. + if (CalleeCtx->getTranslationUnit() != + Pred->getLocationContext()->getTranslationUnit()) { + // Create a new engine. We must be careful that the new engine should not + // reference data structures owned by the old engine. + + AnalysisManager &OldMgr = Eng.SubEng.getAnalysisManager(); + + // Get the callee's translation unit. + idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit(); + + // Create a new AnalysisManager with components of the callee's + // TranslationUnit. + // The Diagnostic is actually shared when we create ASTUnits from AST files. + AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), + OldMgr.getLangOptions(), + OldMgr.getPathDiagnosticClient(), + OldMgr.getStoreManagerCreator(), + OldMgr.getConstraintManagerCreator(), + OldMgr.getIndexer(), + OldMgr.getMaxNodes(), OldMgr.getMaxVisit(), + OldMgr.shouldVisualizeGraphviz(), + OldMgr.shouldVisualizeUbigraph(), + OldMgr.shouldPurgeDead(), + OldMgr.shouldEagerlyAssume(), + OldMgr.shouldTrimGraph(), + OldMgr.shouldInlineCall(), + OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(), + OldMgr.getAnalysisContextManager().getAddImplicitDtors(), + OldMgr.getAnalysisContextManager().getAddInitializers()); + llvm::OwningPtr TF(MakeCFRefCountTF(AMgr.getASTContext(), + /* GCEnabled */ false, + AMgr.getLangOptions())); + // Create the new engine. + ExprEngine NewEng(AMgr, TF.take()); + + // Create the new LocationContext. + AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(), + CalleeCtx->getTranslationUnit()); + const StackFrameContext *OldLocCtx = CalleeCtx; + const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx, + OldLocCtx->getParent(), + OldLocCtx->getCallSite(), + OldLocCtx->getCallSiteBlock(), + OldLocCtx->getIndex()); + + // Now create an initial state for the new engine. + const GRState *NewState = NewEng.getStateManager().MarshalState(state, + NewLocCtx); + ExplodedNodeSet ReturnNodes; + NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(), + NewState, ReturnNodes); + return; + } + + // Get the callee entry block. + const CFGBlock *Entry = &(CalleeCtx->getCFG()->getEntry()); + assert(Entry->empty()); + assert(Entry->succ_size() == 1); + + // Get the solitary successor. + const CFGBlock *SuccB = *(Entry->succ_begin()); + + // Construct an edge representing the starting location in the callee. + BlockEdge Loc(Entry, SuccB, CalleeCtx); + + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(const_cast(Pred), *Eng.G); + + if (isNew) + Eng.WList->Enqueue(Node); +} + +void CallExitNodeBuilder::generateNode(const GRState *state) { + // Get the callee's location context. + const StackFrameContext *LocCtx + = cast(Pred->getLocationContext()); + // When exiting an implicit automatic obj dtor call, the callsite is the Stmt + // that triggers the dtor. + PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(const_cast(Pred), *Eng.G); + if (isNew) + Eng.WList->Enqueue(Node, LocCtx->getCallSiteBlock(), + LocCtx->getIndex() + 1); +} diff --git a/clang/lib/GR/ExprEngine.cpp b/clang/lib/GR/ExprEngine.cpp new file mode 100644 index 00000000000..7cf9054f247 --- /dev/null +++ b/clang/lib/GR/ExprEngine.cpp @@ -0,0 +1,3513 @@ +//=-- ExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that +// is built on GREngine, but provides the boilerplate to execute transfer +// functions and build the ExplodedGraph at the expression level. +// +//===----------------------------------------------------------------------===// + +// FIXME: Restructure checker registration. +#include "Checkers/ExprEngineInternalChecks.h" + +#include "clang/GR/BugReporter/BugType.h" +#include "clang/GR/PathSensitive/AnalysisManager.h" +#include "clang/GR/PathSensitive/ExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngineBuilders.h" +#include "clang/GR/PathSensitive/Checker.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/ParentMap.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/ImmutableList.h" + +#ifndef NDEBUG +#include "llvm/Support/GraphWriter.h" +#endif + +using namespace clang; +using namespace GR; +using llvm::dyn_cast; +using llvm::dyn_cast_or_null; +using llvm::cast; +using llvm::APSInt; + +namespace { + // Trait class for recording returned expression in the state. + struct ReturnExpr { + static int TagInt; + typedef const Stmt *data_type; + }; + int ReturnExpr::TagInt; +} + +//===----------------------------------------------------------------------===// +// Utility functions. +//===----------------------------------------------------------------------===// + +static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { + IdentifierInfo* II = &Ctx.Idents.get(name); + return Ctx.Selectors.getSelector(0, &II); +} + +//===----------------------------------------------------------------------===// +// Checker worklist routines. +//===----------------------------------------------------------------------===// + +void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, CallbackKind Kind) { + + // Determine if we already have a cached 'CheckersOrdered' vector + // specifically tailored for the provided . This + // can reduce the number of checkers actually called. + CheckersOrdered *CO = &Checkers; + llvm::OwningPtr NewCO; + + // The cache key is made up of the and the callback kind (pre- or post-visit) + // and the statement kind. + CallbackTag K = GetCallbackTag(Kind, S->getStmtClass()); + + CheckersOrdered *& CO_Ref = COCache[K]; + + if (!CO_Ref) { + // If we have no previously cached CheckersOrdered vector for this + // statement kind, then create one. + NewCO.reset(new CheckersOrdered); + } + else { + // Use the already cached set. + CO = CO_Ref; + } + + if (CO->empty()) { + // If there are no checkers, return early without doing any + // more work. + Dst.insert(Src); + return; + } + + ExplodedNodeSet Tmp; + ExplodedNodeSet *PrevSet = &Src; + unsigned checkersEvaluated = 0; + + for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I) { + // If all nodes are sunk, bail out early. + if (PrevSet->empty()) + break; + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } + void *tag = I->first; + Checker *checker = I->second; + bool respondsToCallback = true; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) { + + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, + Kind == PreVisitStmtCallback, respondsToCallback); + + } + + PrevSet = CurrSet; + + if (NewCO.get()) { + ++checkersEvaluated; + if (respondsToCallback) + NewCO->push_back(*I); + } + } + + // If we built NewCO, check if we called all the checkers. This is important + // so that we know that we accurately determined the entire set of checkers + // that responds to this callback. Note that 'checkersEvaluated' might + // not be the same as Checkers.size() if one of the Checkers generates + // a sink node. + if (NewCO.get() && checkersEvaluated == Checkers.size()) + CO_Ref = NewCO.take(); + + // Don't autotransition. The CheckerContext objects should do this + // automatically. +} + +void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, + ExplodedNodeSet &Dst, + const GRState *state, + ExplodedNode *Pred) { + bool evaluated = false; + ExplodedNodeSet DstTmp; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + + if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state, + tag)) { + evaluated = true; + break; + } else + // The checker didn't evaluate the expr. Restore the Dst. + DstTmp.clear(); + } + + if (evaluated) + Dst.insert(DstTmp); + else + Dst.insert(Pred); +} + +// CheckerEvalCall returns true if one of the checkers processed the node. +// This may return void when all call evaluation logic goes to some checker +// in the future. +bool ExprEngine::CheckerEvalCall(const CallExpr *CE, + ExplodedNodeSet &Dst, + ExplodedNode *Pred) { + bool evaluated = false; + ExplodedNodeSet DstTmp; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + + if (checker->GR_evalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) { + evaluated = true; + break; + } else + // The checker didn't evaluate the expr. Restore the DstTmp set. + DstTmp.clear(); + } + + if (evaluated) + Dst.insert(DstTmp); + else + Dst.insert(Pred); + + return evaluated; +} + +// FIXME: This is largely copy-paste from CheckerVisit(). Need to +// unify. +void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, SVal location, + SVal val, bool isPrevisit) { + + if (Checkers.empty()) { + Dst.insert(Src); + return; + } + + ExplodedNodeSet Tmp; + ExplodedNodeSet *PrevSet = &Src; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } + + void *tag = I->first; + Checker *checker = I->second; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) + checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE, + *NI, tag, location, val, isPrevisit); + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } + + // Don't autotransition. The CheckerContext objects should do this + // automatically. +} +//===----------------------------------------------------------------------===// +// Engine construction and deletion. +//===----------------------------------------------------------------------===// + +static void RegisterInternalChecks(ExprEngine &Eng) { + // Register internal "built-in" BugTypes with the BugReporter. These BugTypes + // are different than what probably many checks will do since they don't + // create BugReports on-the-fly but instead wait until ExprEngine finishes + // analyzing a function. Generation of BugReport objects is done via a call + // to 'FlushReports' from BugReporter. + // The following checks do not need to have their associated BugTypes + // explicitly registered with the BugReporter. If they issue any BugReports, + // their associated BugType will get registered with the BugReporter + // automatically. Note that the check itself is owned by the ExprEngine + // object. + RegisterAdjustedReturnValueChecker(Eng); + // CallAndMessageChecker should be registered before AttrNonNullChecker, + // where we assume arguments are not undefined. + RegisterCallAndMessageChecker(Eng); + RegisterAttrNonNullChecker(Eng); + RegisterDereferenceChecker(Eng); + RegisterVLASizeChecker(Eng); + RegisterDivZeroChecker(Eng); + RegisterReturnUndefChecker(Eng); + RegisterUndefinedArraySubscriptChecker(Eng); + RegisterUndefinedAssignmentChecker(Eng); + RegisterUndefBranchChecker(Eng); + RegisterUndefCapturedBlockVarChecker(Eng); + RegisterUndefResultChecker(Eng); + RegisterStackAddrLeakChecker(Eng); + RegisterObjCAtSyncChecker(Eng); + + // This is not a checker yet. + RegisterNoReturnFunctionChecker(Eng); + RegisterBuiltinFunctionChecker(Eng); + RegisterOSAtomicChecker(Eng); + RegisterUnixAPIChecker(Eng); + RegisterMacOSXAPIChecker(Eng); +} + +ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf) + : AMgr(mgr), + Engine(*this), + G(Engine.getGraph()), + Builder(NULL), + StateMgr(getContext(), mgr.getStoreManagerCreator(), + mgr.getConstraintManagerCreator(), G.getAllocator(), + *this), + SymMgr(StateMgr.getSymbolManager()), + svalBuilder(StateMgr.getSValBuilder()), + EntryNode(NULL), currentStmt(NULL), + NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), + RaiseSel(GetNullarySelector("raise", getContext())), + BR(mgr, *this), TF(tf) { + // Register internal checks. + RegisterInternalChecks(*this); + + // FIXME: Eventually remove the TF object entirely. + TF->RegisterChecks(*this); + TF->RegisterPrinters(getStateManager().Printers); +} + +ExprEngine::~ExprEngine() { + BR.FlushReports(); + delete [] NSExceptionInstanceRaiseSelectors; + + // Delete the set of checkers. + for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) + delete I->second; + + for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end(); + I!=E;++I) + delete I->second; +} + +//===----------------------------------------------------------------------===// +// Utility methods. +//===----------------------------------------------------------------------===// + +const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) { + const GRState *state = StateMgr.getInitialState(InitLoc); + + // Preconditions. + + // FIXME: It would be nice if we had a more general mechanism to add + // such preconditions. Some day. + do { + const Decl *D = InitLoc->getDecl(); + if (const FunctionDecl *FD = dyn_cast(D)) { + // Precondition: the first argument of 'main' is an integer guaranteed + // to be > 0. + const IdentifierInfo *II = FD->getIdentifier(); + if (!II || !(II->getName() == "main" && FD->getNumParams() > 0)) + break; + + const ParmVarDecl *PD = FD->getParamDecl(0); + QualType T = PD->getType(); + if (!T->isIntegerType()) + break; + + const MemRegion *R = state->getRegion(PD, InitLoc); + if (!R) + break; + + SVal V = state->getSVal(loc::MemRegionVal(R)); + SVal Constraint_untested = evalBinOp(state, BO_GT, V, + svalBuilder.makeZeroVal(T), + getContext().IntTy); + + DefinedOrUnknownSVal *Constraint = + dyn_cast(&Constraint_untested); + + if (!Constraint) + break; + + if (const GRState *newState = state->assume(*Constraint, true)) + state = newState; + + break; + } + + if (const ObjCMethodDecl *MD = dyn_cast(D)) { + // Precondition: 'self' is always non-null upon entry to an Objective-C + // method. + const ImplicitParamDecl *SelfD = MD->getSelfDecl(); + const MemRegion *R = state->getRegion(SelfD, InitLoc); + SVal V = state->getSVal(loc::MemRegionVal(R)); + + if (const Loc *LV = dyn_cast(&V)) { + // Assume that the pointer value in 'self' is non-null. + state = state->assume(*LV, true); + assert(state && "'self' cannot be null"); + } + } + } while (0); + + return state; +} + +//===----------------------------------------------------------------------===// +// Top-level transfer function logic (Dispatcher). +//===----------------------------------------------------------------------===// + +/// evalAssume - Called by ConstraintManager. Used to call checker-specific +/// logic for handling assumptions on symbolic values. +const GRState *ExprEngine::ProcessAssume(const GRState *state, SVal cond, + bool assumption) { + // Determine if we already have a cached 'CheckersOrdered' vector + // specifically tailored for processing assumptions. This + // can reduce the number of checkers actually called. + CheckersOrdered *CO = &Checkers; + llvm::OwningPtr NewCO; + + CallbackTag K = GetCallbackTag(ProcessAssumeCallback); + CheckersOrdered *& CO_Ref = COCache[K]; + + if (!CO_Ref) { + // If we have no previously cached CheckersOrdered vector for this + // statement kind, then create one. + NewCO.reset(new CheckersOrdered); + } + else { + // Use the already cached set. + CO = CO_Ref; + } + + if (!CO->empty()) { + // Let the checkers have a crack at the assume before the transfer functions + // get their turn. + for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I!=E; ++I) { + + // If any checker declares the state infeasible (or if it starts that + // way), bail out. + if (!state) + return NULL; + + Checker *C = I->second; + bool respondsToCallback = true; + + state = C->evalAssume(state, cond, assumption, &respondsToCallback); + + // Check if we're building the cache of checkers that care about + // assumptions. + if (NewCO.get() && respondsToCallback) + NewCO->push_back(*I); + } + + // If we got through all the checkers, and we built a list of those that + // care about assumptions, save it. + if (NewCO.get()) + CO_Ref = NewCO.take(); + } + + // If the state is infeasible at this point, bail out. + if (!state) + return NULL; + + return TF->evalAssume(state, cond, assumption); +} + +bool ExprEngine::WantsRegionChangeUpdate(const GRState* state) { + CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); + CheckersOrdered *CO = COCache[K]; + + if (!CO) + CO = &Checkers; + + for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { + Checker *C = I->second; + if (C->WantsRegionChangeUpdate(state)) + return true; + } + + return false; +} + +const GRState * +ExprEngine::ProcessRegionChanges(const GRState *state, + const MemRegion * const *Begin, + const MemRegion * const *End) { + // FIXME: Most of this method is copy-pasted from ProcessAssume. + + // Determine if we already have a cached 'CheckersOrdered' vector + // specifically tailored for processing region changes. This + // can reduce the number of checkers actually called. + CheckersOrdered *CO = &Checkers; + llvm::OwningPtr NewCO; + + CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); + CheckersOrdered *& CO_Ref = COCache[K]; + + if (!CO_Ref) { + // If we have no previously cached CheckersOrdered vector for this + // callback, then create one. + NewCO.reset(new CheckersOrdered); + } + else { + // Use the already cached set. + CO = CO_Ref; + } + + // If there are no checkers, just return the state as is. + if (CO->empty()) + return state; + + for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { + // If any checker declares the state infeasible (or if it starts that way), + // bail out. + if (!state) + return NULL; + + Checker *C = I->second; + bool respondsToCallback = true; + + state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback); + + // See if we're building a cache of checkers that care about region changes. + if (NewCO.get() && respondsToCallback) + NewCO->push_back(*I); + } + + // If we got through all the checkers, and we built a list of those that + // care about region changes, save it. + if (NewCO.get()) + CO_Ref = NewCO.take(); + + return state; +} + +void ExprEngine::ProcessEndWorklist(bool hasWorkRemaining) { + for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + I->second->VisitEndAnalysis(G, BR, *this); + } +} + +void ExprEngine::ProcessElement(const CFGElement E, + StmtNodeBuilder& builder) { + switch (E.getKind()) { + case CFGElement::Statement: + ProcessStmt(E.getAs(), builder); + break; + case CFGElement::Initializer: + ProcessInitializer(E.getAs(), builder); + break; + case CFGElement::ImplicitDtor: + ProcessImplicitDtor(E.getAs(), builder); + break; + default: + // Suppress compiler warning. + llvm_unreachable("Unexpected CFGElement kind."); + } +} + +void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { + currentStmt = S.getStmt(); + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + currentStmt->getLocStart(), + "Error evaluating statement"); + + Builder = &builder; + EntryNode = builder.getBasePredecessor(); + + // Create the cleaned state. + const LocationContext *LC = EntryNode->getLocationContext(); + SymbolReaper SymReaper(LC, currentStmt, SymMgr); + + if (AMgr.shouldPurgeDead()) { + const GRState *St = EntryNode->getState(); + + for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + Checker *checker = I->second; + checker->MarkLiveSymbols(St, SymReaper); + } + + const StackFrameContext *SFC = LC->getCurrentStackFrame(); + CleanedState = StateMgr.RemoveDeadBindings(St, SFC, SymReaper); + } else { + CleanedState = EntryNode->getState(); + } + + // Process any special transfer function for dead symbols. + ExplodedNodeSet Tmp; + + if (!SymReaper.hasDeadSymbols()) + Tmp.Add(EntryNode); + else { + SaveAndRestore OldSink(Builder->BuildSinks); + SaveOr OldHasGen(Builder->HasGeneratedNode); + + SaveAndRestore OldPurgeDeadSymbols(Builder->PurgingDeadSymbols); + Builder->PurgingDeadSymbols = true; + + // FIXME: This should soon be removed. + ExplodedNodeSet Tmp2; + getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode, + CleanedState, SymReaper); + + if (Checkers.empty()) + Tmp.insert(Tmp2); + else { + ExplodedNodeSet Tmp3; + ExplodedNodeSet *SrcSet = &Tmp2; + for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + ExplodedNodeSet *DstSet = 0; + if (I+1 == E) + DstSet = &Tmp; + else { + DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2; + DstSet->clear(); + } + + void *tag = I->first; + Checker *checker = I->second; + for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); + NI != NE; ++NI) + checker->GR_evalDeadSymbols(*DstSet, *Builder, *this, currentStmt, + *NI, SymReaper, tag); + SrcSet = DstSet; + } + } + + if (!Builder->BuildSinks && !Builder->HasGeneratedNode) + Tmp.Add(EntryNode); + } + + bool HasAutoGenerated = false; + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + ExplodedNodeSet Dst; + + // Set the cleaned state. + Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I)); + + // Visit the statement. + Visit(currentStmt, *I, Dst); + + // Do we need to auto-generate a node? We only need to do this to generate + // a node with a "cleaned" state; CoreEngine will actually handle + // auto-transitions for other cases. + if (Dst.size() == 1 && *Dst.begin() == EntryNode + && !Builder->HasGeneratedNode && !HasAutoGenerated) { + HasAutoGenerated = true; + builder.generateNode(currentStmt, GetState(EntryNode), *I); + } + } + + // NULL out these variables to cleanup. + CleanedState = NULL; + EntryNode = NULL; + + currentStmt = 0; + + Builder = NULL; +} + +void ExprEngine::ProcessInitializer(const CFGInitializer Init, + StmtNodeBuilder &builder) { + // We don't set EntryNode and currentStmt. And we don't clean up state. + const CXXBaseOrMemberInitializer *BMI = Init.getInitializer(); + + ExplodedNode *Pred = builder.getBasePredecessor(); + const LocationContext *LC = Pred->getLocationContext(); + + if (BMI->isAnyMemberInitializer()) { + ExplodedNodeSet Dst; + + // Evaluate the initializer. + Visit(BMI->getInit(), Pred, Dst); + + for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){ + ExplodedNode *Pred = *I; + const GRState *state = Pred->getState(); + + const FieldDecl *FD = BMI->getAnyMember(); + const RecordDecl *RD = FD->getParent(); + const CXXThisRegion *ThisR = getCXXThisRegion(cast(RD), + cast(LC)); + + SVal ThisV = state->getSVal(ThisR); + SVal FieldLoc = state->getLValue(FD, ThisV); + SVal InitVal = state->getSVal(BMI->getInit()); + state = state->bindLoc(FieldLoc, InitVal); + + // Use a custom node building process. + PostInitializer PP(BMI, LC); + // Builder automatically add the generated node to the deferred set, + // which are processed in the builder's dtor. + builder.generateNode(PP, state, Pred); + } + } +} + +void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, + StmtNodeBuilder &builder) { + Builder = &builder; + + switch (D.getDtorKind()) { + case CFGElement::AutomaticObjectDtor: + ProcessAutomaticObjDtor(cast(D), builder); + break; + case CFGElement::BaseDtor: + ProcessBaseDtor(cast(D), builder); + break; + case CFGElement::MemberDtor: + ProcessMemberDtor(cast(D), builder); + break; + case CFGElement::TemporaryDtor: + ProcessTemporaryDtor(cast(D), builder); + break; + default: + llvm_unreachable("Unexpected dtor kind."); + } +} + +void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor, + StmtNodeBuilder &builder) { + ExplodedNode *pred = builder.getBasePredecessor(); + const GRState *state = pred->getState(); + const VarDecl *varDecl = dtor.getVarDecl(); + + QualType varType = varDecl->getType(); + + if (const ReferenceType *refType = varType->getAs()) + varType = refType->getPointeeType(); + + const CXXRecordDecl *recordDecl = varType->getAsCXXRecordDecl(); + assert(recordDecl && "get CXXRecordDecl fail"); + const CXXDestructorDecl *dtorDecl = recordDecl->getDestructor(); + + Loc dest = state->getLValue(varDecl, pred->getLocationContext()); + + ExplodedNodeSet dstSet; + VisitCXXDestructor(dtorDecl, cast(dest).getRegion(), + dtor.getTriggerStmt(), pred, dstSet); +} + +void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, + StmtNodeBuilder &builder) { +} + +void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, + StmtNodeBuilder &builder) { +} + +void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, + StmtNodeBuilder &builder) { +} + +void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + S->getLocStart(), + "Error evaluating statement"); + + // Expressions to ignore. + if (const Expr *Ex = dyn_cast(S)) + S = Ex->IgnoreParens(); + + // FIXME: add metadata to the CFG so that we can disable + // this check when we KNOW that there is no block-level subexpression. + // The motivation is that this check requires a hashtable lookup. + + if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) { + Dst.Add(Pred); + return; + } + + switch (S->getStmtClass()) { + // C++ stuff we don't support yet. + case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::ExprWithCleanupsClass: + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::CXXPseudoDestructorExprClass: + case Stmt::CXXTemporaryObjectExprClass: + case Stmt::CXXThrowExprClass: + case Stmt::CXXTryStmtClass: + case Stmt::CXXTypeidExprClass: + case Stmt::CXXUuidofExprClass: + case Stmt::CXXUnresolvedConstructExprClass: + case Stmt::CXXScalarValueInitExprClass: + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::UnaryTypeTraitExprClass: + case Stmt::BinaryTypeTraitExprClass: + case Stmt::UnresolvedLookupExprClass: + case Stmt::UnresolvedMemberExprClass: + case Stmt::CXXNoexceptExprClass: + { + SaveAndRestore OldSink(Builder->BuildSinks); + Builder->BuildSinks = true; + MakeNode(Dst, S, Pred, GetState(Pred)); + break; + } + + case Stmt::ParenExprClass: + llvm_unreachable("ParenExprs already handled."); + // Cases that should never be evaluated simply because they shouldn't + // appear in the CFG. + case Stmt::BreakStmtClass: + case Stmt::CaseStmtClass: + case Stmt::CompoundStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::DoStmtClass: + case Stmt::GotoStmtClass: + case Stmt::IndirectGotoStmtClass: + case Stmt::LabelStmtClass: + case Stmt::NoStmtClass: + case Stmt::NullStmtClass: + case Stmt::SwitchCaseClass: + case Stmt::OpaqueValueExprClass: + llvm_unreachable("Stmt should not be in analyzer evaluation loop"); + break; + + case Stmt::GNUNullExprClass: { + MakeNode(Dst, S, Pred, GetState(Pred)->BindExpr(S, svalBuilder.makeNull())); + break; + } + + case Stmt::ObjCAtSynchronizedStmtClass: + VisitObjCAtSynchronizedStmt(cast(S), Pred, Dst); + break; + + // Cases not handled yet; but will handle some day. + case Stmt::DesignatedInitExprClass: + case Stmt::ExtVectorElementExprClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::ImplicitValueInitExprClass: + case Stmt::ObjCAtCatchStmtClass: + case Stmt::ObjCAtFinallyStmtClass: + case Stmt::ObjCAtTryStmtClass: + case Stmt::ObjCEncodeExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ObjCPropertyRefExprClass: + case Stmt::ObjCProtocolExprClass: + case Stmt::ObjCSelectorExprClass: + case Stmt::ObjCStringLiteralClass: + case Stmt::ParenListExprClass: + case Stmt::PredefinedExprClass: + case Stmt::ShuffleVectorExprClass: + case Stmt::VAArgExprClass: + // Fall through. + + // Cases we intentionally don't evaluate, since they don't need + // to be explicitly evaluated. + case Stmt::AddrLabelExprClass: + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::CXXBoolLiteralExprClass: + case Stmt::FloatingLiteralClass: + Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. + break; + + case Stmt::ArraySubscriptExprClass: + VisitLvalArraySubscriptExpr(cast(S), Pred, Dst); + break; + + case Stmt::AsmStmtClass: + VisitAsmStmt(cast(S), Pred, Dst); + break; + + case Stmt::BlockDeclRefExprClass: { + const BlockDeclRefExpr *BE = cast(S); + VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst); + break; + } + + case Stmt::BlockExprClass: + VisitBlockExpr(cast(S), Pred, Dst); + break; + + case Stmt::BinaryOperatorClass: { + const BinaryOperator* B = cast(S); + if (B->isLogicalOp()) { + VisitLogicalExpr(B, Pred, Dst); + break; + } + else if (B->getOpcode() == BO_Comma) { + const GRState* state = GetState(Pred); + MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS()))); + break; + } + + if (AMgr.shouldEagerlyAssume() && + (B->isRelationalOp() || B->isEqualityOp())) { + ExplodedNodeSet Tmp; + VisitBinaryOperator(cast(S), Pred, Tmp); + evalEagerlyAssume(Dst, Tmp, cast(S)); + } + else + VisitBinaryOperator(cast(S), Pred, Dst); + + break; + } + + case Stmt::CallExprClass: { + const CallExpr* C = cast(S); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + break; + } + + case Stmt::CXXConstructExprClass: { + const CXXConstructExpr *C = cast(S); + // For block-level CXXConstructExpr, we don't have a destination region. + // Let VisitCXXConstructExpr() create one. + VisitCXXConstructExpr(C, 0, Pred, Dst); + break; + } + + case Stmt::CXXMemberCallExprClass: { + const CXXMemberCallExpr *MCE = cast(S); + VisitCXXMemberCallExpr(MCE, Pred, Dst); + break; + } + + case Stmt::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *C = cast(S); + VisitCXXOperatorCallExpr(C, Pred, Dst); + break; + } + + case Stmt::CXXNewExprClass: { + const CXXNewExpr *NE = cast(S); + VisitCXXNewExpr(NE, Pred, Dst); + break; + } + + case Stmt::CXXDeleteExprClass: { + const CXXDeleteExpr *CDE = cast(S); + VisitCXXDeleteExpr(CDE, Pred, Dst); + break; + } + // FIXME: ChooseExpr is really a constant. We need to fix + // the CFG do not model them as explicit control-flow. + + case Stmt::ChooseExprClass: { // __builtin_choose_expr + const ChooseExpr* C = cast(S); + VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); + break; + } + + case Stmt::CompoundAssignOperatorClass: + VisitBinaryOperator(cast(S), Pred, Dst); + break; + + case Stmt::CompoundLiteralExprClass: + VisitCompoundLiteralExpr(cast(S), Pred, Dst); + break; + + case Stmt::ConditionalOperatorClass: { // '?' operator + const ConditionalOperator* C = cast(S); + VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); + break; + } + + case Stmt::CXXThisExprClass: + VisitCXXThisExpr(cast(S), Pred, Dst); + break; + + case Stmt::DeclRefExprClass: { + const DeclRefExpr *DE = cast(S); + VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst); + break; + } + + case Stmt::DeclStmtClass: + VisitDeclStmt(cast(S), Pred, Dst); + break; + + case Stmt::ForStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast(S)->getConditionVariable(), S, Pred, Dst); + break; + + case Stmt::ImplicitCastExprClass: + case Stmt::CStyleCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXReinterpretCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXFunctionalCastExprClass: { + const CastExpr* C = cast(S); + VisitCast(C, C->getSubExpr(), Pred, Dst); + break; + } + + case Stmt::IfStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast(S)->getConditionVariable(), S, Pred, Dst); + break; + + case Stmt::InitListExprClass: + VisitInitListExpr(cast(S), Pred, Dst); + break; + + case Stmt::MemberExprClass: + VisitMemberExpr(cast(S), Pred, Dst); + break; + case Stmt::ObjCIvarRefExprClass: + VisitLvalObjCIvarRefExpr(cast(S), Pred, Dst); + break; + + case Stmt::ObjCForCollectionStmtClass: + VisitObjCForCollectionStmt(cast(S), Pred, Dst); + break; + + case Stmt::ObjCMessageExprClass: + VisitObjCMessageExpr(cast(S), Pred, Dst); + break; + + case Stmt::ObjCAtThrowStmtClass: { + // FIXME: This is not complete. We basically treat @throw as + // an abort. + SaveAndRestore OldSink(Builder->BuildSinks); + Builder->BuildSinks = true; + MakeNode(Dst, S, Pred, GetState(Pred)); + break; + } + + case Stmt::ReturnStmtClass: + VisitReturnStmt(cast(S), Pred, Dst); + break; + + case Stmt::OffsetOfExprClass: + VisitOffsetOfExpr(cast(S), Pred, Dst); + break; + + case Stmt::SizeOfAlignOfExprClass: + VisitSizeOfAlignOfExpr(cast(S), Pred, Dst); + break; + + case Stmt::StmtExprClass: { + const StmtExpr* SE = cast(S); + + if (SE->getSubStmt()->body_empty()) { + // Empty statement expression. + assert(SE->getType() == getContext().VoidTy + && "Empty statement expression must have void type."); + Dst.Add(Pred); + break; + } + + if (Expr* LastExpr = dyn_cast(*SE->getSubStmt()->body_rbegin())) { + const GRState* state = GetState(Pred); + MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr))); + } + else + Dst.Add(Pred); + + break; + } + + case Stmt::StringLiteralClass: { + const GRState* state = GetState(Pred); + SVal V = state->getLValue(cast(S)); + MakeNode(Dst, S, Pred, state->BindExpr(S, V)); + return; + } + + case Stmt::SwitchStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast(S)->getConditionVariable(), S, Pred, Dst); + break; + + case Stmt::UnaryOperatorClass: { + const UnaryOperator *U = cast(S); + if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) { + ExplodedNodeSet Tmp; + VisitUnaryOperator(U, Pred, Tmp); + evalEagerlyAssume(Dst, Tmp, U); + } + else + VisitUnaryOperator(U, Pred, Dst); + break; + } + + case Stmt::WhileStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast(S)->getConditionVariable(), S, Pred, Dst); + break; + } +} + +//===----------------------------------------------------------------------===// +// Block entrance. (Update counters). +//===----------------------------------------------------------------------===// + +bool ExprEngine::ProcessBlockEntrance(const CFGBlock* B, + const ExplodedNode *Pred, + BlockCounter BC) { + return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(), + B->getBlockID()) < AMgr.getMaxVisit(); +} + +//===----------------------------------------------------------------------===// +// Generic node creation. +//===----------------------------------------------------------------------===// + +ExplodedNode* ExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, + ExplodedNode* Pred, const GRState* St, + ProgramPoint::Kind K, const void *tag) { + assert (Builder && "StmtNodeBuilder not present."); + SaveAndRestore OldTag(Builder->Tag); + Builder->Tag = tag; + return Builder->MakeNode(Dst, S, Pred, St, K); +} + +//===----------------------------------------------------------------------===// +// Branch processing. +//===----------------------------------------------------------------------===// + +const GRState* ExprEngine::MarkBranch(const GRState* state, + const Stmt* Terminator, + bool branchTaken) { + + switch (Terminator->getStmtClass()) { + default: + return state; + + case Stmt::BinaryOperatorClass: { // '&&' and '||' + + const BinaryOperator* B = cast(Terminator); + BinaryOperator::Opcode Op = B->getOpcode(); + + assert (Op == BO_LAnd || Op == BO_LOr); + + // For &&, if we take the true branch, then the value of the whole + // expression is that of the RHS expression. + // + // For ||, if we take the false branch, then the value of the whole + // expression is that of the RHS expression. + + const Expr* Ex = (Op == BO_LAnd && branchTaken) || + (Op == BO_LOr && !branchTaken) + ? B->getRHS() : B->getLHS(); + + return state->BindExpr(B, UndefinedVal(Ex)); + } + + case Stmt::ConditionalOperatorClass: { // ?: + + const ConditionalOperator* C = cast(Terminator); + + // For ?, if branchTaken == true then the value is either the LHS or + // the condition itself. (GNU extension). + + const Expr* Ex; + + if (branchTaken) + Ex = C->getLHS() ? C->getLHS() : C->getCond(); + else + Ex = C->getRHS(); + + return state->BindExpr(C, UndefinedVal(Ex)); + } + + case Stmt::ChooseExprClass: { // ?: + + const ChooseExpr* C = cast(Terminator); + + const Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); + return state->BindExpr(C, UndefinedVal(Ex)); + } + } +} + +/// RecoverCastedSymbol - A helper function for ProcessBranch that is used +/// to try to recover some path-sensitivity for casts of symbolic +/// integers that promote their values (which are currently not tracked well). +/// This function returns the SVal bound to Condition->IgnoreCasts if all the +// cast(s) did was sign-extend the original value. +static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state, + const Stmt* Condition, ASTContext& Ctx) { + + const Expr *Ex = dyn_cast(Condition); + if (!Ex) + return UnknownVal(); + + uint64_t bits = 0; + bool bitsInit = false; + + while (const CastExpr *CE = dyn_cast(Ex)) { + QualType T = CE->getType(); + + if (!T->isIntegerType()) + return UnknownVal(); + + uint64_t newBits = Ctx.getTypeSize(T); + if (!bitsInit || newBits < bits) { + bitsInit = true; + bits = newBits; + } + + Ex = CE->getSubExpr(); + } + + // We reached a non-cast. Is it a symbolic value? + QualType T = Ex->getType(); + + if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits) + return UnknownVal(); + + return state->getSVal(Ex); +} + +void ExprEngine::ProcessBranch(const Stmt* Condition, const Stmt* Term, + BranchNodeBuilder& builder) { + + // Check for NULL conditions; e.g. "for(;;)" + if (!Condition) { + builder.markInfeasible(false); + return; + } + + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + Condition->getLocStart(), + "Error evaluating branch"); + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + checker->VisitBranchCondition(builder, *this, Condition, tag); + } + + // If the branch condition is undefined, return; + if (!builder.isFeasible(true) && !builder.isFeasible(false)) + return; + + const GRState* PrevState = builder.getState(); + SVal X = PrevState->getSVal(Condition); + + if (X.isUnknown()) { + // Give it a chance to recover from unknown. + if (const Expr *Ex = dyn_cast(Condition)) { + if (Ex->getType()->isIntegerType()) { + // Try to recover some path-sensitivity. Right now casts of symbolic + // integers that promote their values are currently not tracked well. + // If 'Condition' is such an expression, try and recover the + // underlying value and use that instead. + SVal recovered = RecoverCastedSymbol(getStateManager(), + builder.getState(), Condition, + getContext()); + + if (!recovered.isUnknown()) { + X = recovered; + } + } + } + // If the condition is still unknown, give up. + if (X.isUnknown()) { + builder.generateNode(MarkBranch(PrevState, Term, true), true); + builder.generateNode(MarkBranch(PrevState, Term, false), false); + return; + } + } + + DefinedSVal V = cast(X); + + // Process the true branch. + if (builder.isFeasible(true)) { + if (const GRState *state = PrevState->assume(V, true)) + builder.generateNode(MarkBranch(state, Term, true), true); + else + builder.markInfeasible(true); + } + + // Process the false branch. + if (builder.isFeasible(false)) { + if (const GRState *state = PrevState->assume(V, false)) + builder.generateNode(MarkBranch(state, Term, false), false); + else + builder.markInfeasible(false); + } +} + +/// ProcessIndirectGoto - Called by CoreEngine. Used to generate successor +/// nodes by processing the 'effects' of a computed goto jump. +void ExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) { + + const GRState *state = builder.getState(); + SVal V = state->getSVal(builder.getTarget()); + + // Three possibilities: + // + // (1) We know the computed label. + // (2) The label is NULL (or some other constant), or Undefined. + // (3) We have no clue about the label. Dispatch to all targets. + // + + typedef IndirectGotoNodeBuilder::iterator iterator; + + if (isa(V)) { + const LabelStmt* L = cast(V).getLabel(); + + for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) { + if (I.getLabel() == L) { + builder.generateNode(I, state); + return; + } + } + + assert (false && "No block with label."); + return; + } + + if (isa(V) || isa(V)) { + // Dispatch to the first target and mark it as a sink. + //ExplodedNode* N = builder.generateNode(builder.begin(), state, true); + // FIXME: add checker visit. + // UndefBranches.insert(N); + return; + } + + // This is really a catch-all. We don't support symbolics yet. + // FIXME: Implement dispatch for symbolic pointers. + + for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) + builder.generateNode(I, state); +} + + +void ExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L, + const Expr* R, + ExplodedNode* Pred, ExplodedNodeSet& Dst) { + + assert(Ex == currentStmt && + Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); + + const GRState* state = GetState(Pred); + SVal X = state->getSVal(Ex); + + assert (X.isUndef()); + + const Expr *SE = (Expr*) cast(X).getData(); + assert(SE); + X = state->getSVal(SE); + + // Make sure that we invalidate the previous binding. + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true)); +} + +/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path +/// nodes when the control reaches the end of a function. +void ExprEngine::ProcessEndPath(EndPathNodeBuilder& builder) { + getTF().evalEndPath(*this, builder); + StateMgr.EndPath(builder.getState()); + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ + void *tag = I->first; + Checker *checker = I->second; + checker->evalEndPath(builder, tag, *this); + } +} + +/// ProcessSwitch - Called by CoreEngine. Used to generate successor +/// nodes by processing the 'effects' of a switch statement. +void ExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { + typedef SwitchNodeBuilder::iterator iterator; + const GRState* state = builder.getState(); + const Expr* CondE = builder.getCondition(); + SVal CondV_untested = state->getSVal(CondE); + + if (CondV_untested.isUndef()) { + //ExplodedNode* N = builder.generateDefaultCaseNode(state, true); + // FIXME: add checker + //UndefBranches.insert(N); + + return; + } + DefinedOrUnknownSVal CondV = cast(CondV_untested); + + const GRState *DefaultSt = state; + + iterator I = builder.begin(), EI = builder.end(); + bool defaultIsFeasible = I == EI; + + for ( ; I != EI; ++I) { + const CaseStmt* Case = I.getCase(); + + // Evaluate the LHS of the case value. + Expr::EvalResult V1; + bool b = Case->getLHS()->Evaluate(V1, getContext()); + + // Sanity checks. These go away in Release builds. + assert(b && V1.Val.isInt() && !V1.HasSideEffects + && "Case condition must evaluate to an integer constant."); + b = b; // silence unused variable warning + assert(V1.Val.getInt().getBitWidth() == + getContext().getTypeSize(CondE->getType())); + + // Get the RHS of the case, if it exists. + Expr::EvalResult V2; + + if (const Expr* E = Case->getRHS()) { + b = E->Evaluate(V2, getContext()); + assert(b && V2.Val.isInt() && !V2.HasSideEffects + && "Case condition must evaluate to an integer constant."); + b = b; // silence unused variable warning + } + else + V2 = V1; + + // FIXME: Eventually we should replace the logic below with a range + // comparison, rather than concretize the values within the range. + // This should be easy once we have "ranges" for NonLVals. + + do { + nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt())); + DefinedOrUnknownSVal Res = svalBuilder.evalEQ(DefaultSt ? DefaultSt : state, + CondV, CaseVal); + + // Now "assume" that the case matches. + if (const GRState* stateNew = state->assume(Res, true)) { + builder.generateCaseStmtNode(I, stateNew); + + // If CondV evaluates to a constant, then we know that this + // is the *only* case that we can take, so stop evaluating the + // others. + if (isa(CondV)) + return; + } + + // Now "assume" that the case doesn't match. Add this state + // to the default state (if it is feasible). + if (DefaultSt) { + if (const GRState *stateNew = DefaultSt->assume(Res, false)) { + defaultIsFeasible = true; + DefaultSt = stateNew; + } + else { + defaultIsFeasible = false; + DefaultSt = NULL; + } + } + + // Concretize the next value in the range. + if (V1.Val.getInt() == V2.Val.getInt()) + break; + + ++V1.Val.getInt(); + assert (V1.Val.getInt() <= V2.Val.getInt()); + + } while (true); + } + + if (!defaultIsFeasible) + return; + + // If we have switch(enum value), the default branch is not + // feasible if all of the enum constants not covered by 'case:' statements + // are not feasible values for the switch condition. + // + // Note that this isn't as accurate as it could be. Even if there isn't + // a case for a particular enum value as long as that enum value isn't + // feasible then it shouldn't be considered for making 'default:' reachable. + const SwitchStmt *SS = builder.getSwitch(); + const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts(); + if (CondExpr->getType()->getAs()) { + if (SS->isAllEnumCasesCovered()) + return; + } + + builder.generateDefaultCaseNode(DefaultSt); +} + +void ExprEngine::ProcessCallEnter(CallEnterNodeBuilder &B) { + const GRState *state = B.getState()->EnterStackFrame(B.getCalleeContext()); + B.generateNode(state); +} + +void ExprEngine::ProcessCallExit(CallExitNodeBuilder &B) { + const GRState *state = B.getState(); + const ExplodedNode *Pred = B.getPredecessor(); + const StackFrameContext *calleeCtx = + cast(Pred->getLocationContext()); + const Stmt *CE = calleeCtx->getCallSite(); + + // If the callee returns an expression, bind its value to CallExpr. + const Stmt *ReturnedExpr = state->get(); + if (ReturnedExpr) { + SVal RetVal = state->getSVal(ReturnedExpr); + state = state->BindExpr(CE, RetVal); + // Clear the return expr GDM. + state = state->remove(); + } + + // Bind the constructed object value to CXXConstructExpr. + if (const CXXConstructExpr *CCE = dyn_cast(CE)) { + const CXXThisRegion *ThisR = + getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); + + SVal ThisV = state->getSVal(ThisR); + // Always bind the region to the CXXConstructExpr. + state = state->BindExpr(CCE, ThisV); + } + + B.generateNode(state); +} + +//===----------------------------------------------------------------------===// +// Transfer functions: logical operations ('&&', '||'). +//===----------------------------------------------------------------------===// + +void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + + assert(B->getOpcode() == BO_LAnd || + B->getOpcode() == BO_LOr); + + assert(B==currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); + + const GRState* state = GetState(Pred); + SVal X = state->getSVal(B); + assert(X.isUndef()); + + const Expr *Ex = (const Expr*) cast(X).getData(); + assert(Ex); + + if (Ex == B->getRHS()) { + X = state->getSVal(Ex); + + // Handle undefined values. + if (X.isUndef()) { + MakeNode(Dst, B, Pred, state->BindExpr(B, X)); + return; + } + + DefinedOrUnknownSVal XD = cast(X); + + // We took the RHS. Because the value of the '&&' or '||' expression must + // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0 + // or 1. Alternatively, we could take a lazy approach, and calculate this + // value later when necessary. We don't have the machinery in place for + // this right now, and since most logical expressions are used for branches, + // the payoff is not likely to be large. Instead, we do eager evaluation. + if (const GRState *newState = state->assume(XD, true)) + MakeNode(Dst, B, Pred, + newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType()))); + + if (const GRState *newState = state->assume(XD, false)) + MakeNode(Dst, B, Pred, + newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType()))); + } + else { + // We took the LHS expression. Depending on whether we are '&&' or + // '||' we know what the value of the expression is via properties of + // the short-circuiting. + X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U, + B->getType()); + MakeNode(Dst, B, Pred, state->BindExpr(B, X)); + } +} + +//===----------------------------------------------------------------------===// +// Transfer functions: Loads and stores. +//===----------------------------------------------------------------------===// + +void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + ExplodedNodeSet Tmp; + + CanQualType T = getContext().getCanonicalType(BE->getType()); + SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T, + Pred->getLocationContext()); + + MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V), + ProgramPoint::PostLValueKind); + + // Post-visit the BlockExpr. + CheckerVisit(BE, Dst, Tmp, PostVisitStmtCallback); +} + +void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + const GRState *state = GetState(Pred); + + if (const VarDecl* VD = dyn_cast(D)) { + assert(Ex->isLValue()); + SVal V = state->getLValue(VD, Pred->getLocationContext()); + + // For references, the 'lvalue' is the pointer address stored in the + // reference region. + if (VD->getType()->isReferenceType()) { + if (const MemRegion *R = V.getAsRegion()) + V = state->getSVal(R); + else + V = UnknownVal(); + } + + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), + ProgramPoint::PostLValueKind); + return; + } + if (const EnumConstantDecl* ED = dyn_cast(D)) { + assert(!Ex->isLValue()); + SVal V = svalBuilder.makeIntVal(ED->getInitVal()); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V)); + return; + } + if (const FunctionDecl* FD = dyn_cast(D)) { + SVal V = svalBuilder.getFunctionPointer(FD); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), + ProgramPoint::PostLValueKind); + return; + } + assert (false && + "ValueDecl support for this ValueDecl not implemented."); +} + +/// VisitArraySubscriptExpr - Transfer function for array accesses +void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A, + ExplodedNode* Pred, + ExplodedNodeSet& Dst){ + + const Expr* Base = A->getBase()->IgnoreParens(); + const Expr* Idx = A->getIdx()->IgnoreParens(); + + // Evaluate the base. + ExplodedNodeSet Tmp; + Visit(Base, Pred, Tmp); + + for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) { + ExplodedNodeSet Tmp2; + Visit(Idx, *I1, Tmp2); // Evaluate the index. + ExplodedNodeSet Tmp3; + CheckerVisit(A, Tmp3, Tmp2, PreVisitStmtCallback); + + for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) { + const GRState* state = GetState(*I2); + SVal V = state->getLValue(A->getType(), state->getSVal(Idx), + state->getSVal(Base)); + assert(A->isLValue()); + MakeNode(Dst, A, *I2, state->BindExpr(A, V), ProgramPoint::PostLValueKind); + } + } +} + +/// VisitMemberExpr - Transfer function for member expressions. +void ExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + + Expr *baseExpr = M->getBase()->IgnoreParens(); + ExplodedNodeSet dstBase; + Visit(baseExpr, Pred, dstBase); + + FieldDecl *field = dyn_cast(M->getMemberDecl()); + if (!field) // FIXME: skipping member expressions for non-fields + return; + + for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end(); + I != E; ++I) { + const GRState* state = GetState(*I); + SVal baseExprVal = state->getSVal(baseExpr); + if (isa(baseExprVal) || + isa(baseExprVal)) { + MakeNode(Dst, M, *I, state->BindExpr(M, UnknownVal())); + continue; + } + + // FIXME: Should we insert some assumption logic in here to determine + // if "Base" is a valid piece of memory? Before we put this assumption + // later when using FieldOffset lvals (which we no longer have). + + // For all other cases, compute an lvalue. + SVal L = state->getLValue(field, baseExprVal); + if (M->isLValue()) + MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind); + else + evalLoad(Dst, M, *I, state, L); + } +} + +/// evalBind - Handle the semantics of binding a value to a specific location. +/// This method is used by evalStore and (soon) VisitDeclStmt, and others. +void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, + ExplodedNode* Pred, const GRState* state, + SVal location, SVal Val, bool atDeclInit) { + + + // Do a previsit of the bind. + ExplodedNodeSet CheckedSet, Src; + Src.Add(Pred); + CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true); + + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I!=E; ++I) { + + if (Pred != *I) + state = GetState(*I); + + const GRState* newState = 0; + + if (atDeclInit) { + const VarRegion *VR = + cast(cast(location).getRegion()); + + newState = state->bindDecl(VR, Val); + } + else { + if (location.isUnknown()) { + // We know that the new state will be the same as the old state since + // the location of the binding is "unknown". Consequently, there + // is no reason to just create a new node. + newState = state; + } + else { + // We are binding to a value other than 'unknown'. Perform the binding + // using the StoreManager. + newState = state->bindLoc(cast(location), Val); + } + } + + // The next thing to do is check if the TransferFuncs 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. + + // NOTE: We use 'AssignE' for the location of the PostStore if 'AssignE' + // is non-NULL. Checkers typically care about + + StmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE, + true); + + getTF().evalBind(BuilderRef, location, Val); + } +} + +/// evalStore - Handle the semantics of a store via an assignment. +/// @param Dst The node set to store generated state nodes +/// @param AssignE The assignment expression if the store happens in an +/// assignment. +/// @param LocatioinE The location expression that is stored to. +/// @param state The current simulation state +/// @param location The location to store the value +/// @param Val The value to be stored +void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE, + const Expr* LocationE, + ExplodedNode* Pred, + const GRState* state, SVal location, SVal Val, + const void *tag) { + + assert(Builder && "StmtNodeBuilder must be defined."); + + // Evaluate the location (checks for bad dereferences). + ExplodedNodeSet Tmp; + evalLocation(Tmp, LocationE, Pred, state, location, tag, false); + + if (Tmp.empty()) + return; + + assert(!location.isUndef()); + + SaveAndRestore OldSPointKind(Builder->PointKind, + ProgramPoint::PostStoreKind); + SaveAndRestore OldTag(Builder->Tag, tag); + + // Proceed with the store. We use AssignE as the anchor for the PostStore + // ProgramPoint if it is non-NULL, and LocationE otherwise. + const Expr *StoreE = AssignE ? AssignE : LocationE; + + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) + evalBind(Dst, StoreE, *NI, GetState(*NI), location, Val); +} + +void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex, + ExplodedNode* Pred, + const GRState* state, SVal location, + const void *tag, QualType LoadTy) { + assert(!isa(location) && "location cannot be a NonLoc."); + + // Are we loading from a region? This actually results in two loads; one + // to fetch the address of the referenced value and one to fetch the + // referenced value. + if (const TypedRegion *TR = + dyn_cast_or_null(location.getAsRegion())) { + + QualType ValTy = TR->getValueType(); + if (const ReferenceType *RT = ValTy->getAs()) { + static int loadReferenceTag = 0; + ExplodedNodeSet Tmp; + evalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag, + getContext().getPointerType(RT->getPointeeType())); + + // Perform the load from the referenced value. + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) { + state = GetState(*I); + location = state->getSVal(Ex); + evalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy); + } + return; + } + } + + evalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy); +} + +void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex, + ExplodedNode* Pred, + const GRState* state, SVal location, + const void *tag, QualType LoadTy) { + + // Evaluate the location (checks for bad dereferences). + ExplodedNodeSet Tmp; + evalLocation(Tmp, Ex, Pred, state, location, tag, true); + + if (Tmp.empty()) + return; + + assert(!location.isUndef()); + + SaveAndRestore OldSPointKind(Builder->PointKind); + SaveAndRestore OldTag(Builder->Tag); + + // Proceed with the load. + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { + state = GetState(*NI); + + if (location.isUnknown()) { + // This is important. We must nuke the old binding. + MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()), + ProgramPoint::PostLoadKind, tag); + } + else { + if (LoadTy.isNull()) + LoadTy = Ex->getType(); + SVal V = state->getSVal(cast(location), LoadTy); + MakeNode(Dst, Ex, *NI, state->bindExprAndLocation(Ex, location, V), + ProgramPoint::PostLoadKind, tag); + } + } +} + +void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, + ExplodedNode* Pred, + const GRState* state, SVal location, + const void *tag, bool isLoad) { + // Early checks for performance reason. + if (location.isUnknown() || Checkers.empty()) { + Dst.Add(Pred); + return; + } + + ExplodedNodeSet Src, Tmp; + Src.Add(Pred); + ExplodedNodeSet *PrevSet = &Src; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } + + void *tag = I->first; + Checker *checker = I->second; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) { + // Use the 'state' argument only when the predecessor node is the + // same as Pred. This allows us to catch updates to the state. + checker->GR_visitLocation(*CurrSet, *Builder, *this, S, *NI, + *NI == Pred ? state : GetState(*NI), + location, tag, isLoad); + } + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } +} + +bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, + ExplodedNode *Pred) { + const GRState *state = GetState(Pred); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + const FunctionDecl *FD = L.getAsFunctionDecl(); + if (!FD) + return false; + + // Check if the function definition is in the same translation unit. + if (FD->hasBody(FD)) { + const StackFrameContext *stackFrame = + AMgr.getStackFrame(AMgr.getAnalysisContext(FD), + Pred->getLocationContext(), + CE, Builder->getBlock(), Builder->getIndex()); + // Now we have the definition of the callee, create a CallEnter node. + CallEnter Loc(CE, stackFrame, Pred->getLocationContext()); + + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + Dst.Add(N); + return true; + } + + // Check if we can find the function definition in other translation units. + if (AMgr.hasIndexer()) { + AnalysisContext *C = AMgr.getAnalysisContextInAnotherTU(FD); + if (C == 0) + return false; + const StackFrameContext *stackFrame = + AMgr.getStackFrame(C, Pred->getLocationContext(), + CE, Builder->getBlock(), Builder->getIndex()); + CallEnter Loc(CE, stackFrame, Pred->getLocationContext()); + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + Dst.Add(N); + return true; + } + + return false; +} + +void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred, + CallExpr::const_arg_iterator AI, + CallExpr::const_arg_iterator AE, + ExplodedNodeSet& Dst) { + + // Determine the type of function we're calling (if available). + const FunctionProtoType *Proto = NULL; + QualType FnType = CE->getCallee()->IgnoreParens()->getType(); + if (const PointerType *FnTypePtr = FnType->getAs()) + Proto = FnTypePtr->getPointeeType()->getAs(); + + // Evaluate the arguments. + ExplodedNodeSet ArgsEvaluated; + evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated); + + // Now process the call itself. + ExplodedNodeSet DstTmp; + const Expr* Callee = CE->getCallee()->IgnoreParens(); + + for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(), + NE=ArgsEvaluated.end(); NI != NE; ++NI) { + // Evaluate the callee. + ExplodedNodeSet DstTmp2; + Visit(Callee, *NI, DstTmp2); + // Perform the previsit of the CallExpr, storing the results in DstTmp. + CheckerVisit(CE, DstTmp, DstTmp2, PreVisitStmtCallback); + } + + // Finally, evaluate the function call. We try each of the checkers + // to see if the can evaluate the function call. + ExplodedNodeSet DstTmp3; + + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); + DI != DE; ++DI) { + + const GRState* state = GetState(*DI); + SVal L = state->getSVal(Callee); + + // FIXME: Add support for symbolic function calls (calls involving + // function pointer values that are symbolic). + SaveAndRestore OldSink(Builder->BuildSinks); + ExplodedNodeSet DstChecker; + + // If the callee is processed by a checker, skip the rest logic. + if (CheckerEvalCall(CE, DstChecker, *DI)) + DstTmp3.insert(DstChecker); + else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) { + // Callee is inlined. We shouldn't do post call checking. + return; + } + else { + for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), + DE_Checker = DstChecker.end(); + DI_Checker != DE_Checker; ++DI_Checker) { + + // Dispatch to the plug-in transfer function. + unsigned oldSize = DstTmp3.size(); + SaveOr OldHasGen(Builder->HasGeneratedNode); + Pred = *DI_Checker; + + // Dispatch to transfer function logic to handle the call itself. + // FIXME: Allow us to chain together transfer functions. + assert(Builder && "StmtNodeBuilder must be defined."); + getTF().evalCall(DstTmp3, *this, *Builder, CE, L, Pred); + + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!Builder->BuildSinks && DstTmp3.size() == oldSize && + !Builder->HasGeneratedNode) + MakeNode(DstTmp3, CE, Pred, state); + } + } + } + + // Finally, perform the post-condition check of the CallExpr and store + // the created nodes in 'Dst'. + CheckerVisit(CE, Dst, DstTmp3, PostVisitStmtCallback); +} + +//===----------------------------------------------------------------------===// +// Transfer function: Objective-C ivar references. +//===----------------------------------------------------------------------===// + +static std::pair EagerlyAssumeTag + = std::pair(&EagerlyAssumeTag,static_cast(0)); + +void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + const Expr *Ex) { + for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { + ExplodedNode *Pred = *I; + + // Test if the previous node was as the same expression. This can happen + // when the expression fails to evaluate to anything meaningful and + // (as an optimization) we don't generate a node. + ProgramPoint P = Pred->getLocation(); + if (!isa(P) || cast(P).getStmt() != Ex) { + Dst.Add(Pred); + continue; + } + + const GRState* state = GetState(Pred); + SVal V = state->getSVal(Ex); + if (nonloc::SymExprVal *SEV = dyn_cast(&V)) { + // First assume that the condition is true. + if (const GRState *stateTrue = state->assume(*SEV, true)) { + stateTrue = stateTrue->BindExpr(Ex, + svalBuilder.makeIntVal(1U, Ex->getType())); + Dst.Add(Builder->generateNode(PostStmtCustom(Ex, + &EagerlyAssumeTag, Pred->getLocationContext()), + stateTrue, Pred)); + } + + // Next, assume that the condition is false. + if (const GRState *stateFalse = state->assume(*SEV, false)) { + stateFalse = stateFalse->BindExpr(Ex, + svalBuilder.makeIntVal(0U, Ex->getType())); + Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag, + Pred->getLocationContext()), + stateFalse, Pred)); + } + } + else + Dst.Add(Pred); + } +} + +//===----------------------------------------------------------------------===// +// Transfer function: Objective-C @synchronized. +//===----------------------------------------------------------------------===// + +void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + // The mutex expression is a CFGElement, so we don't need to explicitly + // visit it since it will already be processed. + + // Pre-visit the ObjCAtSynchronizedStmt. + ExplodedNodeSet Tmp; + Tmp.Add(Pred); + CheckerVisit(S, Dst, Tmp, PreVisitStmtCallback); +} + +//===----------------------------------------------------------------------===// +// Transfer function: Objective-C ivar references. +//===----------------------------------------------------------------------===// + +void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex, + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + + // Visit the base expression, which is needed for computing the lvalue + // of the ivar. + ExplodedNodeSet dstBase; + const Expr *baseExpr = Ex->getBase(); + Visit(baseExpr, Pred, dstBase); + + // Using the base, compute the lvalue of the instance variable. + for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end(); + I!=E; ++I) { + ExplodedNode *nodeBase = *I; + const GRState *state = GetState(nodeBase); + SVal baseVal = state->getSVal(baseExpr); + SVal location = state->getLValue(Ex->getDecl(), baseVal); + MakeNode(Dst, Ex, *I, state->BindExpr(Ex, location)); + } +} + +//===----------------------------------------------------------------------===// +// Transfer function: Objective-C fast enumeration 'for' statements. +//===----------------------------------------------------------------------===// + +void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S, + ExplodedNode* Pred, ExplodedNodeSet& Dst) { + + // ObjCForCollectionStmts are processed in two places. This method + // handles the case where an ObjCForCollectionStmt* occurs as one of the + // statements within a basic block. This transfer function does two things: + // + // (1) binds the next container value to 'element'. This creates a new + // node in the ExplodedGraph. + // + // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating + // whether or not the container has any more elements. This value + // will be tested in ProcessBranch. We need to explicitly bind + // this value because a container can contain nil elements. + // + // FIXME: Eventually this logic should actually do dispatches to + // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration). + // This will require simulating a temporary NSFastEnumerationState, either + // through an SVal or through the use of MemRegions. This value can + // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop + // terminates we reclaim the temporary (it goes out of scope) and we + // we can test if the SVal is 0 or if the MemRegion is null (depending + // on what approach we take). + // + // For now: simulate (1) by assigning either a symbol or nil if the + // container is empty. Thus this transfer function will by default + // result in state splitting. + + const Stmt* elem = S->getElement(); + SVal ElementV; + + if (const DeclStmt* DS = dyn_cast(elem)) { + const VarDecl* ElemD = cast(DS->getSingleDecl()); + assert (ElemD->getInit() == 0); + ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext()); + VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV); + return; + } + + ExplodedNodeSet Tmp; + Visit(cast(elem), Pred, Tmp); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { + const GRState* state = GetState(*I); + VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem)); + } +} + +void ExprEngine::VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S, + ExplodedNode* Pred, ExplodedNodeSet& Dst, + SVal ElementV) { + + // Check if the location we are writing back to is a null pointer. + const Stmt* elem = S->getElement(); + ExplodedNodeSet Tmp; + evalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false); + + if (Tmp.empty()) + return; + + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { + Pred = *NI; + const GRState *state = GetState(Pred); + + // Handle the case where the container still has elements. + SVal TrueV = svalBuilder.makeTruthVal(1); + const GRState *hasElems = state->BindExpr(S, TrueV); + + // Handle the case where the container has no elements. + SVal FalseV = svalBuilder.makeTruthVal(0); + const GRState *noElems = state->BindExpr(S, FalseV); + + if (loc::MemRegionVal* MV = dyn_cast(&ElementV)) + if (const TypedRegion* R = dyn_cast(MV->getRegion())) { + // FIXME: The proper thing to do is to really iterate over the + // container. We will do this with dispatch logic to the store. + // For now, just 'conjure' up a symbolic value. + QualType T = R->getValueType(); + assert(Loc::IsLocType(T)); + unsigned Count = Builder->getCurrentBlockCount(); + SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count); + SVal V = svalBuilder.makeLoc(Sym); + hasElems = hasElems->bindLoc(ElementV, V); + + // Bind the location to 'nil' on the false branch. + SVal nilV = svalBuilder.makeIntVal(0, T); + noElems = noElems->bindLoc(ElementV, nilV); + } + + // Create the new nodes. + MakeNode(Dst, S, Pred, hasElems); + MakeNode(Dst, S, Pred, noElems); + } +} + +//===----------------------------------------------------------------------===// +// Transfer function: Objective-C message expressions. +//===----------------------------------------------------------------------===// + +namespace { +class ObjCMsgWLItem { +public: + ObjCMessageExpr::const_arg_iterator I; + ExplodedNode *N; + + ObjCMsgWLItem(const ObjCMessageExpr::const_arg_iterator &i, ExplodedNode *n) + : I(i), N(n) {} +}; +} // end anonymous namespace + +void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, + ExplodedNode* Pred, + ExplodedNodeSet& Dst){ + + // Create a worklist to process both the arguments. + llvm::SmallVector WL; + + // But first evaluate the receiver (if any). + ObjCMessageExpr::const_arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); + if (const Expr *Receiver = ME->getInstanceReceiver()) { + ExplodedNodeSet Tmp; + Visit(Receiver, Pred, Tmp); + + if (Tmp.empty()) + return; + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) + WL.push_back(ObjCMsgWLItem(AI, *I)); + } + else + WL.push_back(ObjCMsgWLItem(AI, Pred)); + + // Evaluate the arguments. + ExplodedNodeSet ArgsEvaluated; + while (!WL.empty()) { + ObjCMsgWLItem Item = WL.back(); + WL.pop_back(); + + if (Item.I == AE) { + ArgsEvaluated.insert(Item.N); + continue; + } + + // Evaluate the subexpression. + ExplodedNodeSet Tmp; + + // FIXME: [Objective-C++] handle arguments that are references + Visit(*Item.I, Item.N, Tmp); + + // Enqueue evaluating the next argument on the worklist. + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) + WL.push_back(ObjCMsgWLItem(Item.I, *NI)); + } + + // Now that the arguments are processed, handle the previsits checks. + ExplodedNodeSet DstPrevisit; + CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback); + + // Proceed with evaluate the message expression. + ExplodedNodeSet dstEval; + + for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(), + DE = DstPrevisit.end(); DI != DE; ++DI) { + + Pred = *DI; + bool RaisesException = false; + unsigned oldSize = dstEval.size(); + SaveAndRestore OldSink(Builder->BuildSinks); + SaveOr OldHasGen(Builder->HasGeneratedNode); + + if (const Expr *Receiver = ME->getInstanceReceiver()) { + const GRState *state = GetState(Pred); + + // Bifurcate the state into nil and non-nil ones. + DefinedOrUnknownSVal receiverVal = + cast(state->getSVal(Receiver)); + + const GRState *notNilState, *nilState; + llvm::tie(notNilState, nilState) = state->assume(receiverVal); + + // There are three cases: can be nil or non-nil, must be nil, must be + // non-nil. We handle must be nil, and merge the rest two into non-nil. + if (nilState && !notNilState) { + CheckerEvalNilReceiver(ME, dstEval, nilState, Pred); + continue; + } + + // Check if the "raise" message was sent. + assert(notNilState); + if (ME->getSelector() == RaiseSel) + RaisesException = true; + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + evalObjCMessageExpr(dstEval, ME, Pred, notNilState); + } + else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) { + IdentifierInfo* ClsName = Iface->getIdentifier(); + Selector S = ME->getSelector(); + + // Check for special instance methods. + if (!NSExceptionII) { + ASTContext& Ctx = getContext(); + NSExceptionII = &Ctx.Idents.get("NSException"); + } + + if (ClsName == NSExceptionII) { + enum { NUM_RAISE_SELECTORS = 2 }; + + // Lazily create a cache of the selectors. + if (!NSExceptionInstanceRaiseSelectors) { + ASTContext& Ctx = getContext(); + NSExceptionInstanceRaiseSelectors = + new Selector[NUM_RAISE_SELECTORS]; + llvm::SmallVector II; + unsigned idx = 0; + + // raise:format: + II.push_back(&Ctx.Idents.get("raise")); + II.push_back(&Ctx.Idents.get("format")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); + + // raise:format::arguments: + II.push_back(&Ctx.Idents.get("arguments")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); + } + + for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) + if (S == NSExceptionInstanceRaiseSelectors[i]) { + RaisesException = true; + break; + } + } + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred)); + } + + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!Builder->BuildSinks && dstEval.size() == oldSize && + !Builder->HasGeneratedNode) + MakeNode(dstEval, ME, Pred, GetState(Pred)); + } + + // Finally, perform the post-condition check of the ObjCMessageExpr and store + // the created nodes in 'Dst'. + CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback); +} + +//===----------------------------------------------------------------------===// +// Transfer functions: Miscellaneous statements. +//===----------------------------------------------------------------------===// + +void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, + ExplodedNode *Pred, ExplodedNodeSet &Dst) { + + ExplodedNodeSet S1; + Visit(Ex, Pred, S1); + ExplodedNodeSet S2; + CheckerVisit(CastE, S2, S1, PreVisitStmtCallback); + + if (CastE->getCastKind() == CK_LValueToRValue) { + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I!=E; ++I) { + ExplodedNode *subExprNode = *I; + const GRState *state = GetState(subExprNode); + evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex)); + } + return; + } + + // All other casts. + QualType T = CastE->getType(); + QualType ExTy = Ex->getType(); + + if (const ExplicitCastExpr *ExCast=dyn_cast_or_null(CastE)) + T = ExCast->getTypeAsWritten(); + +#if 0 + // If we are evaluating the cast in an lvalue context, we implicitly want + // the cast to evaluate to a location. + if (asLValue) { + ASTContext &Ctx = getContext(); + T = Ctx.getPointerType(Ctx.getCanonicalType(T)); + ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy)); + } +#endif + + switch (CastE->getCastKind()) { + case CK_ToVoid: + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) + Dst.Add(*I); + return; + + case CK_LValueToRValue: + case CK_NoOp: + case CK_FunctionToPointerDecay: + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + // Copy the SVal of Ex to CastE. + ExplodedNode *N = *I; + const GRState *state = GetState(N); + SVal V = state->getSVal(Ex); + state = state->BindExpr(CastE, V); + MakeNode(Dst, CastE, N, state); + } + return; + + case CK_GetObjCProperty: + case CK_Dependent: + case CK_ArrayToPointerDecay: + case CK_BitCast: + case CK_LValueBitCast: + case CK_IntegralCast: + case CK_NullToPointer: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_PointerToBoolean: + case CK_IntegralToBoolean: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingToBoolean: + case CK_FloatingCast: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexToReal: + case CK_IntegralComplexToBoolean: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + + case CK_ObjCObjectLValueCast: { + // Delegate to SValBuilder to process. + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + ExplodedNode* N = *I; + const GRState* state = GetState(N); + SVal V = state->getSVal(Ex); + V = svalBuilder.evalCast(V, T, ExTy); + state = state->BindExpr(CastE, V); + MakeNode(Dst, CastE, N, state); + } + return; + } + + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + // For DerivedToBase cast, delegate to the store manager. + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + ExplodedNode *node = *I; + const GRState *state = GetState(node); + SVal val = state->getSVal(Ex); + val = getStoreManager().evalDerivedToBase(val, T); + state = state->BindExpr(CastE, val); + MakeNode(Dst, CastE, node, state); + } + return; + + // Various C++ casts that are not handled yet. + case CK_Dynamic: + case CK_ToUnion: + case CK_BaseToDerived: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_UserDefinedConversion: + case CK_ConstructorConversion: + case CK_VectorSplat: + case CK_MemberPointerToBoolean: { + SaveAndRestore OldSink(Builder->BuildSinks); + Builder->BuildSinks = true; + MakeNode(Dst, CastE, Pred, GetState(Pred)); + return; + } + } +} + +void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL, + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + const InitListExpr* ILE + = cast(CL->getInitializer()->IgnoreParens()); + ExplodedNodeSet Tmp; + Visit(ILE, Pred, Tmp); + + for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) { + const GRState* state = GetState(*I); + SVal ILV = state->getSVal(ILE); + const LocationContext *LC = (*I)->getLocationContext(); + state = state->bindCompoundLiteral(CL, LC, ILV); + + if (CL->isLValue()) { + MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC))); + } + else + MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV)); + } +} + +void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, + ExplodedNodeSet& Dst) { + + // The CFG has one DeclStmt per Decl. + const Decl* D = *DS->decl_begin(); + + if (!D || !isa(D)) + return; + + const VarDecl* VD = dyn_cast(D); + const Expr* InitEx = VD->getInit(); + + // FIXME: static variables may have an initializer, but the second + // time a function is called those values may not be current. + ExplodedNodeSet Tmp; + + if (InitEx) { + if (VD->getType()->isReferenceType() && !InitEx->isLValue()) { + // If the initializer is C++ record type, it should already has a + // temp object. + if (!InitEx->getType()->isRecordType()) + CreateCXXTemporaryObject(InitEx, Pred, Tmp); + else + Tmp.Add(Pred); + } else + Visit(InitEx, Pred, Tmp); + } else + Tmp.Add(Pred); + + ExplodedNodeSet Tmp2; + CheckerVisit(DS, Tmp2, Tmp, PreVisitStmtCallback); + + for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) { + ExplodedNode *N = *I; + const GRState *state = GetState(N); + + // Decls without InitExpr are not initialized explicitly. + const LocationContext *LC = N->getLocationContext(); + + if (InitEx) { + SVal InitVal = state->getSVal(InitEx); + + // We bound the temp obj region to the CXXConstructExpr. Now recover + // the lazy compound value when the variable is not a reference. + if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() && + !VD->getType()->isReferenceType() && isa(InitVal)){ + InitVal = state->getSVal(cast(InitVal).getRegion()); + assert(isa(InitVal)); + } + + // Recover some path-sensitivity if a scalar value evaluated to + // UnknownVal. + if ((InitVal.isUnknown() || + !getConstraintManager().canReasonAbout(InitVal)) && + !VD->getType()->isReferenceType()) { + InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, + Builder->getCurrentBlockCount()); + } + + evalBind(Dst, DS, *I, state, + loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); + } + else { + state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); + MakeNode(Dst, DS, *I, state); + } + } +} + +void ExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S, + ExplodedNode *Pred, ExplodedNodeSet& Dst) { + + const Expr* InitEx = VD->getInit(); + ExplodedNodeSet Tmp; + Visit(InitEx, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + ExplodedNode *N = *I; + const GRState *state = GetState(N); + + const LocationContext *LC = N->getLocationContext(); + SVal InitVal = state->getSVal(InitEx); + + // Recover some path-sensitivity if a scalar value evaluated to + // UnknownVal. + if (InitVal.isUnknown() || + !getConstraintManager().canReasonAbout(InitVal)) { + InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, + Builder->getCurrentBlockCount()); + } + + evalBind(Dst, S, N, state, + loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); + } +} + +namespace { + // This class is used by VisitInitListExpr as an item in a worklist + // for processing the values contained in an InitListExpr. +class InitListWLItem { +public: + llvm::ImmutableList Vals; + ExplodedNode* N; + InitListExpr::const_reverse_iterator Itr; + + InitListWLItem(ExplodedNode* n, llvm::ImmutableList vals, + InitListExpr::const_reverse_iterator itr) + : Vals(vals), N(n), Itr(itr) {} +}; +} + + +void ExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + + const GRState* state = GetState(Pred); + QualType T = getContext().getCanonicalType(E->getType()); + unsigned NumInitElements = E->getNumInits(); + + if (T->isArrayType() || T->isRecordType() || T->isVectorType()) { + llvm::ImmutableList StartVals = getBasicVals().getEmptySValList(); + + // Handle base case where the initializer has no elements. + // e.g: static int* myArray[] = {}; + if (NumInitElements == 0) { + SVal V = svalBuilder.makeCompoundVal(T, StartVals); + MakeNode(Dst, E, Pred, state->BindExpr(E, V)); + return; + } + + // Create a worklist to process the initializers. + llvm::SmallVector WorkList; + WorkList.reserve(NumInitElements); + WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin())); + InitListExpr::const_reverse_iterator ItrEnd = E->rend(); + assert(!(E->rbegin() == E->rend())); + + // Process the worklist until it is empty. + while (!WorkList.empty()) { + InitListWLItem X = WorkList.back(); + WorkList.pop_back(); + + ExplodedNodeSet Tmp; + Visit(*X.Itr, X.N, Tmp); + + InitListExpr::const_reverse_iterator NewItr = X.Itr + 1; + + for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) { + // Get the last initializer value. + state = GetState(*NI); + SVal InitV = state->getSVal(cast(*X.Itr)); + + // Construct the new list of values by prepending the new value to + // the already constructed list. + llvm::ImmutableList NewVals = + getBasicVals().consVals(InitV, X.Vals); + + if (NewItr == ItrEnd) { + // Now we have a list holding all init values. Make CompoundValData. + SVal V = svalBuilder.makeCompoundVal(T, NewVals); + + // Make final state and node. + MakeNode(Dst, E, *NI, state->BindExpr(E, V)); + } + else { + // Still some initializer values to go. Push them onto the worklist. + WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr)); + } + } + } + + return; + } + + if (Loc::IsLocType(T) || T->isIntegerType()) { + assert (E->getNumInits() == 1); + ExplodedNodeSet Tmp; + const Expr* Init = E->getInit(0); + Visit(Init, Pred, Tmp); + for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) { + state = GetState(*I); + MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init))); + } + return; + } + + assert(0 && "unprocessed InitListExpr type"); +} + +/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type). +void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + QualType T = Ex->getTypeOfArgument(); + CharUnits amt; + + if (Ex->isSizeOf()) { + if (T == getContext().VoidTy) { + // sizeof(void) == 1 byte. + amt = CharUnits::One(); + } + else if (!T->isConstantSizeType()) { + assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); + + // FIXME: Add support for VLA type arguments, not just VLA expressions. + // When that happens, we should probably refactor VLASizeChecker's code. + if (Ex->isArgumentType()) { + Dst.Add(Pred); + return; + } + + // Get the size by getting the extent of the sub-expression. + // First, visit the sub-expression to find its region. + const Expr *Arg = Ex->getArgumentExpr(); + ExplodedNodeSet Tmp; + Visit(Arg, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + const GRState* state = GetState(*I); + const MemRegion *MR = state->getSVal(Arg).getAsRegion(); + + // If the subexpression can't be resolved to a region, we don't know + // anything about its size. Just leave the state as is and continue. + if (!MR) { + Dst.Add(*I); + continue; + } + + // The result is the extent of the VLA. + SVal Extent = cast(MR)->getExtent(svalBuilder); + MakeNode(Dst, Ex, *I, state->BindExpr(Ex, Extent)); + } + + return; + } + else if (T->getAs()) { + // Some code tries to take the sizeof an ObjCObjectType, relying that + // the compiler has laid out its representation. Just report Unknown + // for these. + Dst.Add(Pred); + return; + } + else { + // All other cases. + amt = getContext().getTypeSizeInChars(T); + } + } + else // Get alignment of the type. + amt = getContext().getTypeAlignInChars(T); + + MakeNode(Dst, Ex, Pred, + GetState(Pred)->BindExpr(Ex, + svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType()))); +} + +void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE, + ExplodedNode* Pred, ExplodedNodeSet& Dst) { + Expr::EvalResult Res; + if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); + assert(OOE->getType()->isIntegerType()); + assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); + SVal X = svalBuilder.makeIntVal(IV); + MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X)); + return; + } + // FIXME: Handle the case where __builtin_offsetof is not a constant. + Dst.Add(Pred); +} + +void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + + switch (U->getOpcode()) { + + default: + break; + + case UO_Real: { + const Expr* Ex = U->getSubExpr()->IgnoreParens(); + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + + // FIXME: We don't have complex SValues yet. + if (Ex->getType()->isAnyComplexType()) { + // Just report "Unknown." + Dst.Add(*I); + continue; + } + + // For all other types, UO_Real is an identity operation. + assert (U->getType() == Ex->getType()); + const GRState* state = GetState(*I); + MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); + } + + return; + } + + case UO_Imag: { + + const Expr* Ex = U->getSubExpr()->IgnoreParens(); + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + // FIXME: We don't have complex SValues yet. + if (Ex->getType()->isAnyComplexType()) { + // Just report "Unknown." + Dst.Add(*I); + continue; + } + + // For all other types, UO_Imag returns 0. + const GRState* state = GetState(*I); + SVal X = svalBuilder.makeZeroVal(Ex->getType()); + MakeNode(Dst, U, *I, state->BindExpr(U, X)); + } + + return; + } + + case UO_Plus: + assert(!U->isLValue()); + // FALL-THROUGH. + case UO_Deref: + case UO_AddrOf: + case UO_Extension: { + + // Unary "+" is a no-op, similar to a parentheses. We still have places + // where it may be a block-level expression, so we need to + // generate an extra node that just propagates the value of the + // subexpression. + + const Expr* Ex = U->getSubExpr()->IgnoreParens(); + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + const GRState* state = GetState(*I); + MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); + } + + return; + } + + case UO_LNot: + case UO_Minus: + case UO_Not: { + assert (!U->isLValue()); + const Expr* Ex = U->getSubExpr()->IgnoreParens(); + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + const GRState* state = GetState(*I); + + // Get the value of the subexpression. + SVal V = state->getSVal(Ex); + + if (V.isUnknownOrUndef()) { + MakeNode(Dst, U, *I, state->BindExpr(U, V)); + continue; + } + +// QualType DstT = getContext().getCanonicalType(U->getType()); +// QualType SrcT = getContext().getCanonicalType(Ex->getType()); +// +// if (DstT != SrcT) // Perform promotions. +// V = evalCast(V, DstT); +// +// if (V.isUnknownOrUndef()) { +// MakeNode(Dst, U, *I, BindExpr(St, U, V)); +// continue; +// } + + switch (U->getOpcode()) { + default: + assert(false && "Invalid Opcode."); + break; + + case UO_Not: + // FIXME: Do we need to handle promotions? + state = state->BindExpr(U, evalComplement(cast(V))); + break; + + case UO_Minus: + // FIXME: Do we need to handle promotions? + state = state->BindExpr(U, evalMinus(cast(V))); + break; + + case UO_LNot: + + // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." + // + // Note: technically we do "E == 0", but this is the same in the + // transfer functions as "0 == E". + SVal Result; + + if (isa(V)) { + Loc X = svalBuilder.makeNull(); + Result = evalBinOp(state, BO_EQ, cast(V), X, + U->getType()); + } + else { + nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType())); + Result = evalBinOp(state, BO_EQ, cast(V), X, + U->getType()); + } + + state = state->BindExpr(U, Result); + + break; + } + + MakeNode(Dst, U, *I, state); + } + + return; + } + } + + // Handle ++ and -- (both pre- and post-increment). + assert (U->isIncrementDecrementOp()); + ExplodedNodeSet Tmp; + const Expr* Ex = U->getSubExpr()->IgnoreParens(); + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { + + const GRState* state = GetState(*I); + SVal loc = state->getSVal(Ex); + + // Perform a load. + ExplodedNodeSet Tmp2; + evalLoad(Tmp2, Ex, *I, state, loc); + + for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) { + + state = GetState(*I2); + SVal V2_untested = state->getSVal(Ex); + + // Propagate unknown and undefined values. + if (V2_untested.isUnknownOrUndef()) { + MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested)); + continue; + } + DefinedSVal V2 = cast(V2_untested); + + // Handle all other values. + BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add + : BO_Sub; + + // If the UnaryOperator has non-location type, use its type to create the + // constant value. If the UnaryOperator has location type, create the + // constant with int type and pointer width. + SVal RHS; + + if (U->getType()->isAnyPointerType()) + RHS = svalBuilder.makeIntValWithPtrWidth(1, false); + else + RHS = svalBuilder.makeIntVal(1, U->getType()); + + SVal Result = evalBinOp(state, Op, V2, RHS, U->getType()); + + // Conjure a new symbol if necessary to recover precision. + if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){ + DefinedOrUnknownSVal SymVal = + svalBuilder.getConjuredSymbolVal(NULL, Ex, + Builder->getCurrentBlockCount()); + Result = SymVal; + + // 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. + if (Loc::IsLocType(U->getType())) { + DefinedOrUnknownSVal Constraint = + svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType())); + + if (!state->assume(Constraint, true)) { + // It isn't feasible for the original value to be null. + // Propagate this constraint. + Constraint = svalBuilder.evalEQ(state, SymVal, + svalBuilder.makeZeroVal(U->getType())); + + + state = state->assume(Constraint, false); + assert(state); + } + } + } + + // Since the lvalue-to-rvalue conversion is explicit in the AST, + // we bind an l-value if the operator is prefix and an lvalue (in C++). + if (U->isPrefix() && U->isLValue()) + state = state->BindExpr(U, loc); + else + state = state->BindExpr(U, V2); + + // Perform the store. + evalStore(Dst, NULL, U, *I2, state, loc, Result); + } + } +} + +void ExprEngine::VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); +} + +void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A, + AsmStmt::const_outputs_iterator I, + AsmStmt::const_outputs_iterator E, + ExplodedNode* Pred, ExplodedNodeSet& Dst) { + if (I == E) { + VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst); + return; + } + + ExplodedNodeSet Tmp; + Visit(*I, Pred, Tmp); + ++I; + + for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI) + VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst); +} + +void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A, + AsmStmt::const_inputs_iterator I, + AsmStmt::const_inputs_iterator E, + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + if (I == E) { + + // We have processed both the inputs and the outputs. All of the outputs + // should evaluate to Locs. Nuke all of their values. + + // FIXME: Some day in the future it would be nice to allow a "plug-in" + // which interprets the inline asm and stores proper results in the + // outputs. + + const GRState* state = GetState(Pred); + + for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(), + OE = A->end_outputs(); OI != OE; ++OI) { + + SVal X = state->getSVal(*OI); + assert (!isa(X)); // Should be an Lval, or unknown, undef. + + if (isa(X)) + state = state->bindLoc(cast(X), UnknownVal()); + } + + MakeNode(Dst, A, Pred, state); + return; + } + + ExplodedNodeSet Tmp; + Visit(*I, Pred, Tmp); + + ++I; + + for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI!=NE; ++NI) + VisitAsmStmtHelperInputs(A, I, E, *NI, Dst); +} + +void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Src; + if (const Expr *RetE = RS->getRetValue()) { + // Record the returned expression in the state. It will be used in + // ProcessCallExit to bind the return value to the call expr. + { + static int Tag = 0; + SaveAndRestore OldTag(Builder->Tag, &Tag); + const GRState *state = GetState(Pred); + state = state->set(RetE); + Pred = Builder->generateNode(RetE, state, Pred); + } + // We may get a NULL Pred because we generated a cached node. + if (Pred) + Visit(RetE, Pred, Src); + } + else { + Src.Add(Pred); + } + + ExplodedNodeSet CheckedSet; + CheckerVisit(RS, CheckedSet, Src, PreVisitStmtCallback); + + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + + assert(Builder && "StmtNodeBuilder must be defined."); + + Pred = *I; + unsigned size = Dst.size(); + + SaveAndRestore OldSink(Builder->BuildSinks); + SaveOr OldHasGen(Builder->HasGeneratedNode); + + getTF().evalReturn(Dst, *this, *Builder, RS, Pred); + + // Handle the case where no nodes where generated. + if (!Builder->BuildSinks && Dst.size() == size && + !Builder->HasGeneratedNode) + MakeNode(Dst, RS, Pred, GetState(Pred)); + } +} + +//===----------------------------------------------------------------------===// +// Transfer functions: Binary operators. +//===----------------------------------------------------------------------===// + +void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + ExplodedNodeSet Tmp1; + Expr* LHS = B->getLHS()->IgnoreParens(); + Expr* RHS = B->getRHS()->IgnoreParens(); + + Visit(LHS, Pred, Tmp1); + ExplodedNodeSet Tmp3; + + for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { + SVal LeftV = GetState(*I1)->getSVal(LHS); + ExplodedNodeSet Tmp2; + Visit(RHS, *I1, Tmp2); + + ExplodedNodeSet CheckedSet; + CheckerVisit(B, CheckedSet, Tmp2, PreVisitStmtCallback); + + // With both the LHS and RHS evaluated, process the operation itself. + + for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end(); + I2 != E2; ++I2) { + + const GRState *state = GetState(*I2); + SVal RightV = state->getSVal(RHS); + + BinaryOperator::Opcode Op = B->getOpcode(); + + if (Op == BO_Assign) { + // EXPERIMENTAL: "Conjured" symbols. + // FIXME: Handle structs. + QualType T = RHS->getType(); + + if (RightV.isUnknown() ||!getConstraintManager().canReasonAbout(RightV)) + { + unsigned Count = Builder->getCurrentBlockCount(); + RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count); + } + + SVal ExprVal = B->isLValue() ? LeftV : RightV; + + // Simulate the effects of a "store": bind the value of the RHS + // to the L-Value represented by the LHS. + evalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), 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()) { + MakeNode(Tmp3, B, *I2, state); + continue; + } + + state = state->BindExpr(B, Result); + + MakeNode(Tmp3, B, *I2, state); + continue; + } + + assert (B->isCompoundAssignmentOp()); + + switch (Op) { + default: + assert(0 && "Invalid opcode for compound assignment."); + case BO_MulAssign: Op = BO_Mul; break; + case BO_DivAssign: Op = BO_Div; break; + case BO_RemAssign: Op = BO_Rem; break; + case BO_AddAssign: Op = BO_Add; break; + case BO_SubAssign: Op = BO_Sub; break; + case BO_ShlAssign: Op = BO_Shl; break; + case BO_ShrAssign: Op = BO_Shr; break; + case BO_AndAssign: Op = BO_And; break; + case BO_XorAssign: Op = BO_Xor; break; + case BO_OrAssign: Op = BO_Or; break; + } + + // Perform a load (the LHS). This performs the checks for + // null dereferences, and so on. + ExplodedNodeSet Tmp4; + SVal location = state->getSVal(LHS); + evalLoad(Tmp4, LHS, *I2, state, location); + + for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4; + ++I4) { + state = GetState(*I4); + SVal V = state->getSVal(LHS); + + // Get the computation type. + QualType CTy = + cast(B)->getComputationResultType(); + CTy = getContext().getCanonicalType(CTy); + + QualType CLHSTy = + cast(B)->getComputationLHSType(); + CLHSTy = getContext().getCanonicalType(CLHSTy); + + QualType LTy = getContext().getCanonicalType(LHS->getType()); + QualType RTy = getContext().getCanonicalType(RHS->getType()); + + // Promote LHS. + V = svalBuilder.evalCast(V, CLHSTy, LTy); + + // Compute the result of the operation. + SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy), + B->getType(), CTy); + + // EXPERIMENTAL: "Conjured" symbols. + // FIXME: Handle structs. + + SVal LHSVal; + + if (Result.isUnknown() || + !getConstraintManager().canReasonAbout(Result)) { + + unsigned Count = Builder->getCurrentBlockCount(); + + // The symbolic value is actually for the type of the left-hand side + // expression, not the computation type, as this is the value the + // LValue on the LHS will bind to. + LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count); + + // However, we need to convert the symbol to the computation type. + Result = svalBuilder.evalCast(LHSVal, CTy, LTy); + } + else { + // The left-hand side may bind to a different value then the + // computation type. + LHSVal = svalBuilder.evalCast(Result, LTy, CTy); + } + + evalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result), + location, LHSVal); + } + } + } + + CheckerVisit(B, Dst, Tmp3, PostVisitStmtCallback); +} + +//===----------------------------------------------------------------------===// +// Checker registration/lookup. +//===----------------------------------------------------------------------===// + +Checker *ExprEngine::lookupChecker(void *tag) const { + CheckerMap::const_iterator I = CheckerM.find(tag); + return (I == CheckerM.end()) ? NULL : Checkers[I->second].second; +} + +//===----------------------------------------------------------------------===// +// Visualization. +//===----------------------------------------------------------------------===// + +#ifndef NDEBUG +static ExprEngine* GraphPrintCheckerState; +static SourceManager* GraphPrintSourceManager; + +namespace llvm { +template<> +struct DOTGraphTraits : + public DefaultDOTGraphTraits { + + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + // FIXME: Since we do not cache error nodes in ExprEngine now, this does not + // work. + static std::string getNodeAttributes(const ExplodedNode* N, void*) { + +#if 0 + // FIXME: Replace with a general scheme to tell if the node is + // an error node. + if (GraphPrintCheckerState->isImplicitNullDeref(N) || + GraphPrintCheckerState->isExplicitNullDeref(N) || + GraphPrintCheckerState->isUndefDeref(N) || + GraphPrintCheckerState->isUndefStore(N) || + GraphPrintCheckerState->isUndefControlFlow(N) || + GraphPrintCheckerState->isUndefResult(N) || + GraphPrintCheckerState->isBadCall(N) || + GraphPrintCheckerState->isUndefArg(N)) + return "color=\"red\",style=\"filled\""; + + if (GraphPrintCheckerState->isNoReturnCall(N)) + return "color=\"blue\",style=\"filled\""; +#endif + return ""; + } + + static std::string getNodeLabel(const ExplodedNode* N, void*){ + + std::string sbuf; + llvm::raw_string_ostream Out(sbuf); + + // Program Location. + ProgramPoint Loc = N->getLocation(); + + switch (Loc.getKind()) { + case ProgramPoint::BlockEntranceKind: + Out << "Block Entrance: B" + << cast(Loc).getBlock()->getBlockID(); + break; + + case ProgramPoint::BlockExitKind: + assert (false); + break; + + case ProgramPoint::CallEnterKind: + Out << "CallEnter"; + break; + + case ProgramPoint::CallExitKind: + Out << "CallExit"; + break; + + default: { + if (StmtPoint *L = dyn_cast(&Loc)) { + const Stmt* S = L->getStmt(); + SourceLocation SLoc = S->getLocStart(); + + Out << S->getStmtClassName() << ' ' << (void*) S << ' '; + LangOptions LO; // FIXME. + S->printPretty(Out, 0, PrintingPolicy(LO)); + + if (SLoc.isFileID()) { + Out << "\\lline=" + << GraphPrintSourceManager->getInstantiationLineNumber(SLoc) + << " col=" + << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc) + << "\\l"; + } + + if (isa(Loc)) + Out << "\\lPreStmt\\l;"; + else if (isa(Loc)) + Out << "\\lPostLoad\\l;"; + else if (isa(Loc)) + Out << "\\lPostStore\\l"; + else if (isa(Loc)) + Out << "\\lPostLValue\\l"; + +#if 0 + // FIXME: Replace with a general scheme to determine + // the name of the check. + if (GraphPrintCheckerState->isImplicitNullDeref(N)) + Out << "\\|Implicit-Null Dereference.\\l"; + else if (GraphPrintCheckerState->isExplicitNullDeref(N)) + Out << "\\|Explicit-Null Dereference.\\l"; + else if (GraphPrintCheckerState->isUndefDeref(N)) + Out << "\\|Dereference of undefialied value.\\l"; + else if (GraphPrintCheckerState->isUndefStore(N)) + Out << "\\|Store to Undefined Loc."; + else if (GraphPrintCheckerState->isUndefResult(N)) + Out << "\\|Result of operation is undefined."; + else if (GraphPrintCheckerState->isNoReturnCall(N)) + Out << "\\|Call to function marked \"noreturn\"."; + else if (GraphPrintCheckerState->isBadCall(N)) + Out << "\\|Call to NULL/Undefined."; + else if (GraphPrintCheckerState->isUndefArg(N)) + Out << "\\|Argument in call is undefined"; +#endif + + break; + } + + const BlockEdge& E = cast(Loc); + Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" + << E.getDst()->getBlockID() << ')'; + + if (const Stmt* T = E.getSrc()->getTerminator()) { + + SourceLocation SLoc = T->getLocStart(); + + Out << "\\|Terminator: "; + LangOptions LO; // FIXME. + E.getSrc()->printTerminator(Out, LO); + + if (SLoc.isFileID()) { + Out << "\\lline=" + << GraphPrintSourceManager->getInstantiationLineNumber(SLoc) + << " col=" + << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc); + } + + if (isa(T)) { + const Stmt* Label = E.getDst()->getLabel(); + + if (Label) { + if (const CaseStmt* C = dyn_cast(Label)) { + Out << "\\lcase "; + LangOptions LO; // FIXME. + C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO)); + + if (const Stmt* RHS = C->getRHS()) { + Out << " .. "; + RHS->printPretty(Out, 0, PrintingPolicy(LO)); + } + + Out << ":"; + } + else { + assert (isa(Label)); + Out << "\\ldefault:"; + } + } + else + Out << "\\l(implicit) default:"; + } + else if (isa(T)) { + // FIXME + } + else { + Out << "\\lCondition: "; + if (*E.getSrc()->succ_begin() == E.getDst()) + Out << "true"; + else + Out << "false"; + } + + Out << "\\l"; + } + +#if 0 + // FIXME: Replace with a general scheme to determine + // the name of the check. + if (GraphPrintCheckerState->isUndefControlFlow(N)) { + Out << "\\|Control-flow based on\\lUndefined value.\\l"; + } +#endif + } + } + + const GRState *state = N->getState(); + Out << "\\|StateID: " << (void*) state + << " NodeID: " << (void*) N << "\\|"; + state->printDOT(Out, *N->getLocationContext()->getCFG()); + Out << "\\l"; + return Out.str(); + } +}; +} // end llvm namespace +#endif + +#ifndef NDEBUG +template +ExplodedNode* GetGraphNode(ITERATOR I) { return *I; } + +template <> ExplodedNode* +GetGraphNode::iterator> + (llvm::DenseMap::iterator I) { + return I->first; +} +#endif + +void ExprEngine::ViewGraph(bool trim) { +#ifndef NDEBUG + if (trim) { + std::vector Src; + + // Flush any outstanding reports to make sure we cover all the nodes. + // This does not cause them to get displayed. + for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) + const_cast(*I)->FlushReports(BR); + + // Iterate through the reports and get their nodes. + for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) { + for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end(); + I2!=E2; ++I2) { + const BugReportEquivClass& EQ = *I2; + const BugReport &R = **EQ.begin(); + ExplodedNode *N = const_cast(R.getErrorNode()); + if (N) Src.push_back(N); + } + } + + ViewGraph(&Src[0], &Src[0]+Src.size()); + } + else { + GraphPrintCheckerState = this; + GraphPrintSourceManager = &getContext().getSourceManager(); + + llvm::ViewGraph(*G.roots_begin(), "ExprEngine"); + + GraphPrintCheckerState = NULL; + GraphPrintSourceManager = NULL; + } +#endif +} + +void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) { +#ifndef NDEBUG + GraphPrintCheckerState = this; + GraphPrintSourceManager = &getContext().getSourceManager(); + + std::auto_ptr TrimmedG(G.Trim(Beg, End).first); + + if (!TrimmedG.get()) + llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; + else + llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine"); + + GraphPrintCheckerState = NULL; + GraphPrintSourceManager = NULL; +#endif +} diff --git a/clang/lib/GR/GRBlockCounter.cpp b/clang/lib/GR/GRBlockCounter.cpp deleted file mode 100644 index 8a026b1ed4b..00000000000 --- a/clang/lib/GR/GRBlockCounter.cpp +++ /dev/null @@ -1,86 +0,0 @@ -//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count -// the number of times a given block has been visited along a path -// analyzed by GRCoreEngine. -// -//===----------------------------------------------------------------------===// - -#include "clang/GR/PathSensitive/GRBlockCounter.h" -#include "llvm/ADT/ImmutableMap.h" - -using namespace clang; -using namespace GR; - -namespace { - -class CountKey { - const StackFrameContext *CallSite; - unsigned BlockID; - -public: - CountKey(const StackFrameContext *CS, unsigned ID) - : CallSite(CS), BlockID(ID) {} - - bool operator==(const CountKey &RHS) const { - return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID); - } - - bool operator<(const CountKey &RHS) const { - return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID) - : (CallSite < RHS.CallSite); - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(CallSite); - ID.AddInteger(BlockID); - } -}; - -} - -typedef llvm::ImmutableMap CountMap; - -static inline CountMap GetMap(void* D) { - return CountMap(static_cast(D)); -} - -static inline CountMap::Factory& GetFactory(void* F) { - return *static_cast(F); -} - -unsigned GRBlockCounter::getNumVisited(const StackFrameContext *CallSite, - unsigned BlockID) const { - CountMap M = GetMap(Data); - CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID)); - return T ? *T : 0; -} - -GRBlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) { - F = new CountMap::Factory(Alloc); -} - -GRBlockCounter::Factory::~Factory() { - delete static_cast(F); -} - -GRBlockCounter -GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, - const StackFrameContext *CallSite, - unsigned BlockID) { - return GRBlockCounter(GetFactory(F).add(GetMap(BC.Data), - CountKey(CallSite, BlockID), - BC.getNumVisited(CallSite, BlockID)+1).getRoot()); -} - -GRBlockCounter -GRBlockCounter::Factory::GetEmptyCounter() { - return GRBlockCounter(GetFactory(F).getEmptyMap().getRoot()); -} diff --git a/clang/lib/GR/GRCXXExprEngine.cpp b/clang/lib/GR/GRCXXExprEngine.cpp deleted file mode 100644 index 24629551793..00000000000 --- a/clang/lib/GR/GRCXXExprEngine.cpp +++ /dev/null @@ -1,328 +0,0 @@ -//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- 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 the C++ expression evaluation engine. -// -//===----------------------------------------------------------------------===// - -#include "clang/GR/PathSensitive/AnalysisManager.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" -#include "clang/AST/DeclCXX.h" - -using namespace clang; -using namespace GR; - -namespace { -class CallExprWLItem { -public: - CallExpr::const_arg_iterator I; - ExplodedNode *N; - - CallExprWLItem(const CallExpr::const_arg_iterator &i, ExplodedNode *n) - : I(i), N(n) {} -}; -} - -void GRExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE, - const FunctionProtoType *FnType, - ExplodedNode *Pred, ExplodedNodeSet &Dst, - bool FstArgAsLValue) { - - - llvm::SmallVector WorkList; - WorkList.reserve(AE - AI); - WorkList.push_back(CallExprWLItem(AI, Pred)); - - while (!WorkList.empty()) { - CallExprWLItem Item = WorkList.back(); - WorkList.pop_back(); - - if (Item.I == AE) { - Dst.insert(Item.N); - continue; - } - - // Evaluate the argument. - ExplodedNodeSet Tmp; - bool VisitAsLvalue = FstArgAsLValue; - if (FstArgAsLValue) { - FstArgAsLValue = false; - } else { - const unsigned ParamIdx = Item.I - AI; - VisitAsLvalue = FnType && ParamIdx < FnType->getNumArgs() - ? FnType->getArgType(ParamIdx)->isReferenceType() - : false; - } - - Visit(*Item.I, Item.N, Tmp); - ++(Item.I); - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) - WorkList.push_back(CallExprWLItem(Item.I, *NI)); - } -} - -const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXRecordDecl *D, - const StackFrameContext *SFC) { - Type *T = D->getTypeForDecl(); - QualType PT = getContext().getPointerType(QualType(T, 0)); - return svalBuilder.getRegionManager().getCXXThisRegion(PT, SFC); -} - -const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *decl, - const StackFrameContext *frameCtx) { - return svalBuilder.getRegionManager(). - getCXXThisRegion(decl->getThisType(getContext()), frameCtx); -} - -void GRExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { - const GRState *state = GetState(*I); - - // Bind the temporary object to the value of the expression. Then bind - // the expression to the location of the object. - SVal V = state->getSVal(Ex); - - const MemRegion *R = - svalBuilder.getRegionManager().getCXXTempObjectRegion(Ex, - Pred->getLocationContext()); - - state = state->bindLoc(loc::MemRegionVal(R), V); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); - } -} - -void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, - const MemRegion *Dest, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (!Dest) - Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E, - Pred->getLocationContext()); - - if (E->isElidable()) { - VisitAggExpr(E->getArg(0), Dest, Pred, Dst); - return; - } - - const CXXConstructorDecl *CD = E->getConstructor(); - assert(CD); - - if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) - // FIXME: invalidate the object. - return; - - - // Evaluate other arguments. - ExplodedNodeSet argsEvaluated; - const FunctionProtoType *FnType = CD->getType()->getAs(); - evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated); - // The callee stack frame context used to create the 'this' parameter region. - const StackFrameContext *SFC = AMgr.getStackFrame(CD, - Pred->getLocationContext(), - E, Builder->getBlock(), - Builder->getIndex()); - - const CXXThisRegion *ThisR =getCXXThisRegion(E->getConstructor()->getParent(), - SFC); - - CallEnter Loc(E, SFC, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), - NE = argsEvaluated.end(); NI != NE; ++NI) { - const GRState *state = GetState(*NI); - // Setup 'this' region, so that the ctor is evaluated on the object pointed - // by 'Dest'. - state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - if (N) - Dst.Add(N); - } -} - -void GRExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, - const MemRegion *Dest, - const Stmt *S, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (!(DD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) - return; - // Create the context for 'this' region. - const StackFrameContext *SFC = AMgr.getStackFrame(DD, - Pred->getLocationContext(), - S, Builder->getBlock(), - Builder->getIndex()); - - const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC); - - CallEnter PP(S, SFC, Pred->getLocationContext()); - - const GRState *state = Pred->getState(); - state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); - ExplodedNode *N = Builder->generateNode(PP, state, Pred); - if (N) - Dst.Add(N); -} - -void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - // Get the method type. - const FunctionProtoType *FnType = - MCE->getCallee()->getType()->getAs(); - assert(FnType && "Method type not available"); - - // Evaluate explicit arguments with a worklist. - ExplodedNodeSet argsEvaluated; - evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated); - - // Evaluate the implicit object argument. - ExplodedNodeSet AllargsEvaluated; - const MemberExpr *ME = dyn_cast(MCE->getCallee()->IgnoreParens()); - if (!ME) - return; - Expr *ObjArgExpr = ME->getBase(); - for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), - E = argsEvaluated.end(); I != E; ++I) { - Visit(ObjArgExpr, *I, AllargsEvaluated); - } - - // Now evaluate the call itself. - const CXXMethodDecl *MD = cast(ME->getMemberDecl()); - assert(MD && "not a CXXMethodDecl?"); - evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst); -} - -void GRExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - const CXXMethodDecl *MD = dyn_cast_or_null(C->getCalleeDecl()); - if (!MD) { - // If the operator doesn't represent a method call treat as regural call. - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); - return; - } - - // Determine the type of function we're calling (if available). - const FunctionProtoType *Proto = NULL; - QualType FnType = C->getCallee()->IgnoreParens()->getType(); - if (const PointerType *FnTypePtr = FnType->getAs()) - Proto = FnTypePtr->getPointeeType()->getAs(); - - // Evaluate arguments treating the first one (object method is called on) - // as alvalue. - ExplodedNodeSet argsEvaluated; - evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true); - - // Now evaluate the call itself. - evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst); -} - -void GRExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, - const Expr *ThisExpr, ExplodedNode *Pred, - ExplodedNodeSet &Src, ExplodedNodeSet &Dst) { - // Allow checkers to pre-visit the member call. - ExplodedNodeSet PreVisitChecks; - CheckerVisit(MCE, PreVisitChecks, Src, PreVisitStmtCallback); - - if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) { - // FIXME: conservative method call evaluation. - CheckerVisit(MCE, Dst, PreVisitChecks, PostVisitStmtCallback); - return; - } - - const StackFrameContext *SFC = AMgr.getStackFrame(MD, - Pred->getLocationContext(), - MCE, - Builder->getBlock(), - Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); - CallEnter Loc(MCE, SFC, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(), - E = PreVisitChecks.end(); I != E; ++I) { - // Set up 'this' region. - const GRState *state = GetState(*I); - state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr)); - Dst.Add(Builder->generateNode(Loc, state, *I)); - } -} - -void GRExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (CNE->isArray()) { - // FIXME: allocating an array has not been handled. - return; - } - - unsigned Count = Builder->getCurrentBlockCount(); - DefinedOrUnknownSVal symVal = - svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), Count); - const MemRegion *NewReg = cast(symVal).getRegion(); - - QualType ObjTy = CNE->getType()->getAs()->getPointeeType(); - - const ElementRegion *EleReg = - getStoreManager().GetElementZeroRegion(NewReg, ObjTy); - - // Evaluate constructor arguments. - const FunctionProtoType *FnType = NULL; - const CXXConstructorDecl *CD = CNE->getConstructor(); - if (CD) - FnType = CD->getType()->getAs(); - ExplodedNodeSet argsEvaluated; - evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), - FnType, Pred, argsEvaluated); - - // Initialize the object region and bind the 'new' expression. - for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), - E = argsEvaluated.end(); I != E; ++I) { - const GRState *state = GetState(*I); - - if (ObjTy->isRecordType()) { - state = state->InvalidateRegion(EleReg, CNE, Count); - } else { - if (CNE->hasInitializer()) { - SVal V = state->getSVal(*CNE->constructor_arg_begin()); - state = state->bindLoc(loc::MemRegionVal(EleReg), V); - } else { - // Explicitly set to undefined, because currently we retrieve symbolic - // value from symbolic region. - state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); - } - } - state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); - MakeNode(Dst, CNE, *I, state); - } -} - -void GRExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, - ExplodedNode *Pred,ExplodedNodeSet &Dst) { - // Should do more checking. - ExplodedNodeSet Argevaluated; - Visit(CDE->getArgument(), Pred, Argevaluated); - for (ExplodedNodeSet::iterator I = Argevaluated.begin(), - E = Argevaluated.end(); I != E; ++I) { - const GRState *state = GetState(*I); - MakeNode(Dst, CDE, *I, state); - } -} - -void GRExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - // Get the this object region from StoreManager. - const MemRegion *R = - svalBuilder.getRegionManager().getCXXThisRegion( - getContext().getCanonicalType(TE->getType()), - Pred->getLocationContext()); - - const GRState *state = GetState(Pred); - SVal V = state->getSVal(loc::MemRegionVal(R)); - MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); -} diff --git a/clang/lib/GR/GRCoreEngine.cpp b/clang/lib/GR/GRCoreEngine.cpp deleted file mode 100644 index 092cb460aef..00000000000 --- a/clang/lib/GR/GRCoreEngine.cpp +++ /dev/null @@ -1,809 +0,0 @@ -//==- GRCoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- 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 a generic engine for intraprocedural, path-sensitive, -// dataflow analysis via graph reachability engine. -// -//===----------------------------------------------------------------------===// - -#include "clang/GR/PathSensitive/AnalysisManager.h" -#include "clang/GR/PathSensitive/GRCoreEngine.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" -#include "clang/Index/TranslationUnit.h" -#include "clang/AST/Expr.h" -#include "llvm/Support/Casting.h" -#include "llvm/ADT/DenseMap.h" -#include -#include - -using llvm::cast; -using llvm::isa; -using namespace clang; -using namespace GR; - -// This should be removed in the future. -namespace clang { -namespace GR { -GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, - const LangOptions& lopts); -} -} - -//===----------------------------------------------------------------------===// -// Worklist classes for exploration of reachable states. -//===----------------------------------------------------------------------===// - -GRWorkList::Visitor::~Visitor() {} - -namespace { -class DFS : public GRWorkList { - llvm::SmallVector Stack; -public: - virtual bool hasWork() const { - return !Stack.empty(); - } - - virtual void Enqueue(const GRWorkListUnit& U) { - Stack.push_back(U); - } - - virtual GRWorkListUnit Dequeue() { - assert (!Stack.empty()); - const GRWorkListUnit& U = Stack.back(); - Stack.pop_back(); // This technically "invalidates" U, but we are fine. - return U; - } - - virtual bool VisitItemsInWorkList(Visitor &V) { - for (llvm::SmallVectorImpl::iterator - I = Stack.begin(), E = Stack.end(); I != E; ++I) { - if (V.Visit(*I)) - return true; - } - return false; - } -}; - -class BFS : public GRWorkList { - std::deque Queue; -public: - virtual bool hasWork() const { - return !Queue.empty(); - } - - virtual void Enqueue(const GRWorkListUnit& U) { - Queue.push_front(U); - } - - virtual GRWorkListUnit Dequeue() { - GRWorkListUnit U = Queue.front(); - Queue.pop_front(); - return U; - } - - virtual bool VisitItemsInWorkList(Visitor &V) { - for (std::deque::iterator - I = Queue.begin(), E = Queue.end(); I != E; ++I) { - if (V.Visit(*I)) - return true; - } - return false; - } -}; - -} // end anonymous namespace - -// Place the dstor for GRWorkList here because it contains virtual member -// functions, and we the code for the dstor generated in one compilation unit. -GRWorkList::~GRWorkList() {} - -GRWorkList *GRWorkList::MakeDFS() { return new DFS(); } -GRWorkList *GRWorkList::MakeBFS() { return new BFS(); } - -namespace { - class BFSBlockDFSContents : public GRWorkList { - std::deque Queue; - llvm::SmallVector Stack; - public: - virtual bool hasWork() const { - return !Queue.empty() || !Stack.empty(); - } - - virtual void Enqueue(const GRWorkListUnit& U) { - if (isa(U.getNode()->getLocation())) - Queue.push_front(U); - else - Stack.push_back(U); - } - - virtual GRWorkListUnit Dequeue() { - // Process all basic blocks to completion. - if (!Stack.empty()) { - const GRWorkListUnit& U = Stack.back(); - Stack.pop_back(); // This technically "invalidates" U, but we are fine. - return U; - } - - assert(!Queue.empty()); - // Don't use const reference. The subsequent pop_back() might make it - // unsafe. - GRWorkListUnit U = Queue.front(); - Queue.pop_front(); - return U; - } - virtual bool VisitItemsInWorkList(Visitor &V) { - for (llvm::SmallVectorImpl::iterator - I = Stack.begin(), E = Stack.end(); I != E; ++I) { - if (V.Visit(*I)) - return true; - } - for (std::deque::iterator - I = Queue.begin(), E = Queue.end(); I != E; ++I) { - if (V.Visit(*I)) - return true; - } - return false; - } - - }; -} // end anonymous namespace - -GRWorkList* GRWorkList::MakeBFSBlockDFSContents() { - return new BFSBlockDFSContents(); -} - -//===----------------------------------------------------------------------===// -// Core analysis engine. -//===----------------------------------------------------------------------===// - -/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. -bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, - const GRState *InitState) { - - if (G->num_roots() == 0) { // Initialize the analysis by constructing - // the root if none exists. - - const CFGBlock* Entry = &(L->getCFG()->getEntry()); - - assert (Entry->empty() && - "Entry block must be empty."); - - assert (Entry->succ_size() == 1 && - "Entry block must have 1 successor."); - - // Get the solitary successor. - const CFGBlock* Succ = *(Entry->succ_begin()); - - // Construct an edge representing the - // starting location in the function. - BlockEdge StartLoc(Entry, Succ, L); - - // Set the current block counter to being empty. - WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); - - if (!InitState) - // Generate the root. - generateNode(StartLoc, getInitialState(L), 0); - else - generateNode(StartLoc, InitState, 0); - } - - // Check if we have a steps limit - bool UnlimitedSteps = Steps == 0; - - while (WList->hasWork()) { - if (!UnlimitedSteps) { - if (Steps == 0) - break; - --Steps; - } - - const GRWorkListUnit& WU = WList->Dequeue(); - - // Set the current block counter. - WList->setBlockCounter(WU.getBlockCounter()); - - // Retrieve the node. - ExplodedNode* Node = WU.getNode(); - - // Dispatch on the location type. - switch (Node->getLocation().getKind()) { - case ProgramPoint::BlockEdgeKind: - HandleBlockEdge(cast(Node->getLocation()), Node); - break; - - case ProgramPoint::BlockEntranceKind: - HandleBlockEntrance(cast(Node->getLocation()), Node); - break; - - case ProgramPoint::BlockExitKind: - assert (false && "BlockExit location never occur in forward analysis."); - break; - - case ProgramPoint::CallEnterKind: - HandleCallEnter(cast(Node->getLocation()), WU.getBlock(), - WU.getIndex(), Node); - break; - - case ProgramPoint::CallExitKind: - HandleCallExit(cast(Node->getLocation()), Node); - break; - - default: - assert(isa(Node->getLocation()) || - isa(Node->getLocation())); - HandlePostStmt(WU.getBlock(), WU.getIndex(), Node); - break; - } - } - - SubEngine.ProcessEndWorklist(hasWorkRemaining()); - return WList->hasWork(); -} - -void GRCoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, - unsigned Steps, - const GRState *InitState, - ExplodedNodeSet &Dst) { - ExecuteWorkList(L, Steps, InitState); - for (llvm::SmallVectorImpl::iterator I = G->EndNodes.begin(), - E = G->EndNodes.end(); I != E; ++I) { - Dst.Add(*I); - } -} - -void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, - unsigned Index, ExplodedNode *Pred) { - GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), - L.getCalleeContext(), Block, Index); - ProcessCallEnter(Builder); -} - -void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { - GRCallExitNodeBuilder Builder(*this, Pred); - ProcessCallExit(Builder); -} - -void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { - - const CFGBlock* Blk = L.getDst(); - - // Check if we are entering the EXIT block. - if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { - - assert (L.getLocationContext()->getCFG()->getExit().size() == 0 - && "EXIT block cannot contain Stmts."); - - // Process the final state transition. - GREndPathNodeBuilder Builder(Blk, Pred, this); - ProcessEndPath(Builder); - - // This path is done. Don't enqueue any more nodes. - return; - } - - // FIXME: Should we allow ProcessBlockEntrance to also manipulate state? - - if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter())) - generateNode(BlockEntrance(Blk, Pred->getLocationContext()), - Pred->State, Pred); - else { - blocksAborted.push_back(std::make_pair(L, Pred)); - } -} - -void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L, - ExplodedNode* Pred) { - - // Increment the block counter. - GRBlockCounter Counter = WList->getBlockCounter(); - Counter = BCounterFactory.IncrementCount(Counter, - Pred->getLocationContext()->getCurrentStackFrame(), - L.getBlock()->getBlockID()); - WList->setBlockCounter(Counter); - - // Process the entrance of the block. - if (CFGElement E = L.getFirstElement()) { - GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this, - SubEngine.getStateManager()); - ProcessElement(E, Builder); - } - else - HandleBlockExit(L.getBlock(), Pred); -} - -void GRCoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) { - - if (const Stmt* Term = B->getTerminator()) { - switch (Term->getStmtClass()) { - default: - assert(false && "Analysis for this terminator not implemented."); - break; - - case Stmt::BinaryOperatorClass: // '&&' and '||' - HandleBranch(cast(Term)->getLHS(), Term, B, Pred); - return; - - case Stmt::ConditionalOperatorClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - // FIXME: Use constant-folding in CFG construction to simplify this - // case. - - case Stmt::ChooseExprClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - case Stmt::DoStmtClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - case Stmt::ForStmtClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - case Stmt::ContinueStmtClass: - case Stmt::BreakStmtClass: - case Stmt::GotoStmtClass: - break; - - case Stmt::IfStmtClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - case Stmt::IndirectGotoStmtClass: { - // Only 1 successor: the indirect goto dispatch block. - assert (B->succ_size() == 1); - - GRIndirectGotoNodeBuilder - builder(Pred, B, cast(Term)->getTarget(), - *(B->succ_begin()), this); - - ProcessIndirectGoto(builder); - return; - } - - case Stmt::ObjCForCollectionStmtClass: { - // In the case of ObjCForCollectionStmt, it appears twice in a CFG: - // - // (1) inside a basic block, which represents the binding of the - // 'element' variable to a value. - // (2) in a terminator, which represents the branch. - // - // For (1), subengines will bind a value (i.e., 0 or 1) indicating - // whether or not collection contains any more elements. We cannot - // just test to see if the element is nil because a container can - // contain nil elements. - HandleBranch(Term, Term, B, Pred); - return; - } - - case Stmt::SwitchStmtClass: { - GRSwitchNodeBuilder builder(Pred, B, cast(Term)->getCond(), - this); - - ProcessSwitch(builder); - return; - } - - case Stmt::WhileStmtClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - } - } - - assert (B->succ_size() == 1 && - "Blocks with no terminator should have at most 1 successor."); - - generateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()), - Pred->State, Pred); -} - -void GRCoreEngine::HandleBranch(const Stmt* Cond, const Stmt* Term, - const CFGBlock * B, ExplodedNode* Pred) { - assert (B->succ_size() == 2); - - GRBranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), - Pred, this); - - ProcessBranch(Cond, Term, Builder); -} - -void GRCoreEngine::HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, - ExplodedNode* Pred) { - assert (!B->empty()); - - if (StmtIdx == B->size()) - HandleBlockExit(B, Pred); - else { - GRStmtNodeBuilder Builder(B, StmtIdx, Pred, this, - SubEngine.getStateManager()); - ProcessElement((*B)[StmtIdx], Builder); - } -} - -/// generateNode - Utility method to generate nodes, hook up successors, -/// and add nodes to the worklist. -void GRCoreEngine::generateNode(const ProgramPoint& Loc, - const GRState* State, ExplodedNode* Pred) { - - bool IsNew; - ExplodedNode* Node = G->getNode(Loc, State, &IsNew); - - if (Pred) - Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor. - else { - assert (IsNew); - G->addRoot(Node); // 'Node' has no predecessor. Make it a root. - } - - // Only add 'Node' to the worklist if it was freshly generated. - if (IsNew) WList->Enqueue(Node); -} - -GRStmtNodeBuilder::GRStmtNodeBuilder(const CFGBlock* b, unsigned idx, - ExplodedNode* N, GRCoreEngine* e, - GRStateManager &mgr) - : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr), - PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false), - PointKind(ProgramPoint::PostStmtKind), Tag(0) { - Deferred.insert(N); - CleanedState = Pred->getState(); -} - -GRStmtNodeBuilder::~GRStmtNodeBuilder() { - for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) - if (!(*I)->isSink()) - GenerateAutoTransition(*I); -} - -void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { - assert (!N->isSink()); - - // Check if this node entered a callee. - if (isa(N->getLocation())) { - // Still use the index of the CallExpr. It's needed to create the callee - // StackFrameContext. - Eng.WList->Enqueue(N, &B, Idx); - return; - } - - // Do not create extra nodes. Move to the next CFG element. - if (isa(N->getLocation())) { - Eng.WList->Enqueue(N, &B, Idx+1); - return; - } - - PostStmt Loc(getStmt(), N->getLocationContext()); - - if (Loc == N->getLocation()) { - // Note: 'N' should be a fresh node because otherwise it shouldn't be - // a member of Deferred. - Eng.WList->Enqueue(N, &B, Idx+1); - return; - } - - bool IsNew; - ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew); - Succ->addPredecessor(N, *Eng.G); - - if (IsNew) - Eng.WList->Enqueue(Succ, &B, Idx+1); -} - -ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, - ExplodedNode* Pred, const GRState* St, - ProgramPoint::Kind K) { - - ExplodedNode* N = generateNode(S, St, Pred, K); - - if (N) { - if (BuildSinks) - N->markAsSink(); - else - Dst.Add(N); - } - - return N; -} - -static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K, - const LocationContext *LC, const void *tag){ - switch (K) { - default: - assert(false && "Unhandled ProgramPoint kind"); - case ProgramPoint::PreStmtKind: - return PreStmt(S, LC, tag); - case ProgramPoint::PostStmtKind: - return PostStmt(S, LC, tag); - case ProgramPoint::PreLoadKind: - return PreLoad(S, LC, tag); - case ProgramPoint::PostLoadKind: - return PostLoad(S, LC, tag); - case ProgramPoint::PreStoreKind: - return PreStore(S, LC, tag); - case ProgramPoint::PostStoreKind: - return PostStore(S, LC, tag); - case ProgramPoint::PostLValueKind: - return PostLValue(S, LC, tag); - case ProgramPoint::PostPurgeDeadSymbolsKind: - return PostPurgeDeadSymbols(S, LC, tag); - } -} - -ExplodedNode* -GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state, - ExplodedNode* Pred, - ProgramPoint::Kind K, - const void *tag) { - - const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag); - return generateNodeInternal(L, state, Pred); -} - -ExplodedNode* -GRStmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc, - const GRState* State, - ExplodedNode* Pred) { - bool IsNew; - ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew); - N->addPredecessor(Pred, *Eng.G); - Deferred.erase(Pred); - - if (IsNew) { - Deferred.insert(N); - return N; - } - - return NULL; -} - -ExplodedNode* GRBranchNodeBuilder::generateNode(const GRState* State, - bool branch) { - - // If the branch has been marked infeasible we should not generate a node. - if (!isFeasible(branch)) - return NULL; - - bool IsNew; - - ExplodedNode* Succ = - Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()), - State, &IsNew); - - Succ->addPredecessor(Pred, *Eng.G); - - if (branch) - GeneratedTrue = true; - else - GeneratedFalse = true; - - if (IsNew) { - Deferred.push_back(Succ); - return Succ; - } - - return NULL; -} - -GRBranchNodeBuilder::~GRBranchNodeBuilder() { - if (!GeneratedTrue) generateNode(Pred->State, true); - if (!GeneratedFalse) generateNode(Pred->State, false); - - for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) - if (!(*I)->isSink()) Eng.WList->Enqueue(*I); -} - - -ExplodedNode* -GRIndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St, - bool isSink) { - bool IsNew; - - ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), - Pred->getLocationContext()), St, &IsNew); - - Succ->addPredecessor(Pred, *Eng.G); - - if (IsNew) { - - if (isSink) - Succ->markAsSink(); - else - Eng.WList->Enqueue(Succ); - - return Succ; - } - - return NULL; -} - - -ExplodedNode* -GRSwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){ - - bool IsNew; - - ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), - Pred->getLocationContext()), St, &IsNew); - Succ->addPredecessor(Pred, *Eng.G); - - if (IsNew) { - Eng.WList->Enqueue(Succ); - return Succ; - } - - return NULL; -} - - -ExplodedNode* -GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) { - - // Get the block for the default case. - assert (Src->succ_rbegin() != Src->succ_rend()); - CFGBlock* DefaultBlock = *Src->succ_rbegin(); - - bool IsNew; - - ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, - Pred->getLocationContext()), St, &IsNew); - Succ->addPredecessor(Pred, *Eng.G); - - if (IsNew) { - if (isSink) - Succ->markAsSink(); - else - Eng.WList->Enqueue(Succ); - - return Succ; - } - - return NULL; -} - -GREndPathNodeBuilder::~GREndPathNodeBuilder() { - // Auto-generate an EOP node if one has not been generated. - if (!HasGeneratedNode) { - // If we are in an inlined call, generate CallExit node. - if (Pred->getLocationContext()->getParent()) - GenerateCallExitNode(Pred->State); - else - generateNode(Pred->State); - } -} - -ExplodedNode* -GREndPathNodeBuilder::generateNode(const GRState* State, const void *tag, - ExplodedNode* P) { - HasGeneratedNode = true; - bool IsNew; - - ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B, - Pred->getLocationContext(), tag), State, &IsNew); - - Node->addPredecessor(P ? P : Pred, *Eng.G); - - if (IsNew) { - Eng.G->addEndOfPath(Node); - return Node; - } - - return NULL; -} - -void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { - HasGeneratedNode = true; - // Create a CallExit node and enqueue it. - const StackFrameContext *LocCtx - = cast(Pred->getLocationContext()); - const Stmt *CE = LocCtx->getCallSite(); - - // Use the the callee location context. - CallExit Loc(CE, LocCtx); - - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(Pred, *Eng.G); - - if (isNew) - Eng.WList->Enqueue(Node); -} - - -void GRCallEnterNodeBuilder::generateNode(const GRState *state) { - // Check if the callee is in the same translation unit. - if (CalleeCtx->getTranslationUnit() != - Pred->getLocationContext()->getTranslationUnit()) { - // Create a new engine. We must be careful that the new engine should not - // reference data structures owned by the old engine. - - AnalysisManager &OldMgr = Eng.SubEngine.getAnalysisManager(); - - // Get the callee's translation unit. - idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit(); - - // Create a new AnalysisManager with components of the callee's - // TranslationUnit. - // The Diagnostic is actually shared when we create ASTUnits from AST files. - AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), - OldMgr.getLangOptions(), - OldMgr.getPathDiagnosticClient(), - OldMgr.getStoreManagerCreator(), - OldMgr.getConstraintManagerCreator(), - OldMgr.getIndexer(), - OldMgr.getMaxNodes(), OldMgr.getMaxVisit(), - OldMgr.shouldVisualizeGraphviz(), - OldMgr.shouldVisualizeUbigraph(), - OldMgr.shouldPurgeDead(), - OldMgr.shouldEagerlyAssume(), - OldMgr.shouldTrimGraph(), - OldMgr.shouldInlineCall(), - OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(), - OldMgr.getAnalysisContextManager().getAddImplicitDtors(), - OldMgr.getAnalysisContextManager().getAddInitializers()); - llvm::OwningPtr TF(MakeCFRefCountTF(AMgr.getASTContext(), - /* GCEnabled */ false, - AMgr.getLangOptions())); - // Create the new engine. - GRExprEngine NewEng(AMgr, TF.take()); - - // Create the new LocationContext. - AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(), - CalleeCtx->getTranslationUnit()); - const StackFrameContext *OldLocCtx = CalleeCtx; - const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx, - OldLocCtx->getParent(), - OldLocCtx->getCallSite(), - OldLocCtx->getCallSiteBlock(), - OldLocCtx->getIndex()); - - // Now create an initial state for the new engine. - const GRState *NewState = NewEng.getStateManager().MarshalState(state, - NewLocCtx); - ExplodedNodeSet ReturnNodes; - NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(), - NewState, ReturnNodes); - return; - } - - // Get the callee entry block. - const CFGBlock *Entry = &(CalleeCtx->getCFG()->getEntry()); - assert(Entry->empty()); - assert(Entry->succ_size() == 1); - - // Get the solitary successor. - const CFGBlock *SuccB = *(Entry->succ_begin()); - - // Construct an edge representing the starting location in the callee. - BlockEdge Loc(Entry, SuccB, CalleeCtx); - - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(const_cast(Pred), *Eng.G); - - if (isNew) - Eng.WList->Enqueue(Node); -} - -void GRCallExitNodeBuilder::generateNode(const GRState *state) { - // Get the callee's location context. - const StackFrameContext *LocCtx - = cast(Pred->getLocationContext()); - // When exiting an implicit automatic obj dtor call, the callsite is the Stmt - // that triggers the dtor. - PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(const_cast(Pred), *Eng.G); - if (isNew) - Eng.WList->Enqueue(Node, LocCtx->getCallSiteBlock(), - LocCtx->getIndex() + 1); -} diff --git a/clang/lib/GR/GRExprEngine.cpp b/clang/lib/GR/GRExprEngine.cpp deleted file mode 100644 index d6086c76e64..00000000000 --- a/clang/lib/GR/GRExprEngine.cpp +++ /dev/null @@ -1,3513 +0,0 @@ -//=-- GRExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that -// is built on GREngine, but provides the boilerplate to execute transfer -// functions and build the ExplodedGraph at the expression level. -// -//===----------------------------------------------------------------------===// - -// FIXME: Restructure checker registration. -#include "Checkers/GRExprEngineInternalChecks.h" - -#include "clang/GR/BugReporter/BugType.h" -#include "clang/GR/PathSensitive/AnalysisManager.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" -#include "clang/GR/PathSensitive/GRExprEngineBuilders.h" -#include "clang/GR/PathSensitive/Checker.h" -#include "clang/AST/CharUnits.h" -#include "clang/AST/ParentMap.h" -#include "clang/AST/StmtObjC.h" -#include "clang/AST/DeclCXX.h" -#include "clang/Basic/Builtins.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/ImmutableList.h" - -#ifndef NDEBUG -#include "llvm/Support/GraphWriter.h" -#endif - -using namespace clang; -using namespace GR; -using llvm::dyn_cast; -using llvm::dyn_cast_or_null; -using llvm::cast; -using llvm::APSInt; - -namespace { - // Trait class for recording returned expression in the state. - struct ReturnExpr { - static int TagInt; - typedef const Stmt *data_type; - }; - int ReturnExpr::TagInt; -} - -//===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); - return Ctx.Selectors.getSelector(0, &II); -} - -//===----------------------------------------------------------------------===// -// Checker worklist routines. -//===----------------------------------------------------------------------===// - -void GRExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, CallbackKind Kind) { - - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for the provided . This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr NewCO; - - // The cache key is made up of the and the callback kind (pre- or post-visit) - // and the statement kind. - CallbackTag K = GetCallbackTag(Kind, S->getStmtClass()); - - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // statement kind, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - if (CO->empty()) { - // If there are no checkers, return early without doing any - // more work. - Dst.insert(Src); - return; - } - - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - unsigned checkersEvaluated = 0; - - for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I) { - // If all nodes are sunk, bail out early. - if (PrevSet->empty()) - break; - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - void *tag = I->first; - Checker *checker = I->second; - bool respondsToCallback = true; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) { - - checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, - Kind == PreVisitStmtCallback, respondsToCallback); - - } - - PrevSet = CurrSet; - - if (NewCO.get()) { - ++checkersEvaluated; - if (respondsToCallback) - NewCO->push_back(*I); - } - } - - // If we built NewCO, check if we called all the checkers. This is important - // so that we know that we accurately determined the entire set of checkers - // that responds to this callback. Note that 'checkersEvaluated' might - // not be the same as Checkers.size() if one of the Checkers generates - // a sink node. - if (NewCO.get() && checkersEvaluated == Checkers.size()) - CO_Ref = NewCO.take(); - - // Don't autotransition. The CheckerContext objects should do this - // automatically. -} - -void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, - ExplodedNodeSet &Dst, - const GRState *state, - ExplodedNode *Pred) { - bool evaluated = false; - ExplodedNodeSet DstTmp; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - - if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state, - tag)) { - evaluated = true; - break; - } else - // The checker didn't evaluate the expr. Restore the Dst. - DstTmp.clear(); - } - - if (evaluated) - Dst.insert(DstTmp); - else - Dst.insert(Pred); -} - -// CheckerEvalCall returns true if one of the checkers processed the node. -// This may return void when all call evaluation logic goes to some checker -// in the future. -bool GRExprEngine::CheckerEvalCall(const CallExpr *CE, - ExplodedNodeSet &Dst, - ExplodedNode *Pred) { - bool evaluated = false; - ExplodedNodeSet DstTmp; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - - if (checker->GR_evalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) { - evaluated = true; - break; - } else - // The checker didn't evaluate the expr. Restore the DstTmp set. - DstTmp.clear(); - } - - if (evaluated) - Dst.insert(DstTmp); - else - Dst.insert(Pred); - - return evaluated; -} - -// FIXME: This is largely copy-paste from CheckerVisit(). Need to -// unify. -void GRExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, SVal location, - SVal val, bool isPrevisit) { - - if (Checkers.empty()) { - Dst.insert(Src); - return; - } - - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE, - *NI, tag, location, val, isPrevisit); - - // Update which NodeSet is the current one. - PrevSet = CurrSet; - } - - // Don't autotransition. The CheckerContext objects should do this - // automatically. -} -//===----------------------------------------------------------------------===// -// Engine construction and deletion. -//===----------------------------------------------------------------------===// - -static void RegisterInternalChecks(GRExprEngine &Eng) { - // Register internal "built-in" BugTypes with the BugReporter. These BugTypes - // are different than what probably many checks will do since they don't - // create BugReports on-the-fly but instead wait until GRExprEngine finishes - // analyzing a function. Generation of BugReport objects is done via a call - // to 'FlushReports' from BugReporter. - // The following checks do not need to have their associated BugTypes - // explicitly registered with the BugReporter. If they issue any BugReports, - // their associated BugType will get registered with the BugReporter - // automatically. Note that the check itself is owned by the GRExprEngine - // object. - RegisterAdjustedReturnValueChecker(Eng); - // CallAndMessageChecker should be registered before AttrNonNullChecker, - // where we assume arguments are not undefined. - RegisterCallAndMessageChecker(Eng); - RegisterAttrNonNullChecker(Eng); - RegisterDereferenceChecker(Eng); - RegisterVLASizeChecker(Eng); - RegisterDivZeroChecker(Eng); - RegisterReturnUndefChecker(Eng); - RegisterUndefinedArraySubscriptChecker(Eng); - RegisterUndefinedAssignmentChecker(Eng); - RegisterUndefBranchChecker(Eng); - RegisterUndefCapturedBlockVarChecker(Eng); - RegisterUndefResultChecker(Eng); - RegisterStackAddrLeakChecker(Eng); - RegisterObjCAtSyncChecker(Eng); - - // This is not a checker yet. - RegisterNoReturnFunctionChecker(Eng); - RegisterBuiltinFunctionChecker(Eng); - RegisterOSAtomicChecker(Eng); - RegisterUnixAPIChecker(Eng); - RegisterMacOSXAPIChecker(Eng); -} - -GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) - : AMgr(mgr), - CoreEngine(*this), - G(CoreEngine.getGraph()), - Builder(NULL), - StateMgr(getContext(), mgr.getStoreManagerCreator(), - mgr.getConstraintManagerCreator(), G.getAllocator(), - *this), - SymMgr(StateMgr.getSymbolManager()), - svalBuilder(StateMgr.getSValBuilder()), - EntryNode(NULL), currentStmt(NULL), - NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), - RaiseSel(GetNullarySelector("raise", getContext())), - BR(mgr, *this), TF(tf) { - // Register internal checks. - RegisterInternalChecks(*this); - - // FIXME: Eventually remove the TF object entirely. - TF->RegisterChecks(*this); - TF->RegisterPrinters(getStateManager().Printers); -} - -GRExprEngine::~GRExprEngine() { - BR.FlushReports(); - delete [] NSExceptionInstanceRaiseSelectors; - - // Delete the set of checkers. - for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) - delete I->second; - - for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end(); - I!=E;++I) - delete I->second; -} - -//===----------------------------------------------------------------------===// -// Utility methods. -//===----------------------------------------------------------------------===// - -const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { - const GRState *state = StateMgr.getInitialState(InitLoc); - - // Preconditions. - - // FIXME: It would be nice if we had a more general mechanism to add - // such preconditions. Some day. - do { - const Decl *D = InitLoc->getDecl(); - if (const FunctionDecl *FD = dyn_cast(D)) { - // Precondition: the first argument of 'main' is an integer guaranteed - // to be > 0. - const IdentifierInfo *II = FD->getIdentifier(); - if (!II || !(II->getName() == "main" && FD->getNumParams() > 0)) - break; - - const ParmVarDecl *PD = FD->getParamDecl(0); - QualType T = PD->getType(); - if (!T->isIntegerType()) - break; - - const MemRegion *R = state->getRegion(PD, InitLoc); - if (!R) - break; - - SVal V = state->getSVal(loc::MemRegionVal(R)); - SVal Constraint_untested = evalBinOp(state, BO_GT, V, - svalBuilder.makeZeroVal(T), - getContext().IntTy); - - DefinedOrUnknownSVal *Constraint = - dyn_cast(&Constraint_untested); - - if (!Constraint) - break; - - if (const GRState *newState = state->assume(*Constraint, true)) - state = newState; - - break; - } - - if (const ObjCMethodDecl *MD = dyn_cast(D)) { - // Precondition: 'self' is always non-null upon entry to an Objective-C - // method. - const ImplicitParamDecl *SelfD = MD->getSelfDecl(); - const MemRegion *R = state->getRegion(SelfD, InitLoc); - SVal V = state->getSVal(loc::MemRegionVal(R)); - - if (const Loc *LV = dyn_cast(&V)) { - // Assume that the pointer value in 'self' is non-null. - state = state->assume(*LV, true); - assert(state && "'self' cannot be null"); - } - } - } while (0); - - return state; -} - -//===----------------------------------------------------------------------===// -// Top-level transfer function logic (Dispatcher). -//===----------------------------------------------------------------------===// - -/// evalAssume - Called by ConstraintManager. Used to call checker-specific -/// logic for handling assumptions on symbolic values. -const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond, - bool assumption) { - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for processing assumptions. This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr NewCO; - - CallbackTag K = GetCallbackTag(ProcessAssumeCallback); - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // statement kind, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - if (!CO->empty()) { - // Let the checkers have a crack at the assume before the transfer functions - // get their turn. - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I!=E; ++I) { - - // If any checker declares the state infeasible (or if it starts that - // way), bail out. - if (!state) - return NULL; - - Checker *C = I->second; - bool respondsToCallback = true; - - state = C->evalAssume(state, cond, assumption, &respondsToCallback); - - // Check if we're building the cache of checkers that care about - // assumptions. - if (NewCO.get() && respondsToCallback) - NewCO->push_back(*I); - } - - // If we got through all the checkers, and we built a list of those that - // care about assumptions, save it. - if (NewCO.get()) - CO_Ref = NewCO.take(); - } - - // If the state is infeasible at this point, bail out. - if (!state) - return NULL; - - return TF->evalAssume(state, cond, assumption); -} - -bool GRExprEngine::WantsRegionChangeUpdate(const GRState* state) { - CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); - CheckersOrdered *CO = COCache[K]; - - if (!CO) - CO = &Checkers; - - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { - Checker *C = I->second; - if (C->WantsRegionChangeUpdate(state)) - return true; - } - - return false; -} - -const GRState * -GRExprEngine::ProcessRegionChanges(const GRState *state, - const MemRegion * const *Begin, - const MemRegion * const *End) { - // FIXME: Most of this method is copy-pasted from ProcessAssume. - - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for processing region changes. This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr NewCO; - - CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // callback, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - // If there are no checkers, just return the state as is. - if (CO->empty()) - return state; - - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { - // If any checker declares the state infeasible (or if it starts that way), - // bail out. - if (!state) - return NULL; - - Checker *C = I->second; - bool respondsToCallback = true; - - state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback); - - // See if we're building a cache of checkers that care about region changes. - if (NewCO.get() && respondsToCallback) - NewCO->push_back(*I); - } - - // If we got through all the checkers, and we built a list of those that - // care about region changes, save it. - if (NewCO.get()) - CO_Ref = NewCO.take(); - - return state; -} - -void GRExprEngine::ProcessEndWorklist(bool hasWorkRemaining) { - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - I->second->VisitEndAnalysis(G, BR, *this); - } -} - -void GRExprEngine::ProcessElement(const CFGElement E, - GRStmtNodeBuilder& builder) { - switch (E.getKind()) { - case CFGElement::Statement: - ProcessStmt(E.getAs(), builder); - break; - case CFGElement::Initializer: - ProcessInitializer(E.getAs(), builder); - break; - case CFGElement::ImplicitDtor: - ProcessImplicitDtor(E.getAs(), builder); - break; - default: - // Suppress compiler warning. - llvm_unreachable("Unexpected CFGElement kind."); - } -} - -void GRExprEngine::ProcessStmt(const CFGStmt S, GRStmtNodeBuilder& builder) { - currentStmt = S.getStmt(); - PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), - currentStmt->getLocStart(), - "Error evaluating statement"); - - Builder = &builder; - EntryNode = builder.getBasePredecessor(); - - // Create the cleaned state. - const LocationContext *LC = EntryNode->getLocationContext(); - SymbolReaper SymReaper(LC, currentStmt, SymMgr); - - if (AMgr.shouldPurgeDead()) { - const GRState *St = EntryNode->getState(); - - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - Checker *checker = I->second; - checker->MarkLiveSymbols(St, SymReaper); - } - - const StackFrameContext *SFC = LC->getCurrentStackFrame(); - CleanedState = StateMgr.RemoveDeadBindings(St, SFC, SymReaper); - } else { - CleanedState = EntryNode->getState(); - } - - // Process any special transfer function for dead symbols. - ExplodedNodeSet Tmp; - - if (!SymReaper.hasDeadSymbols()) - Tmp.Add(EntryNode); - else { - SaveAndRestore OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->HasGeneratedNode); - - SaveAndRestore OldPurgeDeadSymbols(Builder->PurgingDeadSymbols); - Builder->PurgingDeadSymbols = true; - - // FIXME: This should soon be removed. - ExplodedNodeSet Tmp2; - getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode, - CleanedState, SymReaper); - - if (Checkers.empty()) - Tmp.insert(Tmp2); - else { - ExplodedNodeSet Tmp3; - ExplodedNodeSet *SrcSet = &Tmp2; - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - ExplodedNodeSet *DstSet = 0; - if (I+1 == E) - DstSet = &Tmp; - else { - DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2; - DstSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); - NI != NE; ++NI) - checker->GR_evalDeadSymbols(*DstSet, *Builder, *this, currentStmt, - *NI, SymReaper, tag); - SrcSet = DstSet; - } - } - - if (!Builder->BuildSinks && !Builder->HasGeneratedNode) - Tmp.Add(EntryNode); - } - - bool HasAutoGenerated = false; - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - ExplodedNodeSet Dst; - - // Set the cleaned state. - Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I)); - - // Visit the statement. - Visit(currentStmt, *I, Dst); - - // Do we need to auto-generate a node? We only need to do this to generate - // a node with a "cleaned" state; GRCoreEngine will actually handle - // auto-transitions for other cases. - if (Dst.size() == 1 && *Dst.begin() == EntryNode - && !Builder->HasGeneratedNode && !HasAutoGenerated) { - HasAutoGenerated = true; - builder.generateNode(currentStmt, GetState(EntryNode), *I); - } - } - - // NULL out these variables to cleanup. - CleanedState = NULL; - EntryNode = NULL; - - currentStmt = 0; - - Builder = NULL; -} - -void GRExprEngine::ProcessInitializer(const CFGInitializer Init, - GRStmtNodeBuilder &builder) { - // We don't set EntryNode and currentStmt. And we don't clean up state. - const CXXBaseOrMemberInitializer *BMI = Init.getInitializer(); - - ExplodedNode *Pred = builder.getBasePredecessor(); - const LocationContext *LC = Pred->getLocationContext(); - - if (BMI->isAnyMemberInitializer()) { - ExplodedNodeSet Dst; - - // Evaluate the initializer. - Visit(BMI->getInit(), Pred, Dst); - - for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){ - ExplodedNode *Pred = *I; - const GRState *state = Pred->getState(); - - const FieldDecl *FD = BMI->getAnyMember(); - const RecordDecl *RD = FD->getParent(); - const CXXThisRegion *ThisR = getCXXThisRegion(cast(RD), - cast(LC)); - - SVal ThisV = state->getSVal(ThisR); - SVal FieldLoc = state->getLValue(FD, ThisV); - SVal InitVal = state->getSVal(BMI->getInit()); - state = state->bindLoc(FieldLoc, InitVal); - - // Use a custom node building process. - PostInitializer PP(BMI, LC); - // Builder automatically add the generated node to the deferred set, - // which are processed in the builder's dtor. - builder.generateNode(PP, state, Pred); - } - } -} - -void GRExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, - GRStmtNodeBuilder &builder) { - Builder = &builder; - - switch (D.getDtorKind()) { - case CFGElement::AutomaticObjectDtor: - ProcessAutomaticObjDtor(cast(D), builder); - break; - case CFGElement::BaseDtor: - ProcessBaseDtor(cast(D), builder); - break; - case CFGElement::MemberDtor: - ProcessMemberDtor(cast(D), builder); - break; - case CFGElement::TemporaryDtor: - ProcessTemporaryDtor(cast(D), builder); - break; - default: - llvm_unreachable("Unexpected dtor kind."); - } -} - -void GRExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor, - GRStmtNodeBuilder &builder) { - ExplodedNode *pred = builder.getBasePredecessor(); - const GRState *state = pred->getState(); - const VarDecl *varDecl = dtor.getVarDecl(); - - QualType varType = varDecl->getType(); - - if (const ReferenceType *refType = varType->getAs()) - varType = refType->getPointeeType(); - - const CXXRecordDecl *recordDecl = varType->getAsCXXRecordDecl(); - assert(recordDecl && "get CXXRecordDecl fail"); - const CXXDestructorDecl *dtorDecl = recordDecl->getDestructor(); - - Loc dest = state->getLValue(varDecl, pred->getLocationContext()); - - ExplodedNodeSet dstSet; - VisitCXXDestructor(dtorDecl, cast(dest).getRegion(), - dtor.getTriggerStmt(), pred, dstSet); -} - -void GRExprEngine::ProcessBaseDtor(const CFGBaseDtor D, - GRStmtNodeBuilder &builder) { -} - -void GRExprEngine::ProcessMemberDtor(const CFGMemberDtor D, - GRStmtNodeBuilder &builder) { -} - -void GRExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, - GRStmtNodeBuilder &builder) { -} - -void GRExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), - S->getLocStart(), - "Error evaluating statement"); - - // Expressions to ignore. - if (const Expr *Ex = dyn_cast(S)) - S = Ex->IgnoreParens(); - - // FIXME: add metadata to the CFG so that we can disable - // this check when we KNOW that there is no block-level subexpression. - // The motivation is that this check requires a hashtable lookup. - - if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) { - Dst.Add(Pred); - return; - } - - switch (S->getStmtClass()) { - // C++ stuff we don't support yet. - case Stmt::CXXBindTemporaryExprClass: - case Stmt::CXXCatchStmtClass: - case Stmt::CXXDefaultArgExprClass: - case Stmt::CXXDependentScopeMemberExprClass: - case Stmt::ExprWithCleanupsClass: - case Stmt::CXXNullPtrLiteralExprClass: - case Stmt::CXXPseudoDestructorExprClass: - case Stmt::CXXTemporaryObjectExprClass: - case Stmt::CXXThrowExprClass: - case Stmt::CXXTryStmtClass: - case Stmt::CXXTypeidExprClass: - case Stmt::CXXUuidofExprClass: - case Stmt::CXXUnresolvedConstructExprClass: - case Stmt::CXXScalarValueInitExprClass: - case Stmt::DependentScopeDeclRefExprClass: - case Stmt::UnaryTypeTraitExprClass: - case Stmt::BinaryTypeTraitExprClass: - case Stmt::UnresolvedLookupExprClass: - case Stmt::UnresolvedMemberExprClass: - case Stmt::CXXNoexceptExprClass: - { - SaveAndRestore OldSink(Builder->BuildSinks); - Builder->BuildSinks = true; - MakeNode(Dst, S, Pred, GetState(Pred)); - break; - } - - case Stmt::ParenExprClass: - llvm_unreachable("ParenExprs already handled."); - // Cases that should never be evaluated simply because they shouldn't - // appear in the CFG. - case Stmt::BreakStmtClass: - case Stmt::CaseStmtClass: - case Stmt::CompoundStmtClass: - case Stmt::ContinueStmtClass: - case Stmt::DefaultStmtClass: - case Stmt::DoStmtClass: - case Stmt::GotoStmtClass: - case Stmt::IndirectGotoStmtClass: - case Stmt::LabelStmtClass: - case Stmt::NoStmtClass: - case Stmt::NullStmtClass: - case Stmt::SwitchCaseClass: - case Stmt::OpaqueValueExprClass: - llvm_unreachable("Stmt should not be in analyzer evaluation loop"); - break; - - case Stmt::GNUNullExprClass: { - MakeNode(Dst, S, Pred, GetState(Pred)->BindExpr(S, svalBuilder.makeNull())); - break; - } - - case Stmt::ObjCAtSynchronizedStmtClass: - VisitObjCAtSynchronizedStmt(cast(S), Pred, Dst); - break; - - // Cases not handled yet; but will handle some day. - case Stmt::DesignatedInitExprClass: - case Stmt::ExtVectorElementExprClass: - case Stmt::ImaginaryLiteralClass: - case Stmt::ImplicitValueInitExprClass: - case Stmt::ObjCAtCatchStmtClass: - case Stmt::ObjCAtFinallyStmtClass: - case Stmt::ObjCAtTryStmtClass: - case Stmt::ObjCEncodeExprClass: - case Stmt::ObjCIsaExprClass: - case Stmt::ObjCPropertyRefExprClass: - case Stmt::ObjCProtocolExprClass: - case Stmt::ObjCSelectorExprClass: - case Stmt::ObjCStringLiteralClass: - case Stmt::ParenListExprClass: - case Stmt::PredefinedExprClass: - case Stmt::ShuffleVectorExprClass: - case Stmt::VAArgExprClass: - // Fall through. - - // Cases we intentionally don't evaluate, since they don't need - // to be explicitly evaluated. - case Stmt::AddrLabelExprClass: - case Stmt::IntegerLiteralClass: - case Stmt::CharacterLiteralClass: - case Stmt::CXXBoolLiteralExprClass: - case Stmt::FloatingLiteralClass: - Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. - break; - - case Stmt::ArraySubscriptExprClass: - VisitLvalArraySubscriptExpr(cast(S), Pred, Dst); - break; - - case Stmt::AsmStmtClass: - VisitAsmStmt(cast(S), Pred, Dst); - break; - - case Stmt::BlockDeclRefExprClass: { - const BlockDeclRefExpr *BE = cast(S); - VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst); - break; - } - - case Stmt::BlockExprClass: - VisitBlockExpr(cast(S), Pred, Dst); - break; - - case Stmt::BinaryOperatorClass: { - const BinaryOperator* B = cast(S); - if (B->isLogicalOp()) { - VisitLogicalExpr(B, Pred, Dst); - break; - } - else if (B->getOpcode() == BO_Comma) { - const GRState* state = GetState(Pred); - MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS()))); - break; - } - - if (AMgr.shouldEagerlyAssume() && - (B->isRelationalOp() || B->isEqualityOp())) { - ExplodedNodeSet Tmp; - VisitBinaryOperator(cast(S), Pred, Tmp); - evalEagerlyAssume(Dst, Tmp, cast(S)); - } - else - VisitBinaryOperator(cast(S), Pred, Dst); - - break; - } - - case Stmt::CallExprClass: { - const CallExpr* C = cast(S); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); - break; - } - - case Stmt::CXXConstructExprClass: { - const CXXConstructExpr *C = cast(S); - // For block-level CXXConstructExpr, we don't have a destination region. - // Let VisitCXXConstructExpr() create one. - VisitCXXConstructExpr(C, 0, Pred, Dst); - break; - } - - case Stmt::CXXMemberCallExprClass: { - const CXXMemberCallExpr *MCE = cast(S); - VisitCXXMemberCallExpr(MCE, Pred, Dst); - break; - } - - case Stmt::CXXOperatorCallExprClass: { - const CXXOperatorCallExpr *C = cast(S); - VisitCXXOperatorCallExpr(C, Pred, Dst); - break; - } - - case Stmt::CXXNewExprClass: { - const CXXNewExpr *NE = cast(S); - VisitCXXNewExpr(NE, Pred, Dst); - break; - } - - case Stmt::CXXDeleteExprClass: { - const CXXDeleteExpr *CDE = cast(S); - VisitCXXDeleteExpr(CDE, Pred, Dst); - break; - } - // FIXME: ChooseExpr is really a constant. We need to fix - // the CFG do not model them as explicit control-flow. - - case Stmt::ChooseExprClass: { // __builtin_choose_expr - const ChooseExpr* C = cast(S); - VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); - break; - } - - case Stmt::CompoundAssignOperatorClass: - VisitBinaryOperator(cast(S), Pred, Dst); - break; - - case Stmt::CompoundLiteralExprClass: - VisitCompoundLiteralExpr(cast(S), Pred, Dst); - break; - - case Stmt::ConditionalOperatorClass: { // '?' operator - const ConditionalOperator* C = cast(S); - VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); - break; - } - - case Stmt::CXXThisExprClass: - VisitCXXThisExpr(cast(S), Pred, Dst); - break; - - case Stmt::DeclRefExprClass: { - const DeclRefExpr *DE = cast(S); - VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst); - break; - } - - case Stmt::DeclStmtClass: - VisitDeclStmt(cast(S), Pred, Dst); - break; - - case Stmt::ForStmtClass: - // This case isn't for branch processing, but for handling the - // initialization of a condition variable. - VisitCondInit(cast(S)->getConditionVariable(), S, Pred, Dst); - break; - - case Stmt::ImplicitCastExprClass: - case Stmt::CStyleCastExprClass: - case Stmt::CXXStaticCastExprClass: - case Stmt::CXXDynamicCastExprClass: - case Stmt::CXXReinterpretCastExprClass: - case Stmt::CXXConstCastExprClass: - case Stmt::CXXFunctionalCastExprClass: { - const CastExpr* C = cast(S); - VisitCast(C, C->getSubExpr(), Pred, Dst); - break; - } - - case Stmt::IfStmtClass: - // This case isn't for branch processing, but for handling the - // initialization of a condition variable. - VisitCondInit(cast(S)->getConditionVariable(), S, Pred, Dst); - break; - - case Stmt::InitListExprClass: - VisitInitListExpr(cast(S), Pred, Dst); - break; - - case Stmt::MemberExprClass: - VisitMemberExpr(cast(S), Pred, Dst); - break; - case Stmt::ObjCIvarRefExprClass: - VisitLvalObjCIvarRefExpr(cast(S), Pred, Dst); - break; - - case Stmt::ObjCForCollectionStmtClass: - VisitObjCForCollectionStmt(cast(S), Pred, Dst); - break; - - case Stmt::ObjCMessageExprClass: - VisitObjCMessageExpr(cast(S), Pred, Dst); - break; - - case Stmt::ObjCAtThrowStmtClass: { - // FIXME: This is not complete. We basically treat @throw as - // an abort. - SaveAndRestore OldSink(Builder->BuildSinks); - Builder->BuildSinks = true; - MakeNode(Dst, S, Pred, GetState(Pred)); - break; - } - - case Stmt::ReturnStmtClass: - VisitReturnStmt(cast(S), Pred, Dst); - break; - - case Stmt::OffsetOfExprClass: - VisitOffsetOfExpr(cast(S), Pred, Dst); - break; - - case Stmt::SizeOfAlignOfExprClass: - VisitSizeOfAlignOfExpr(cast(S), Pred, Dst); - break; - - case Stmt::StmtExprClass: { - const StmtExpr* SE = cast(S); - - if (SE->getSubStmt()->body_empty()) { - // Empty statement expression. - assert(SE->getType() == getContext().VoidTy - && "Empty statement expression must have void type."); - Dst.Add(Pred); - break; - } - - if (Expr* LastExpr = dyn_cast(*SE->getSubStmt()->body_rbegin())) { - const GRState* state = GetState(Pred); - MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr))); - } - else - Dst.Add(Pred); - - break; - } - - case Stmt::StringLiteralClass: { - const GRState* state = GetState(Pred); - SVal V = state->getLValue(cast(S)); - MakeNode(Dst, S, Pred, state->BindExpr(S, V)); - return; - } - - case Stmt::SwitchStmtClass: - // This case isn't for branch processing, but for handling the - // initialization of a condition variable. - VisitCondInit(cast(S)->getConditionVariable(), S, Pred, Dst); - break; - - case Stmt::UnaryOperatorClass: { - const UnaryOperator *U = cast(S); - if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) { - ExplodedNodeSet Tmp; - VisitUnaryOperator(U, Pred, Tmp); - evalEagerlyAssume(Dst, Tmp, U); - } - else - VisitUnaryOperator(U, Pred, Dst); - break; - } - - case Stmt::WhileStmtClass: - // This case isn't for branch processing, but for handling the - // initialization of a condition variable. - VisitCondInit(cast(S)->getConditionVariable(), S, Pred, Dst); - break; - } -} - -//===----------------------------------------------------------------------===// -// Block entrance. (Update counters). -//===----------------------------------------------------------------------===// - -bool GRExprEngine::ProcessBlockEntrance(const CFGBlock* B, - const ExplodedNode *Pred, - GRBlockCounter BC) { - return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(), - B->getBlockID()) < AMgr.getMaxVisit(); -} - -//===----------------------------------------------------------------------===// -// Generic node creation. -//===----------------------------------------------------------------------===// - -ExplodedNode* GRExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, - ExplodedNode* Pred, const GRState* St, - ProgramPoint::Kind K, const void *tag) { - assert (Builder && "GRStmtNodeBuilder not present."); - SaveAndRestore OldTag(Builder->Tag); - Builder->Tag = tag; - return Builder->MakeNode(Dst, S, Pred, St, K); -} - -//===----------------------------------------------------------------------===// -// Branch processing. -//===----------------------------------------------------------------------===// - -const GRState* GRExprEngine::MarkBranch(const GRState* state, - const Stmt* Terminator, - bool branchTaken) { - - switch (Terminator->getStmtClass()) { - default: - return state; - - case Stmt::BinaryOperatorClass: { // '&&' and '||' - - const BinaryOperator* B = cast(Terminator); - BinaryOperator::Opcode Op = B->getOpcode(); - - assert (Op == BO_LAnd || Op == BO_LOr); - - // For &&, if we take the true branch, then the value of the whole - // expression is that of the RHS expression. - // - // For ||, if we take the false branch, then the value of the whole - // expression is that of the RHS expression. - - const Expr* Ex = (Op == BO_LAnd && branchTaken) || - (Op == BO_LOr && !branchTaken) - ? B->getRHS() : B->getLHS(); - - return state->BindExpr(B, UndefinedVal(Ex)); - } - - case Stmt::ConditionalOperatorClass: { // ?: - - const ConditionalOperator* C = cast(Terminator); - - // For ?, if branchTaken == true then the value is either the LHS or - // the condition itself. (GNU extension). - - const Expr* Ex; - - if (branchTaken) - Ex = C->getLHS() ? C->getLHS() : C->getCond(); - else - Ex = C->getRHS(); - - return state->BindExpr(C, UndefinedVal(Ex)); - } - - case Stmt::ChooseExprClass: { // ?: - - const ChooseExpr* C = cast(Terminator); - - const Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); - return state->BindExpr(C, UndefinedVal(Ex)); - } - } -} - -/// RecoverCastedSymbol - A helper function for ProcessBranch that is used -/// to try to recover some path-sensitivity for casts of symbolic -/// integers that promote their values (which are currently not tracked well). -/// This function returns the SVal bound to Condition->IgnoreCasts if all the -// cast(s) did was sign-extend the original value. -static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state, - const Stmt* Condition, ASTContext& Ctx) { - - const Expr *Ex = dyn_cast(Condition); - if (!Ex) - return UnknownVal(); - - uint64_t bits = 0; - bool bitsInit = false; - - while (const CastExpr *CE = dyn_cast(Ex)) { - QualType T = CE->getType(); - - if (!T->isIntegerType()) - return UnknownVal(); - - uint64_t newBits = Ctx.getTypeSize(T); - if (!bitsInit || newBits < bits) { - bitsInit = true; - bits = newBits; - } - - Ex = CE->getSubExpr(); - } - - // We reached a non-cast. Is it a symbolic value? - QualType T = Ex->getType(); - - if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits) - return UnknownVal(); - - return state->getSVal(Ex); -} - -void GRExprEngine::ProcessBranch(const Stmt* Condition, const Stmt* Term, - GRBranchNodeBuilder& builder) { - - // Check for NULL conditions; e.g. "for(;;)" - if (!Condition) { - builder.markInfeasible(false); - return; - } - - PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), - Condition->getLocStart(), - "Error evaluating branch"); - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - checker->VisitBranchCondition(builder, *this, Condition, tag); - } - - // If the branch condition is undefined, return; - if (!builder.isFeasible(true) && !builder.isFeasible(false)) - return; - - const GRState* PrevState = builder.getState(); - SVal X = PrevState->getSVal(Condition); - - if (X.isUnknown()) { - // Give it a chance to recover from unknown. - if (const Expr *Ex = dyn_cast(Condition)) { - if (Ex->getType()->isIntegerType()) { - // Try to recover some path-sensitivity. Right now casts of symbolic - // integers that promote their values are currently not tracked well. - // If 'Condition' is such an expression, try and recover the - // underlying value and use that instead. - SVal recovered = RecoverCastedSymbol(getStateManager(), - builder.getState(), Condition, - getContext()); - - if (!recovered.isUnknown()) { - X = recovered; - } - } - } - // If the condition is still unknown, give up. - if (X.isUnknown()) { - builder.generateNode(MarkBranch(PrevState, Term, true), true); - builder.generateNode(MarkBranch(PrevState, Term, false), false); - return; - } - } - - DefinedSVal V = cast(X); - - // Process the true branch. - if (builder.isFeasible(true)) { - if (const GRState *state = PrevState->assume(V, true)) - builder.generateNode(MarkBranch(state, Term, true), true); - else - builder.markInfeasible(true); - } - - // Process the false branch. - if (builder.isFeasible(false)) { - if (const GRState *state = PrevState->assume(V, false)) - builder.generateNode(MarkBranch(state, Term, false), false); - else - builder.markInfeasible(false); - } -} - -/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor -/// nodes by processing the 'effects' of a computed goto jump. -void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { - - const GRState *state = builder.getState(); - SVal V = state->getSVal(builder.getTarget()); - - // Three possibilities: - // - // (1) We know the computed label. - // (2) The label is NULL (or some other constant), or Undefined. - // (3) We have no clue about the label. Dispatch to all targets. - // - - typedef GRIndirectGotoNodeBuilder::iterator iterator; - - if (isa(V)) { - const LabelStmt* L = cast(V).getLabel(); - - for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) { - if (I.getLabel() == L) { - builder.generateNode(I, state); - return; - } - } - - assert (false && "No block with label."); - return; - } - - if (isa(V) || isa(V)) { - // Dispatch to the first target and mark it as a sink. - //ExplodedNode* N = builder.generateNode(builder.begin(), state, true); - // FIXME: add checker visit. - // UndefBranches.insert(N); - return; - } - - // This is really a catch-all. We don't support symbolics yet. - // FIXME: Implement dispatch for symbolic pointers. - - for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) - builder.generateNode(I, state); -} - - -void GRExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L, - const Expr* R, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { - - assert(Ex == currentStmt && - Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); - - const GRState* state = GetState(Pred); - SVal X = state->getSVal(Ex); - - assert (X.isUndef()); - - const Expr *SE = (Expr*) cast(X).getData(); - assert(SE); - X = state->getSVal(SE); - - // Make sure that we invalidate the previous binding. - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true)); -} - -/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path -/// nodes when the control reaches the end of a function. -void GRExprEngine::ProcessEndPath(GREndPathNodeBuilder& builder) { - getTF().evalEndPath(*this, builder); - StateMgr.EndPath(builder.getState()); - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ - void *tag = I->first; - Checker *checker = I->second; - checker->evalEndPath(builder, tag, *this); - } -} - -/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor -/// nodes by processing the 'effects' of a switch statement. -void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { - typedef GRSwitchNodeBuilder::iterator iterator; - const GRState* state = builder.getState(); - const Expr* CondE = builder.getCondition(); - SVal CondV_untested = state->getSVal(CondE); - - if (CondV_untested.isUndef()) { - //ExplodedNode* N = builder.generateDefaultCaseNode(state, true); - // FIXME: add checker - //UndefBranches.insert(N); - - return; - } - DefinedOrUnknownSVal CondV = cast(CondV_untested); - - const GRState *DefaultSt = state; - - iterator I = builder.begin(), EI = builder.end(); - bool defaultIsFeasible = I == EI; - - for ( ; I != EI; ++I) { - const CaseStmt* Case = I.getCase(); - - // Evaluate the LHS of the case value. - Expr::EvalResult V1; - bool b = Case->getLHS()->Evaluate(V1, getContext()); - - // Sanity checks. These go away in Release builds. - assert(b && V1.Val.isInt() && !V1.HasSideEffects - && "Case condition must evaluate to an integer constant."); - b = b; // silence unused variable warning - assert(V1.Val.getInt().getBitWidth() == - getContext().getTypeSize(CondE->getType())); - - // Get the RHS of the case, if it exists. - Expr::EvalResult V2; - - if (const Expr* E = Case->getRHS()) { - b = E->Evaluate(V2, getContext()); - assert(b && V2.Val.isInt() && !V2.HasSideEffects - && "Case condition must evaluate to an integer constant."); - b = b; // silence unused variable warning - } - else - V2 = V1; - - // FIXME: Eventually we should replace the logic below with a range - // comparison, rather than concretize the values within the range. - // This should be easy once we have "ranges" for NonLVals. - - do { - nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt())); - DefinedOrUnknownSVal Res = svalBuilder.evalEQ(DefaultSt ? DefaultSt : state, - CondV, CaseVal); - - // Now "assume" that the case matches. - if (const GRState* stateNew = state->assume(Res, true)) { - builder.generateCaseStmtNode(I, stateNew); - - // If CondV evaluates to a constant, then we know that this - // is the *only* case that we can take, so stop evaluating the - // others. - if (isa(CondV)) - return; - } - - // Now "assume" that the case doesn't match. Add this state - // to the default state (if it is feasible). - if (DefaultSt) { - if (const GRState *stateNew = DefaultSt->assume(Res, false)) { - defaultIsFeasible = true; - DefaultSt = stateNew; - } - else { - defaultIsFeasible = false; - DefaultSt = NULL; - } - } - - // Concretize the next value in the range. - if (V1.Val.getInt() == V2.Val.getInt()) - break; - - ++V1.Val.getInt(); - assert (V1.Val.getInt() <= V2.Val.getInt()); - - } while (true); - } - - if (!defaultIsFeasible) - return; - - // If we have switch(enum value), the default branch is not - // feasible if all of the enum constants not covered by 'case:' statements - // are not feasible values for the switch condition. - // - // Note that this isn't as accurate as it could be. Even if there isn't - // a case for a particular enum value as long as that enum value isn't - // feasible then it shouldn't be considered for making 'default:' reachable. - const SwitchStmt *SS = builder.getSwitch(); - const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts(); - if (CondExpr->getType()->getAs()) { - if (SS->isAllEnumCasesCovered()) - return; - } - - builder.generateDefaultCaseNode(DefaultSt); -} - -void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) { - const GRState *state = B.getState()->EnterStackFrame(B.getCalleeContext()); - B.generateNode(state); -} - -void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { - const GRState *state = B.getState(); - const ExplodedNode *Pred = B.getPredecessor(); - const StackFrameContext *calleeCtx = - cast(Pred->getLocationContext()); - const Stmt *CE = calleeCtx->getCallSite(); - - // If the callee returns an expression, bind its value to CallExpr. - const Stmt *ReturnedExpr = state->get(); - if (ReturnedExpr) { - SVal RetVal = state->getSVal(ReturnedExpr); - state = state->BindExpr(CE, RetVal); - // Clear the return expr GDM. - state = state->remove(); - } - - // Bind the constructed object value to CXXConstructExpr. - if (const CXXConstructExpr *CCE = dyn_cast(CE)) { - const CXXThisRegion *ThisR = - getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); - - SVal ThisV = state->getSVal(ThisR); - // Always bind the region to the CXXConstructExpr. - state = state->BindExpr(CCE, ThisV); - } - - B.generateNode(state); -} - -//===----------------------------------------------------------------------===// -// Transfer functions: logical operations ('&&', '||'). -//===----------------------------------------------------------------------===// - -void GRExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - assert(B->getOpcode() == BO_LAnd || - B->getOpcode() == BO_LOr); - - assert(B==currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); - - const GRState* state = GetState(Pred); - SVal X = state->getSVal(B); - assert(X.isUndef()); - - const Expr *Ex = (const Expr*) cast(X).getData(); - assert(Ex); - - if (Ex == B->getRHS()) { - X = state->getSVal(Ex); - - // Handle undefined values. - if (X.isUndef()) { - MakeNode(Dst, B, Pred, state->BindExpr(B, X)); - return; - } - - DefinedOrUnknownSVal XD = cast(X); - - // We took the RHS. Because the value of the '&&' or '||' expression must - // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0 - // or 1. Alternatively, we could take a lazy approach, and calculate this - // value later when necessary. We don't have the machinery in place for - // this right now, and since most logical expressions are used for branches, - // the payoff is not likely to be large. Instead, we do eager evaluation. - if (const GRState *newState = state->assume(XD, true)) - MakeNode(Dst, B, Pred, - newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType()))); - - if (const GRState *newState = state->assume(XD, false)) - MakeNode(Dst, B, Pred, - newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType()))); - } - else { - // We took the LHS expression. Depending on whether we are '&&' or - // '||' we know what the value of the expression is via properties of - // the short-circuiting. - X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U, - B->getType()); - MakeNode(Dst, B, Pred, state->BindExpr(B, X)); - } -} - -//===----------------------------------------------------------------------===// -// Transfer functions: Loads and stores. -//===----------------------------------------------------------------------===// - -void GRExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - - ExplodedNodeSet Tmp; - - CanQualType T = getContext().getCanonicalType(BE->getType()); - SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T, - Pred->getLocationContext()); - - MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V), - ProgramPoint::PostLValueKind); - - // Post-visit the BlockExpr. - CheckerVisit(BE, Dst, Tmp, PostVisitStmtCallback); -} - -void GRExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - const GRState *state = GetState(Pred); - - if (const VarDecl* VD = dyn_cast(D)) { - assert(Ex->isLValue()); - SVal V = state->getLValue(VD, Pred->getLocationContext()); - - // For references, the 'lvalue' is the pointer address stored in the - // reference region. - if (VD->getType()->isReferenceType()) { - if (const MemRegion *R = V.getAsRegion()) - V = state->getSVal(R); - else - V = UnknownVal(); - } - - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), - ProgramPoint::PostLValueKind); - return; - } - if (const EnumConstantDecl* ED = dyn_cast(D)) { - assert(!Ex->isLValue()); - SVal V = svalBuilder.makeIntVal(ED->getInitVal()); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V)); - return; - } - if (const FunctionDecl* FD = dyn_cast(D)) { - SVal V = svalBuilder.getFunctionPointer(FD); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), - ProgramPoint::PostLValueKind); - return; - } - assert (false && - "ValueDecl support for this ValueDecl not implemented."); -} - -/// VisitArraySubscriptExpr - Transfer function for array accesses -void GRExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A, - ExplodedNode* Pred, - ExplodedNodeSet& Dst){ - - const Expr* Base = A->getBase()->IgnoreParens(); - const Expr* Idx = A->getIdx()->IgnoreParens(); - - // Evaluate the base. - ExplodedNodeSet Tmp; - Visit(Base, Pred, Tmp); - - for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) { - ExplodedNodeSet Tmp2; - Visit(Idx, *I1, Tmp2); // Evaluate the index. - ExplodedNodeSet Tmp3; - CheckerVisit(A, Tmp3, Tmp2, PreVisitStmtCallback); - - for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) { - const GRState* state = GetState(*I2); - SVal V = state->getLValue(A->getType(), state->getSVal(Idx), - state->getSVal(Base)); - assert(A->isLValue()); - MakeNode(Dst, A, *I2, state->BindExpr(A, V), ProgramPoint::PostLValueKind); - } - } -} - -/// VisitMemberExpr - Transfer function for member expressions. -void GRExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - Expr *baseExpr = M->getBase()->IgnoreParens(); - ExplodedNodeSet dstBase; - Visit(baseExpr, Pred, dstBase); - - FieldDecl *field = dyn_cast(M->getMemberDecl()); - if (!field) // FIXME: skipping member expressions for non-fields - return; - - for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end(); - I != E; ++I) { - const GRState* state = GetState(*I); - SVal baseExprVal = state->getSVal(baseExpr); - if (isa(baseExprVal) || - isa(baseExprVal)) { - MakeNode(Dst, M, *I, state->BindExpr(M, UnknownVal())); - continue; - } - - // FIXME: Should we insert some assumption logic in here to determine - // if "Base" is a valid piece of memory? Before we put this assumption - // later when using FieldOffset lvals (which we no longer have). - - // For all other cases, compute an lvalue. - SVal L = state->getLValue(field, baseExprVal); - if (M->isLValue()) - MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind); - else - evalLoad(Dst, M, *I, state, L); - } -} - -/// evalBind - Handle the semantics of binding a value to a specific location. -/// This method is used by evalStore and (soon) VisitDeclStmt, and others. -void GRExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, - ExplodedNode* Pred, const GRState* state, - SVal location, SVal Val, bool atDeclInit) { - - - // Do a previsit of the bind. - ExplodedNodeSet CheckedSet, Src; - Src.Add(Pred); - CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true); - - for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); - I!=E; ++I) { - - if (Pred != *I) - state = GetState(*I); - - const GRState* newState = 0; - - if (atDeclInit) { - const VarRegion *VR = - cast(cast(location).getRegion()); - - newState = state->bindDecl(VR, Val); - } - else { - if (location.isUnknown()) { - // We know that the new state will be the same as the old state since - // the location of the binding is "unknown". Consequently, there - // is no reason to just create a new node. - newState = state; - } - else { - // We are binding to a value other than 'unknown'. Perform the binding - // using the StoreManager. - newState = state->bindLoc(cast(location), Val); - } - } - - // 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. - - // NOTE: We use 'AssignE' for the location of the PostStore if 'AssignE' - // is non-NULL. Checkers typically care about - - GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE, - true); - - getTF().evalBind(BuilderRef, location, Val); - } -} - -/// evalStore - Handle the semantics of a store via an assignment. -/// @param Dst The node set to store generated state nodes -/// @param AssignE The assignment expression if the store happens in an -/// assignment. -/// @param LocatioinE The location expression that is stored to. -/// @param state The current simulation state -/// @param location The location to store the value -/// @param Val The value to be stored -void GRExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE, - const Expr* LocationE, - ExplodedNode* Pred, - const GRState* state, SVal location, SVal Val, - const void *tag) { - - assert(Builder && "GRStmtNodeBuilder must be defined."); - - // Evaluate the location (checks for bad dereferences). - ExplodedNodeSet Tmp; - evalLocation(Tmp, LocationE, Pred, state, location, tag, false); - - if (Tmp.empty()) - return; - - assert(!location.isUndef()); - - SaveAndRestore OldSPointKind(Builder->PointKind, - ProgramPoint::PostStoreKind); - SaveAndRestore OldTag(Builder->Tag, tag); - - // Proceed with the store. We use AssignE as the anchor for the PostStore - // ProgramPoint if it is non-NULL, and LocationE otherwise. - const Expr *StoreE = AssignE ? AssignE : LocationE; - - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - evalBind(Dst, StoreE, *NI, GetState(*NI), location, Val); -} - -void GRExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex, - ExplodedNode* Pred, - const GRState* state, SVal location, - const void *tag, QualType LoadTy) { - assert(!isa(location) && "location cannot be a NonLoc."); - - // Are we loading from a region? This actually results in two loads; one - // to fetch the address of the referenced value and one to fetch the - // referenced value. - if (const TypedRegion *TR = - dyn_cast_or_null(location.getAsRegion())) { - - QualType ValTy = TR->getValueType(); - if (const ReferenceType *RT = ValTy->getAs()) { - static int loadReferenceTag = 0; - ExplodedNodeSet Tmp; - evalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag, - getContext().getPointerType(RT->getPointeeType())); - - // Perform the load from the referenced value. - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) { - state = GetState(*I); - location = state->getSVal(Ex); - evalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy); - } - return; - } - } - - evalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy); -} - -void GRExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex, - ExplodedNode* Pred, - const GRState* state, SVal location, - const void *tag, QualType LoadTy) { - - // Evaluate the location (checks for bad dereferences). - ExplodedNodeSet Tmp; - evalLocation(Tmp, Ex, Pred, state, location, tag, true); - - if (Tmp.empty()) - return; - - assert(!location.isUndef()); - - SaveAndRestore OldSPointKind(Builder->PointKind); - SaveAndRestore OldTag(Builder->Tag); - - // Proceed with the load. - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { - state = GetState(*NI); - - if (location.isUnknown()) { - // This is important. We must nuke the old binding. - MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()), - ProgramPoint::PostLoadKind, tag); - } - else { - if (LoadTy.isNull()) - LoadTy = Ex->getType(); - SVal V = state->getSVal(cast(location), LoadTy); - MakeNode(Dst, Ex, *NI, state->bindExprAndLocation(Ex, location, V), - ProgramPoint::PostLoadKind, tag); - } - } -} - -void GRExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, - ExplodedNode* Pred, - const GRState* state, SVal location, - const void *tag, bool isLoad) { - // Early checks for performance reason. - if (location.isUnknown() || Checkers.empty()) { - Dst.Add(Pred); - return; - } - - ExplodedNodeSet Src, Tmp; - Src.Add(Pred); - ExplodedNodeSet *PrevSet = &Src; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) { - // Use the 'state' argument only when the predecessor node is the - // same as Pred. This allows us to catch updates to the state. - checker->GR_visitLocation(*CurrSet, *Builder, *this, S, *NI, - *NI == Pred ? state : GetState(*NI), - location, tag, isLoad); - } - - // Update which NodeSet is the current one. - PrevSet = CurrSet; - } -} - -bool GRExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, - ExplodedNode *Pred) { - const GRState *state = GetState(Pred); - const Expr *Callee = CE->getCallee(); - SVal L = state->getSVal(Callee); - - const FunctionDecl *FD = L.getAsFunctionDecl(); - if (!FD) - return false; - - // Check if the function definition is in the same translation unit. - if (FD->hasBody(FD)) { - const StackFrameContext *stackFrame = - AMgr.getStackFrame(AMgr.getAnalysisContext(FD), - Pred->getLocationContext(), - CE, Builder->getBlock(), Builder->getIndex()); - // Now we have the definition of the callee, create a CallEnter node. - CallEnter Loc(CE, stackFrame, Pred->getLocationContext()); - - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - Dst.Add(N); - return true; - } - - // Check if we can find the function definition in other translation units. - if (AMgr.hasIndexer()) { - AnalysisContext *C = AMgr.getAnalysisContextInAnotherTU(FD); - if (C == 0) - return false; - const StackFrameContext *stackFrame = - AMgr.getStackFrame(C, Pred->getLocationContext(), - CE, Builder->getBlock(), Builder->getIndex()); - CallEnter Loc(CE, stackFrame, Pred->getLocationContext()); - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - Dst.Add(N); - return true; - } - - return false; -} - -void GRExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred, - CallExpr::const_arg_iterator AI, - CallExpr::const_arg_iterator AE, - ExplodedNodeSet& Dst) { - - // Determine the type of function we're calling (if available). - const FunctionProtoType *Proto = NULL; - QualType FnType = CE->getCallee()->IgnoreParens()->getType(); - if (const PointerType *FnTypePtr = FnType->getAs()) - Proto = FnTypePtr->getPointeeType()->getAs(); - - // Evaluate the arguments. - ExplodedNodeSet ArgsEvaluated; - evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated); - - // Now process the call itself. - ExplodedNodeSet DstTmp; - const Expr* Callee = CE->getCallee()->IgnoreParens(); - - for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(), - NE=ArgsEvaluated.end(); NI != NE; ++NI) { - // Evaluate the callee. - ExplodedNodeSet DstTmp2; - Visit(Callee, *NI, DstTmp2); - // Perform the previsit of the CallExpr, storing the results in DstTmp. - CheckerVisit(CE, DstTmp, DstTmp2, PreVisitStmtCallback); - } - - // Finally, evaluate the function call. We try each of the checkers - // to see if the can evaluate the function call. - ExplodedNodeSet DstTmp3; - - for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); - DI != DE; ++DI) { - - const GRState* state = GetState(*DI); - SVal L = state->getSVal(Callee); - - // FIXME: Add support for symbolic function calls (calls involving - // function pointer values that are symbolic). - SaveAndRestore OldSink(Builder->BuildSinks); - ExplodedNodeSet DstChecker; - - // If the callee is processed by a checker, skip the rest logic. - if (CheckerEvalCall(CE, DstChecker, *DI)) - DstTmp3.insert(DstChecker); - else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) { - // Callee is inlined. We shouldn't do post call checking. - return; - } - else { - for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), - DE_Checker = DstChecker.end(); - DI_Checker != DE_Checker; ++DI_Checker) { - - // Dispatch to the plug-in transfer function. - unsigned oldSize = DstTmp3.size(); - SaveOr OldHasGen(Builder->HasGeneratedNode); - Pred = *DI_Checker; - - // Dispatch to transfer function logic to handle the call itself. - // FIXME: Allow us to chain together transfer functions. - assert(Builder && "GRStmtNodeBuilder must be defined."); - getTF().evalCall(DstTmp3, *this, *Builder, CE, L, Pred); - - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && DstTmp3.size() == oldSize && - !Builder->HasGeneratedNode) - MakeNode(DstTmp3, CE, Pred, state); - } - } - } - - // Finally, perform the post-condition check of the CallExpr and store - // the created nodes in 'Dst'. - CheckerVisit(CE, Dst, DstTmp3, PostVisitStmtCallback); -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C ivar references. -//===----------------------------------------------------------------------===// - -static std::pair EagerlyAssumeTag - = std::pair(&EagerlyAssumeTag,static_cast(0)); - -void GRExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, - const Expr *Ex) { - for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { - ExplodedNode *Pred = *I; - - // Test if the previous node was as the same expression. This can happen - // when the expression fails to evaluate to anything meaningful and - // (as an optimization) we don't generate a node. - ProgramPoint P = Pred->getLocation(); - if (!isa(P) || cast(P).getStmt() != Ex) { - Dst.Add(Pred); - continue; - } - - const GRState* state = GetState(Pred); - SVal V = state->getSVal(Ex); - if (nonloc::SymExprVal *SEV = dyn_cast(&V)) { - // First assume that the condition is true. - if (const GRState *stateTrue = state->assume(*SEV, true)) { - stateTrue = stateTrue->BindExpr(Ex, - svalBuilder.makeIntVal(1U, Ex->getType())); - Dst.Add(Builder->generateNode(PostStmtCustom(Ex, - &EagerlyAssumeTag, Pred->getLocationContext()), - stateTrue, Pred)); - } - - // Next, assume that the condition is false. - if (const GRState *stateFalse = state->assume(*SEV, false)) { - stateFalse = stateFalse->BindExpr(Ex, - svalBuilder.makeIntVal(0U, Ex->getType())); - Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag, - Pred->getLocationContext()), - stateFalse, Pred)); - } - } - else - Dst.Add(Pred); - } -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C @synchronized. -//===----------------------------------------------------------------------===// - -void GRExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - - // The mutex expression is a CFGElement, so we don't need to explicitly - // visit it since it will already be processed. - - // Pre-visit the ObjCAtSynchronizedStmt. - ExplodedNodeSet Tmp; - Tmp.Add(Pred); - CheckerVisit(S, Dst, Tmp, PreVisitStmtCallback); -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C ivar references. -//===----------------------------------------------------------------------===// - -void GRExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - // Visit the base expression, which is needed for computing the lvalue - // of the ivar. - ExplodedNodeSet dstBase; - const Expr *baseExpr = Ex->getBase(); - Visit(baseExpr, Pred, dstBase); - - // Using the base, compute the lvalue of the instance variable. - for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end(); - I!=E; ++I) { - ExplodedNode *nodeBase = *I; - const GRState *state = GetState(nodeBase); - SVal baseVal = state->getSVal(baseExpr); - SVal location = state->getLValue(Ex->getDecl(), baseVal); - MakeNode(Dst, Ex, *I, state->BindExpr(Ex, location)); - } -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C fast enumeration 'for' statements. -//===----------------------------------------------------------------------===// - -void GRExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { - - // ObjCForCollectionStmts are processed in two places. This method - // handles the case where an ObjCForCollectionStmt* occurs as one of the - // statements within a basic block. This transfer function does two things: - // - // (1) binds the next container value to 'element'. This creates a new - // node in the ExplodedGraph. - // - // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating - // whether or not the container has any more elements. This value - // will be tested in ProcessBranch. We need to explicitly bind - // this value because a container can contain nil elements. - // - // FIXME: Eventually this logic should actually do dispatches to - // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration). - // This will require simulating a temporary NSFastEnumerationState, either - // through an SVal or through the use of MemRegions. This value can - // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop - // terminates we reclaim the temporary (it goes out of scope) and we - // we can test if the SVal is 0 or if the MemRegion is null (depending - // on what approach we take). - // - // For now: simulate (1) by assigning either a symbol or nil if the - // container is empty. Thus this transfer function will by default - // result in state splitting. - - const Stmt* elem = S->getElement(); - SVal ElementV; - - if (const DeclStmt* DS = dyn_cast(elem)) { - const VarDecl* ElemD = cast(DS->getSingleDecl()); - assert (ElemD->getInit() == 0); - ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext()); - VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV); - return; - } - - ExplodedNodeSet Tmp; - Visit(cast(elem), Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem)); - } -} - -void GRExprEngine::VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S, - ExplodedNode* Pred, ExplodedNodeSet& Dst, - SVal ElementV) { - - // Check if the location we are writing back to is a null pointer. - const Stmt* elem = S->getElement(); - ExplodedNodeSet Tmp; - evalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false); - - if (Tmp.empty()) - return; - - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { - Pred = *NI; - const GRState *state = GetState(Pred); - - // Handle the case where the container still has elements. - SVal TrueV = svalBuilder.makeTruthVal(1); - const GRState *hasElems = state->BindExpr(S, TrueV); - - // Handle the case where the container has no elements. - SVal FalseV = svalBuilder.makeTruthVal(0); - const GRState *noElems = state->BindExpr(S, FalseV); - - if (loc::MemRegionVal* MV = dyn_cast(&ElementV)) - if (const TypedRegion* R = dyn_cast(MV->getRegion())) { - // FIXME: The proper thing to do is to really iterate over the - // container. We will do this with dispatch logic to the store. - // For now, just 'conjure' up a symbolic value. - QualType T = R->getValueType(); - assert(Loc::IsLocType(T)); - unsigned Count = Builder->getCurrentBlockCount(); - SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count); - SVal V = svalBuilder.makeLoc(Sym); - hasElems = hasElems->bindLoc(ElementV, V); - - // Bind the location to 'nil' on the false branch. - SVal nilV = svalBuilder.makeIntVal(0, T); - noElems = noElems->bindLoc(ElementV, nilV); - } - - // Create the new nodes. - MakeNode(Dst, S, Pred, hasElems); - MakeNode(Dst, S, Pred, noElems); - } -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C message expressions. -//===----------------------------------------------------------------------===// - -namespace { -class ObjCMsgWLItem { -public: - ObjCMessageExpr::const_arg_iterator I; - ExplodedNode *N; - - ObjCMsgWLItem(const ObjCMessageExpr::const_arg_iterator &i, ExplodedNode *n) - : I(i), N(n) {} -}; -} // end anonymous namespace - -void GRExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, - ExplodedNode* Pred, - ExplodedNodeSet& Dst){ - - // Create a worklist to process both the arguments. - llvm::SmallVector WL; - - // But first evaluate the receiver (if any). - ObjCMessageExpr::const_arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); - if (const Expr *Receiver = ME->getInstanceReceiver()) { - ExplodedNodeSet Tmp; - Visit(Receiver, Pred, Tmp); - - if (Tmp.empty()) - return; - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) - WL.push_back(ObjCMsgWLItem(AI, *I)); - } - else - WL.push_back(ObjCMsgWLItem(AI, Pred)); - - // Evaluate the arguments. - ExplodedNodeSet ArgsEvaluated; - while (!WL.empty()) { - ObjCMsgWLItem Item = WL.back(); - WL.pop_back(); - - if (Item.I == AE) { - ArgsEvaluated.insert(Item.N); - continue; - } - - // Evaluate the subexpression. - ExplodedNodeSet Tmp; - - // FIXME: [Objective-C++] handle arguments that are references - Visit(*Item.I, Item.N, Tmp); - - // Enqueue evaluating the next argument on the worklist. - ++(Item.I); - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - WL.push_back(ObjCMsgWLItem(Item.I, *NI)); - } - - // Now that the arguments are processed, handle the previsits checks. - ExplodedNodeSet DstPrevisit; - CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback); - - // Proceed with evaluate the message expression. - ExplodedNodeSet dstEval; - - for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(), - DE = DstPrevisit.end(); DI != DE; ++DI) { - - Pred = *DI; - bool RaisesException = false; - unsigned oldSize = dstEval.size(); - SaveAndRestore OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->HasGeneratedNode); - - if (const Expr *Receiver = ME->getInstanceReceiver()) { - const GRState *state = GetState(Pred); - - // Bifurcate the state into nil and non-nil ones. - DefinedOrUnknownSVal receiverVal = - cast(state->getSVal(Receiver)); - - const GRState *notNilState, *nilState; - llvm::tie(notNilState, nilState) = state->assume(receiverVal); - - // There are three cases: can be nil or non-nil, must be nil, must be - // non-nil. We handle must be nil, and merge the rest two into non-nil. - if (nilState && !notNilState) { - CheckerEvalNilReceiver(ME, dstEval, nilState, Pred); - continue; - } - - // Check if the "raise" message was sent. - assert(notNilState); - if (ME->getSelector() == RaiseSel) - RaisesException = true; - - // Check if we raise an exception. For now treat these as sinks. - // Eventually we will want to handle exceptions properly. - if (RaisesException) - Builder->BuildSinks = true; - - // Dispatch to plug-in transfer function. - evalObjCMessageExpr(dstEval, ME, Pred, notNilState); - } - else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) { - IdentifierInfo* ClsName = Iface->getIdentifier(); - Selector S = ME->getSelector(); - - // Check for special instance methods. - if (!NSExceptionII) { - ASTContext& Ctx = getContext(); - NSExceptionII = &Ctx.Idents.get("NSException"); - } - - if (ClsName == NSExceptionII) { - enum { NUM_RAISE_SELECTORS = 2 }; - - // Lazily create a cache of the selectors. - if (!NSExceptionInstanceRaiseSelectors) { - ASTContext& Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = - new Selector[NUM_RAISE_SELECTORS]; - llvm::SmallVector II; - unsigned idx = 0; - - // raise:format: - II.push_back(&Ctx.Idents.get("raise")); - II.push_back(&Ctx.Idents.get("format")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - - // raise:format::arguments: - II.push_back(&Ctx.Idents.get("arguments")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - } - - for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) - if (S == NSExceptionInstanceRaiseSelectors[i]) { - RaisesException = true; - break; - } - } - - // Check if we raise an exception. For now treat these as sinks. - // Eventually we will want to handle exceptions properly. - if (RaisesException) - Builder->BuildSinks = true; - - // Dispatch to plug-in transfer function. - evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred)); - } - - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && dstEval.size() == oldSize && - !Builder->HasGeneratedNode) - MakeNode(dstEval, ME, Pred, GetState(Pred)); - } - - // Finally, perform the post-condition check of the ObjCMessageExpr and store - // the created nodes in 'Dst'. - CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback); -} - -//===----------------------------------------------------------------------===// -// Transfer functions: Miscellaneous statements. -//===----------------------------------------------------------------------===// - -void GRExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, - ExplodedNode *Pred, ExplodedNodeSet &Dst) { - - ExplodedNodeSet S1; - Visit(Ex, Pred, S1); - ExplodedNodeSet S2; - CheckerVisit(CastE, S2, S1, PreVisitStmtCallback); - - if (CastE->getCastKind() == CK_LValueToRValue) { - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I!=E; ++I) { - ExplodedNode *subExprNode = *I; - const GRState *state = GetState(subExprNode); - evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex)); - } - return; - } - - // All other casts. - QualType T = CastE->getType(); - QualType ExTy = Ex->getType(); - - if (const ExplicitCastExpr *ExCast=dyn_cast_or_null(CastE)) - T = ExCast->getTypeAsWritten(); - -#if 0 - // If we are evaluating the cast in an lvalue context, we implicitly want - // the cast to evaluate to a location. - if (asLValue) { - ASTContext &Ctx = getContext(); - T = Ctx.getPointerType(Ctx.getCanonicalType(T)); - ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy)); - } -#endif - - switch (CastE->getCastKind()) { - case CK_ToVoid: - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) - Dst.Add(*I); - return; - - case CK_LValueToRValue: - case CK_NoOp: - case CK_FunctionToPointerDecay: - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - // Copy the SVal of Ex to CastE. - ExplodedNode *N = *I; - const GRState *state = GetState(N); - SVal V = state->getSVal(Ex); - state = state->BindExpr(CastE, V); - MakeNode(Dst, CastE, N, state); - } - return; - - case CK_GetObjCProperty: - case CK_Dependent: - case CK_ArrayToPointerDecay: - case CK_BitCast: - case CK_LValueBitCast: - case CK_IntegralCast: - case CK_NullToPointer: - case CK_IntegralToPointer: - case CK_PointerToIntegral: - case CK_PointerToBoolean: - case CK_IntegralToBoolean: - case CK_IntegralToFloating: - case CK_FloatingToIntegral: - case CK_FloatingToBoolean: - case CK_FloatingCast: - case CK_FloatingRealToComplex: - case CK_FloatingComplexToReal: - case CK_FloatingComplexToBoolean: - case CK_FloatingComplexCast: - case CK_FloatingComplexToIntegralComplex: - case CK_IntegralRealToComplex: - case CK_IntegralComplexToReal: - case CK_IntegralComplexToBoolean: - case CK_IntegralComplexCast: - case CK_IntegralComplexToFloatingComplex: - case CK_AnyPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - - case CK_ObjCObjectLValueCast: { - // Delegate to SValBuilder to process. - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - ExplodedNode* N = *I; - const GRState* state = GetState(N); - SVal V = state->getSVal(Ex); - V = svalBuilder.evalCast(V, T, ExTy); - state = state->BindExpr(CastE, V); - MakeNode(Dst, CastE, N, state); - } - return; - } - - case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: - // For DerivedToBase cast, delegate to the store manager. - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - ExplodedNode *node = *I; - const GRState *state = GetState(node); - SVal val = state->getSVal(Ex); - val = getStoreManager().evalDerivedToBase(val, T); - state = state->BindExpr(CastE, val); - MakeNode(Dst, CastE, node, state); - } - return; - - // Various C++ casts that are not handled yet. - case CK_Dynamic: - case CK_ToUnion: - case CK_BaseToDerived: - case CK_NullToMemberPointer: - case CK_BaseToDerivedMemberPointer: - case CK_DerivedToBaseMemberPointer: - case CK_UserDefinedConversion: - case CK_ConstructorConversion: - case CK_VectorSplat: - case CK_MemberPointerToBoolean: { - SaveAndRestore OldSink(Builder->BuildSinks); - Builder->BuildSinks = true; - MakeNode(Dst, CastE, Pred, GetState(Pred)); - return; - } - } -} - -void GRExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - const InitListExpr* ILE - = cast(CL->getInitializer()->IgnoreParens()); - ExplodedNodeSet Tmp; - Visit(ILE, Pred, Tmp); - - for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) { - const GRState* state = GetState(*I); - SVal ILV = state->getSVal(ILE); - const LocationContext *LC = (*I)->getLocationContext(); - state = state->bindCompoundLiteral(CL, LC, ILV); - - if (CL->isLValue()) { - MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC))); - } - else - MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV)); - } -} - -void GRExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, - ExplodedNodeSet& Dst) { - - // The CFG has one DeclStmt per Decl. - const Decl* D = *DS->decl_begin(); - - if (!D || !isa(D)) - return; - - const VarDecl* VD = dyn_cast(D); - const Expr* InitEx = VD->getInit(); - - // FIXME: static variables may have an initializer, but the second - // time a function is called those values may not be current. - ExplodedNodeSet Tmp; - - if (InitEx) { - if (VD->getType()->isReferenceType() && !InitEx->isLValue()) { - // If the initializer is C++ record type, it should already has a - // temp object. - if (!InitEx->getType()->isRecordType()) - CreateCXXTemporaryObject(InitEx, Pred, Tmp); - else - Tmp.Add(Pred); - } else - Visit(InitEx, Pred, Tmp); - } else - Tmp.Add(Pred); - - ExplodedNodeSet Tmp2; - CheckerVisit(DS, Tmp2, Tmp, PreVisitStmtCallback); - - for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) { - ExplodedNode *N = *I; - const GRState *state = GetState(N); - - // Decls without InitExpr are not initialized explicitly. - const LocationContext *LC = N->getLocationContext(); - - if (InitEx) { - SVal InitVal = state->getSVal(InitEx); - - // We bound the temp obj region to the CXXConstructExpr. Now recover - // the lazy compound value when the variable is not a reference. - if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() && - !VD->getType()->isReferenceType() && isa(InitVal)){ - InitVal = state->getSVal(cast(InitVal).getRegion()); - assert(isa(InitVal)); - } - - // Recover some path-sensitivity if a scalar value evaluated to - // UnknownVal. - if ((InitVal.isUnknown() || - !getConstraintManager().canReasonAbout(InitVal)) && - !VD->getType()->isReferenceType()) { - InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, - Builder->getCurrentBlockCount()); - } - - evalBind(Dst, DS, *I, state, - loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); - } - else { - state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); - MakeNode(Dst, DS, *I, state); - } - } -} - -void GRExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S, - ExplodedNode *Pred, ExplodedNodeSet& Dst) { - - const Expr* InitEx = VD->getInit(); - ExplodedNodeSet Tmp; - Visit(InitEx, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - ExplodedNode *N = *I; - const GRState *state = GetState(N); - - const LocationContext *LC = N->getLocationContext(); - SVal InitVal = state->getSVal(InitEx); - - // Recover some path-sensitivity if a scalar value evaluated to - // UnknownVal. - if (InitVal.isUnknown() || - !getConstraintManager().canReasonAbout(InitVal)) { - InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, - Builder->getCurrentBlockCount()); - } - - evalBind(Dst, S, N, state, - loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); - } -} - -namespace { - // This class is used by VisitInitListExpr as an item in a worklist - // for processing the values contained in an InitListExpr. -class InitListWLItem { -public: - llvm::ImmutableList Vals; - ExplodedNode* N; - InitListExpr::const_reverse_iterator Itr; - - InitListWLItem(ExplodedNode* n, llvm::ImmutableList vals, - InitListExpr::const_reverse_iterator itr) - : Vals(vals), N(n), Itr(itr) {} -}; -} - - -void GRExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - const GRState* state = GetState(Pred); - QualType T = getContext().getCanonicalType(E->getType()); - unsigned NumInitElements = E->getNumInits(); - - if (T->isArrayType() || T->isRecordType() || T->isVectorType()) { - llvm::ImmutableList StartVals = getBasicVals().getEmptySValList(); - - // Handle base case where the initializer has no elements. - // e.g: static int* myArray[] = {}; - if (NumInitElements == 0) { - SVal V = svalBuilder.makeCompoundVal(T, StartVals); - MakeNode(Dst, E, Pred, state->BindExpr(E, V)); - return; - } - - // Create a worklist to process the initializers. - llvm::SmallVector WorkList; - WorkList.reserve(NumInitElements); - WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin())); - InitListExpr::const_reverse_iterator ItrEnd = E->rend(); - assert(!(E->rbegin() == E->rend())); - - // Process the worklist until it is empty. - while (!WorkList.empty()) { - InitListWLItem X = WorkList.back(); - WorkList.pop_back(); - - ExplodedNodeSet Tmp; - Visit(*X.Itr, X.N, Tmp); - - InitListExpr::const_reverse_iterator NewItr = X.Itr + 1; - - for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) { - // Get the last initializer value. - state = GetState(*NI); - SVal InitV = state->getSVal(cast(*X.Itr)); - - // Construct the new list of values by prepending the new value to - // the already constructed list. - llvm::ImmutableList NewVals = - getBasicVals().consVals(InitV, X.Vals); - - if (NewItr == ItrEnd) { - // Now we have a list holding all init values. Make CompoundValData. - SVal V = svalBuilder.makeCompoundVal(T, NewVals); - - // Make final state and node. - MakeNode(Dst, E, *NI, state->BindExpr(E, V)); - } - else { - // Still some initializer values to go. Push them onto the worklist. - WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr)); - } - } - } - - return; - } - - if (Loc::IsLocType(T) || T->isIntegerType()) { - assert (E->getNumInits() == 1); - ExplodedNodeSet Tmp; - const Expr* Init = E->getInit(0); - Visit(Init, Pred, Tmp); - for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) { - state = GetState(*I); - MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init))); - } - return; - } - - assert(0 && "unprocessed InitListExpr type"); -} - -/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type). -void GRExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - QualType T = Ex->getTypeOfArgument(); - CharUnits amt; - - if (Ex->isSizeOf()) { - if (T == getContext().VoidTy) { - // sizeof(void) == 1 byte. - amt = CharUnits::One(); - } - else if (!T->isConstantSizeType()) { - assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); - - // FIXME: Add support for VLA type arguments, not just VLA expressions. - // When that happens, we should probably refactor VLASizeChecker's code. - if (Ex->isArgumentType()) { - Dst.Add(Pred); - return; - } - - // Get the size by getting the extent of the sub-expression. - // First, visit the sub-expression to find its region. - const Expr *Arg = Ex->getArgumentExpr(); - ExplodedNodeSet Tmp; - Visit(Arg, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - const MemRegion *MR = state->getSVal(Arg).getAsRegion(); - - // If the subexpression can't be resolved to a region, we don't know - // anything about its size. Just leave the state as is and continue. - if (!MR) { - Dst.Add(*I); - continue; - } - - // The result is the extent of the VLA. - SVal Extent = cast(MR)->getExtent(svalBuilder); - MakeNode(Dst, Ex, *I, state->BindExpr(Ex, Extent)); - } - - return; - } - else if (T->getAs()) { - // Some code tries to take the sizeof an ObjCObjectType, relying that - // the compiler has laid out its representation. Just report Unknown - // for these. - Dst.Add(Pred); - return; - } - else { - // All other cases. - amt = getContext().getTypeSizeInChars(T); - } - } - else // Get alignment of the type. - amt = getContext().getTypeAlignInChars(T); - - MakeNode(Dst, Ex, Pred, - GetState(Pred)->BindExpr(Ex, - svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType()))); -} - -void GRExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { - Expr::EvalResult Res; - if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { - const APSInt &IV = Res.Val.getInt(); - assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); - assert(OOE->getType()->isIntegerType()); - assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); - SVal X = svalBuilder.makeIntVal(IV); - MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X)); - return; - } - // FIXME: Handle the case where __builtin_offsetof is not a constant. - Dst.Add(Pred); -} - -void GRExprEngine::VisitUnaryOperator(const UnaryOperator* U, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - switch (U->getOpcode()) { - - default: - break; - - case UO_Real: { - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - - // FIXME: We don't have complex SValues yet. - if (Ex->getType()->isAnyComplexType()) { - // Just report "Unknown." - Dst.Add(*I); - continue; - } - - // For all other types, UO_Real is an identity operation. - assert (U->getType() == Ex->getType()); - const GRState* state = GetState(*I); - MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); - } - - return; - } - - case UO_Imag: { - - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - // FIXME: We don't have complex SValues yet. - if (Ex->getType()->isAnyComplexType()) { - // Just report "Unknown." - Dst.Add(*I); - continue; - } - - // For all other types, UO_Imag returns 0. - const GRState* state = GetState(*I); - SVal X = svalBuilder.makeZeroVal(Ex->getType()); - MakeNode(Dst, U, *I, state->BindExpr(U, X)); - } - - return; - } - - case UO_Plus: - assert(!U->isLValue()); - // FALL-THROUGH. - case UO_Deref: - case UO_AddrOf: - case UO_Extension: { - - // Unary "+" is a no-op, similar to a parentheses. We still have places - // where it may be a block-level expression, so we need to - // generate an extra node that just propagates the value of the - // subexpression. - - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); - } - - return; - } - - case UO_LNot: - case UO_Minus: - case UO_Not: { - assert (!U->isLValue()); - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - - // Get the value of the subexpression. - SVal V = state->getSVal(Ex); - - if (V.isUnknownOrUndef()) { - MakeNode(Dst, U, *I, state->BindExpr(U, V)); - continue; - } - -// QualType DstT = getContext().getCanonicalType(U->getType()); -// QualType SrcT = getContext().getCanonicalType(Ex->getType()); -// -// if (DstT != SrcT) // Perform promotions. -// V = evalCast(V, DstT); -// -// if (V.isUnknownOrUndef()) { -// MakeNode(Dst, U, *I, BindExpr(St, U, V)); -// continue; -// } - - switch (U->getOpcode()) { - default: - assert(false && "Invalid Opcode."); - break; - - case UO_Not: - // FIXME: Do we need to handle promotions? - state = state->BindExpr(U, evalComplement(cast(V))); - break; - - case UO_Minus: - // FIXME: Do we need to handle promotions? - state = state->BindExpr(U, evalMinus(cast(V))); - break; - - case UO_LNot: - - // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." - // - // Note: technically we do "E == 0", but this is the same in the - // transfer functions as "0 == E". - SVal Result; - - if (isa(V)) { - Loc X = svalBuilder.makeNull(); - Result = evalBinOp(state, BO_EQ, cast(V), X, - U->getType()); - } - else { - nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType())); - Result = evalBinOp(state, BO_EQ, cast(V), X, - U->getType()); - } - - state = state->BindExpr(U, Result); - - break; - } - - MakeNode(Dst, U, *I, state); - } - - return; - } - } - - // Handle ++ and -- (both pre- and post-increment). - assert (U->isIncrementDecrementOp()); - ExplodedNodeSet Tmp; - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { - - const GRState* state = GetState(*I); - SVal loc = state->getSVal(Ex); - - // Perform a load. - ExplodedNodeSet Tmp2; - evalLoad(Tmp2, Ex, *I, state, loc); - - for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) { - - state = GetState(*I2); - SVal V2_untested = state->getSVal(Ex); - - // Propagate unknown and undefined values. - if (V2_untested.isUnknownOrUndef()) { - MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested)); - continue; - } - DefinedSVal V2 = cast(V2_untested); - - // Handle all other values. - BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add - : BO_Sub; - - // If the UnaryOperator has non-location type, use its type to create the - // constant value. If the UnaryOperator has location type, create the - // constant with int type and pointer width. - SVal RHS; - - if (U->getType()->isAnyPointerType()) - RHS = svalBuilder.makeIntValWithPtrWidth(1, false); - else - RHS = svalBuilder.makeIntVal(1, U->getType()); - - SVal Result = evalBinOp(state, Op, V2, RHS, U->getType()); - - // Conjure a new symbol if necessary to recover precision. - if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){ - DefinedOrUnknownSVal SymVal = - svalBuilder.getConjuredSymbolVal(NULL, Ex, - Builder->getCurrentBlockCount()); - Result = SymVal; - - // 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. - if (Loc::IsLocType(U->getType())) { - DefinedOrUnknownSVal Constraint = - svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType())); - - if (!state->assume(Constraint, true)) { - // It isn't feasible for the original value to be null. - // Propagate this constraint. - Constraint = svalBuilder.evalEQ(state, SymVal, - svalBuilder.makeZeroVal(U->getType())); - - - state = state->assume(Constraint, false); - assert(state); - } - } - } - - // Since the lvalue-to-rvalue conversion is explicit in the AST, - // we bind an l-value if the operator is prefix and an lvalue (in C++). - if (U->isPrefix() && U->isLValue()) - state = state->BindExpr(U, loc); - else - state = state->BindExpr(U, V2); - - // Perform the store. - evalStore(Dst, NULL, U, *I2, state, loc, Result); - } - } -} - -void GRExprEngine::VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); -} - -void GRExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A, - AsmStmt::const_outputs_iterator I, - AsmStmt::const_outputs_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { - if (I == E) { - VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst); - return; - } - - ExplodedNodeSet Tmp; - Visit(*I, Pred, Tmp); - ++I; - - for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI) - VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst); -} - -void GRExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A, - AsmStmt::const_inputs_iterator I, - AsmStmt::const_inputs_iterator E, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - if (I == E) { - - // We have processed both the inputs and the outputs. All of the outputs - // should evaluate to Locs. Nuke all of their values. - - // FIXME: Some day in the future it would be nice to allow a "plug-in" - // which interprets the inline asm and stores proper results in the - // outputs. - - const GRState* state = GetState(Pred); - - for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(), - OE = A->end_outputs(); OI != OE; ++OI) { - - SVal X = state->getSVal(*OI); - assert (!isa(X)); // Should be an Lval, or unknown, undef. - - if (isa(X)) - state = state->bindLoc(cast(X), UnknownVal()); - } - - MakeNode(Dst, A, Pred, state); - return; - } - - ExplodedNodeSet Tmp; - Visit(*I, Pred, Tmp); - - ++I; - - for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI!=NE; ++NI) - VisitAsmStmtHelperInputs(A, I, E, *NI, Dst); -} - -void GRExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - ExplodedNodeSet Src; - if (const Expr *RetE = RS->getRetValue()) { - // Record the returned expression in the state. It will be used in - // ProcessCallExit to bind the return value to the call expr. - { - static int Tag = 0; - SaveAndRestore OldTag(Builder->Tag, &Tag); - const GRState *state = GetState(Pred); - state = state->set(RetE); - Pred = Builder->generateNode(RetE, state, Pred); - } - // We may get a NULL Pred because we generated a cached node. - if (Pred) - Visit(RetE, Pred, Src); - } - else { - Src.Add(Pred); - } - - ExplodedNodeSet CheckedSet; - CheckerVisit(RS, CheckedSet, Src, PreVisitStmtCallback); - - for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); - I != E; ++I) { - - assert(Builder && "GRStmtNodeBuilder must be defined."); - - Pred = *I; - unsigned size = Dst.size(); - - SaveAndRestore OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->HasGeneratedNode); - - getTF().evalReturn(Dst, *this, *Builder, RS, Pred); - - // Handle the case where no nodes where generated. - if (!Builder->BuildSinks && Dst.size() == size && - !Builder->HasGeneratedNode) - MakeNode(Dst, RS, Pred, GetState(Pred)); - } -} - -//===----------------------------------------------------------------------===// -// Transfer functions: Binary operators. -//===----------------------------------------------------------------------===// - -void GRExprEngine::VisitBinaryOperator(const BinaryOperator* B, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - ExplodedNodeSet Tmp1; - Expr* LHS = B->getLHS()->IgnoreParens(); - Expr* RHS = B->getRHS()->IgnoreParens(); - - Visit(LHS, Pred, Tmp1); - ExplodedNodeSet Tmp3; - - for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { - SVal LeftV = GetState(*I1)->getSVal(LHS); - ExplodedNodeSet Tmp2; - Visit(RHS, *I1, Tmp2); - - ExplodedNodeSet CheckedSet; - CheckerVisit(B, CheckedSet, Tmp2, PreVisitStmtCallback); - - // With both the LHS and RHS evaluated, process the operation itself. - - for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end(); - I2 != E2; ++I2) { - - const GRState *state = GetState(*I2); - SVal RightV = state->getSVal(RHS); - - BinaryOperator::Opcode Op = B->getOpcode(); - - if (Op == BO_Assign) { - // EXPERIMENTAL: "Conjured" symbols. - // FIXME: Handle structs. - QualType T = RHS->getType(); - - if (RightV.isUnknown() ||!getConstraintManager().canReasonAbout(RightV)) - { - unsigned Count = Builder->getCurrentBlockCount(); - RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count); - } - - SVal ExprVal = B->isLValue() ? LeftV : RightV; - - // Simulate the effects of a "store": bind the value of the RHS - // to the L-Value represented by the LHS. - evalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), 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()) { - MakeNode(Tmp3, B, *I2, state); - continue; - } - - state = state->BindExpr(B, Result); - - MakeNode(Tmp3, B, *I2, state); - continue; - } - - assert (B->isCompoundAssignmentOp()); - - switch (Op) { - default: - assert(0 && "Invalid opcode for compound assignment."); - case BO_MulAssign: Op = BO_Mul; break; - case BO_DivAssign: Op = BO_Div; break; - case BO_RemAssign: Op = BO_Rem; break; - case BO_AddAssign: Op = BO_Add; break; - case BO_SubAssign: Op = BO_Sub; break; - case BO_ShlAssign: Op = BO_Shl; break; - case BO_ShrAssign: Op = BO_Shr; break; - case BO_AndAssign: Op = BO_And; break; - case BO_XorAssign: Op = BO_Xor; break; - case BO_OrAssign: Op = BO_Or; break; - } - - // Perform a load (the LHS). This performs the checks for - // null dereferences, and so on. - ExplodedNodeSet Tmp4; - SVal location = state->getSVal(LHS); - evalLoad(Tmp4, LHS, *I2, state, location); - - for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4; - ++I4) { - state = GetState(*I4); - SVal V = state->getSVal(LHS); - - // Get the computation type. - QualType CTy = - cast(B)->getComputationResultType(); - CTy = getContext().getCanonicalType(CTy); - - QualType CLHSTy = - cast(B)->getComputationLHSType(); - CLHSTy = getContext().getCanonicalType(CLHSTy); - - QualType LTy = getContext().getCanonicalType(LHS->getType()); - QualType RTy = getContext().getCanonicalType(RHS->getType()); - - // Promote LHS. - V = svalBuilder.evalCast(V, CLHSTy, LTy); - - // Compute the result of the operation. - SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy), - B->getType(), CTy); - - // EXPERIMENTAL: "Conjured" symbols. - // FIXME: Handle structs. - - SVal LHSVal; - - if (Result.isUnknown() || - !getConstraintManager().canReasonAbout(Result)) { - - unsigned Count = Builder->getCurrentBlockCount(); - - // The symbolic value is actually for the type of the left-hand side - // expression, not the computation type, as this is the value the - // LValue on the LHS will bind to. - LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count); - - // However, we need to convert the symbol to the computation type. - Result = svalBuilder.evalCast(LHSVal, CTy, LTy); - } - else { - // The left-hand side may bind to a different value then the - // computation type. - LHSVal = svalBuilder.evalCast(Result, LTy, CTy); - } - - evalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result), - location, LHSVal); - } - } - } - - CheckerVisit(B, Dst, Tmp3, PostVisitStmtCallback); -} - -//===----------------------------------------------------------------------===// -// Checker registration/lookup. -//===----------------------------------------------------------------------===// - -Checker *GRExprEngine::lookupChecker(void *tag) const { - CheckerMap::const_iterator I = CheckerM.find(tag); - return (I == CheckerM.end()) ? NULL : Checkers[I->second].second; -} - -//===----------------------------------------------------------------------===// -// Visualization. -//===----------------------------------------------------------------------===// - -#ifndef NDEBUG -static GRExprEngine* GraphPrintCheckerState; -static SourceManager* GraphPrintSourceManager; - -namespace llvm { -template<> -struct DOTGraphTraits : - public DefaultDOTGraphTraits { - - DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} - - // FIXME: Since we do not cache error nodes in GRExprEngine now, this does not - // work. - static std::string getNodeAttributes(const ExplodedNode* N, void*) { - -#if 0 - // FIXME: Replace with a general scheme to tell if the node is - // an error node. - if (GraphPrintCheckerState->isImplicitNullDeref(N) || - GraphPrintCheckerState->isExplicitNullDeref(N) || - GraphPrintCheckerState->isUndefDeref(N) || - GraphPrintCheckerState->isUndefStore(N) || - GraphPrintCheckerState->isUndefControlFlow(N) || - GraphPrintCheckerState->isUndefResult(N) || - GraphPrintCheckerState->isBadCall(N) || - GraphPrintCheckerState->isUndefArg(N)) - return "color=\"red\",style=\"filled\""; - - if (GraphPrintCheckerState->isNoReturnCall(N)) - return "color=\"blue\",style=\"filled\""; -#endif - return ""; - } - - static std::string getNodeLabel(const ExplodedNode* N, void*){ - - std::string sbuf; - llvm::raw_string_ostream Out(sbuf); - - // Program Location. - ProgramPoint Loc = N->getLocation(); - - switch (Loc.getKind()) { - case ProgramPoint::BlockEntranceKind: - Out << "Block Entrance: B" - << cast(Loc).getBlock()->getBlockID(); - break; - - case ProgramPoint::BlockExitKind: - assert (false); - break; - - case ProgramPoint::CallEnterKind: - Out << "CallEnter"; - break; - - case ProgramPoint::CallExitKind: - Out << "CallExit"; - break; - - default: { - if (StmtPoint *L = dyn_cast(&Loc)) { - const Stmt* S = L->getStmt(); - SourceLocation SLoc = S->getLocStart(); - - Out << S->getStmtClassName() << ' ' << (void*) S << ' '; - LangOptions LO; // FIXME. - S->printPretty(Out, 0, PrintingPolicy(LO)); - - if (SLoc.isFileID()) { - Out << "\\lline=" - << GraphPrintSourceManager->getInstantiationLineNumber(SLoc) - << " col=" - << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc) - << "\\l"; - } - - if (isa(Loc)) - Out << "\\lPreStmt\\l;"; - else if (isa(Loc)) - Out << "\\lPostLoad\\l;"; - else if (isa(Loc)) - Out << "\\lPostStore\\l"; - else if (isa(Loc)) - Out << "\\lPostLValue\\l"; - -#if 0 - // FIXME: Replace with a general scheme to determine - // the name of the check. - if (GraphPrintCheckerState->isImplicitNullDeref(N)) - Out << "\\|Implicit-Null Dereference.\\l"; - else if (GraphPrintCheckerState->isExplicitNullDeref(N)) - Out << "\\|Explicit-Null Dereference.\\l"; - else if (GraphPrintCheckerState->isUndefDeref(N)) - Out << "\\|Dereference of undefialied value.\\l"; - else if (GraphPrintCheckerState->isUndefStore(N)) - Out << "\\|Store to Undefined Loc."; - else if (GraphPrintCheckerState->isUndefResult(N)) - Out << "\\|Result of operation is undefined."; - else if (GraphPrintCheckerState->isNoReturnCall(N)) - Out << "\\|Call to function marked \"noreturn\"."; - else if (GraphPrintCheckerState->isBadCall(N)) - Out << "\\|Call to NULL/Undefined."; - else if (GraphPrintCheckerState->isUndefArg(N)) - Out << "\\|Argument in call is undefined"; -#endif - - break; - } - - const BlockEdge& E = cast(Loc); - Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" - << E.getDst()->getBlockID() << ')'; - - if (const Stmt* T = E.getSrc()->getTerminator()) { - - SourceLocation SLoc = T->getLocStart(); - - Out << "\\|Terminator: "; - LangOptions LO; // FIXME. - E.getSrc()->printTerminator(Out, LO); - - if (SLoc.isFileID()) { - Out << "\\lline=" - << GraphPrintSourceManager->getInstantiationLineNumber(SLoc) - << " col=" - << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc); - } - - if (isa(T)) { - const Stmt* Label = E.getDst()->getLabel(); - - if (Label) { - if (const CaseStmt* C = dyn_cast(Label)) { - Out << "\\lcase "; - LangOptions LO; // FIXME. - C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO)); - - if (const Stmt* RHS = C->getRHS()) { - Out << " .. "; - RHS->printPretty(Out, 0, PrintingPolicy(LO)); - } - - Out << ":"; - } - else { - assert (isa(Label)); - Out << "\\ldefault:"; - } - } - else - Out << "\\l(implicit) default:"; - } - else if (isa(T)) { - // FIXME - } - else { - Out << "\\lCondition: "; - if (*E.getSrc()->succ_begin() == E.getDst()) - Out << "true"; - else - Out << "false"; - } - - Out << "\\l"; - } - -#if 0 - // FIXME: Replace with a general scheme to determine - // the name of the check. - if (GraphPrintCheckerState->isUndefControlFlow(N)) { - Out << "\\|Control-flow based on\\lUndefined value.\\l"; - } -#endif - } - } - - const GRState *state = N->getState(); - Out << "\\|StateID: " << (void*) state - << " NodeID: " << (void*) N << "\\|"; - state->printDOT(Out, *N->getLocationContext()->getCFG()); - Out << "\\l"; - return Out.str(); - } -}; -} // end llvm namespace -#endif - -#ifndef NDEBUG -template -ExplodedNode* GetGraphNode(ITERATOR I) { return *I; } - -template <> ExplodedNode* -GetGraphNode::iterator> - (llvm::DenseMap::iterator I) { - return I->first; -} -#endif - -void GRExprEngine::ViewGraph(bool trim) { -#ifndef NDEBUG - if (trim) { - std::vector Src; - - // Flush any outstanding reports to make sure we cover all the nodes. - // This does not cause them to get displayed. - for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) - const_cast(*I)->FlushReports(BR); - - // Iterate through the reports and get their nodes. - for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) { - for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end(); - I2!=E2; ++I2) { - const BugReportEquivClass& EQ = *I2; - const BugReport &R = **EQ.begin(); - ExplodedNode *N = const_cast(R.getErrorNode()); - if (N) Src.push_back(N); - } - } - - ViewGraph(&Src[0], &Src[0]+Src.size()); - } - else { - GraphPrintCheckerState = this; - GraphPrintSourceManager = &getContext().getSourceManager(); - - llvm::ViewGraph(*G.roots_begin(), "GRExprEngine"); - - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; - } -#endif -} - -void GRExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) { -#ifndef NDEBUG - GraphPrintCheckerState = this; - GraphPrintSourceManager = &getContext().getSourceManager(); - - std::auto_ptr TrimmedG(G.Trim(Beg, End).first); - - if (!TrimmedG.get()) - llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; - else - llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine"); - - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; -#endif -} diff --git a/clang/lib/GR/GRState.cpp b/clang/lib/GR/GRState.cpp index 993fa1a9cb4..3a4c15a8dbb 100644 --- a/clang/lib/GR/GRState.cpp +++ b/clang/lib/GR/GRState.cpp @@ -14,8 +14,8 @@ #include "clang/Analysis/CFG.h" #include "clang/GR/PathSensitive/GRStateTrait.h" #include "clang/GR/PathSensitive/GRState.h" -#include "clang/GR/PathSensitive/GRSubEngine.h" -#include "clang/GR/PathSensitive/GRTransferFuncs.h" +#include "clang/GR/PathSensitive/SubEngine.h" +#include "clang/GR/PathSensitive/TransferFuncs.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -114,7 +114,7 @@ const GRState *GRState::InvalidateRegions(const MemRegion * const *Begin, StoreManager::InvalidatedSymbols *IS, bool invalidateGlobals) const { GRStateManager &Mgr = getStateManager(); - GRSubEngine &Eng = Mgr.getOwningEngine(); + SubEngine &Eng = Mgr.getOwningEngine(); if (Eng.WantsRegionChangeUpdate(this)) { StoreManager::InvalidatedRegions Regions; diff --git a/clang/lib/GR/RangeConstraintManager.cpp b/clang/lib/GR/RangeConstraintManager.cpp index 378cb6e30f0..8f8528dbde6 100644 --- a/clang/lib/GR/RangeConstraintManager.cpp +++ b/clang/lib/GR/RangeConstraintManager.cpp @@ -15,7 +15,7 @@ #include "SimpleConstraintManager.h" #include "clang/GR/PathSensitive/GRState.h" #include "clang/GR/PathSensitive/GRStateTrait.h" -#include "clang/GR/PathSensitive/GRTransferFuncs.h" +#include "clang/GR/PathSensitive/TransferFuncs.h" #include "clang/GR/ManagerRegistry.h" #include "llvm/Support/Debug.h" #include "llvm/ADT/FoldingSet.h" @@ -208,7 +208,7 @@ namespace { class RangeConstraintManager : public SimpleConstraintManager{ RangeSet GetRange(const GRState *state, SymbolRef sym); public: - RangeConstraintManager(GRSubEngine &subengine) + RangeConstraintManager(SubEngine &subengine) : SimpleConstraintManager(subengine) {} const GRState *assumeSymNE(const GRState* state, SymbolRef sym, @@ -255,7 +255,7 @@ private: } // end anonymous namespace ConstraintManager* GR::CreateRangeConstraintManager(GRStateManager&, - GRSubEngine &subeng) { + SubEngine &subeng) { return new RangeConstraintManager(subeng); } diff --git a/clang/lib/GR/RegionStore.cpp b/clang/lib/GR/RegionStore.cpp index f2c47377d96..2fa8a9754a5 100644 --- a/clang/lib/GR/RegionStore.cpp +++ b/clang/lib/GR/RegionStore.cpp @@ -221,7 +221,7 @@ public: /// type. 'Array' represents the lvalue of the array being decayed /// to a pointer, and the returned SVal represents the decayed /// version of that lvalue (i.e., a pointer to the first element of - /// the array). This is called by GRExprEngine when evaluating + /// the array). This is called by ExprEngine when evaluating /// casts from arrays to pointers. SVal ArrayToPointer(Loc Array); @@ -787,7 +787,7 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, /// type. 'Array' represents the lvalue of the array being decayed /// to a pointer, and the returned SVal represents the decayed /// version of that lvalue (i.e., a pointer to the first element of -/// the array). This is called by GRExprEngine when evaluating casts +/// the array). This is called by ExprEngine when evaluating casts /// from arrays to pointers. SVal RegionStoreManager::ArrayToPointer(Loc Array) { if (!isa(Array)) diff --git a/clang/lib/GR/SimpleConstraintManager.cpp b/clang/lib/GR/SimpleConstraintManager.cpp index 991d0e87e4f..83e79558784 100644 --- a/clang/lib/GR/SimpleConstraintManager.cpp +++ b/clang/lib/GR/SimpleConstraintManager.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "SimpleConstraintManager.h" -#include "clang/GR/PathSensitive/GRExprEngine.h" +#include "clang/GR/PathSensitive/ExprEngine.h" #include "clang/GR/PathSensitive/GRState.h" #include "clang/GR/PathSensitive/Checker.h" diff --git a/clang/lib/GR/SimpleConstraintManager.h b/clang/lib/GR/SimpleConstraintManager.h index 442f0ca9f7c..616369395a1 100644 --- a/clang/lib/GR/SimpleConstraintManager.h +++ b/clang/lib/GR/SimpleConstraintManager.h @@ -22,9 +22,9 @@ namespace clang { namespace GR { class SimpleConstraintManager : public ConstraintManager { - GRSubEngine &SU; + SubEngine &SU; public: - SimpleConstraintManager(GRSubEngine &subengine) : SU(subengine) {} + SimpleConstraintManager(SubEngine &subengine) : SU(subengine) {} virtual ~SimpleConstraintManager(); //===------------------------------------------------------------------===// diff --git a/clang/lib/GR/SimpleSValBuilder.cpp b/clang/lib/GR/SimpleSValBuilder.cpp index 03f8e3076ce..2fc2347608c 100644 --- a/clang/lib/GR/SimpleSValBuilder.cpp +++ b/clang/lib/GR/SimpleSValBuilder.cpp @@ -358,7 +358,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state, case BO_XorAssign: case BO_OrAssign: case BO_Comma: - assert(false && "'=' and ',' operators handled by GRExprEngine."); + assert(false && "'=' and ',' operators handled by ExprEngine."); return UnknownVal(); case BO_PtrMemD: case BO_PtrMemI: diff --git a/clang/lib/GR/SymbolManager.cpp b/clang/lib/GR/SymbolManager.cpp index 95df3077ca5..6d078f41be6 100644 --- a/clang/lib/GR/SymbolManager.cpp +++ b/clang/lib/GR/SymbolManager.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines SymbolManager, a class that manages symbolic values -// created for use by GRExprEngine and related classes. +// created for use by ExprEngine and related classes. // //===----------------------------------------------------------------------===// -- cgit v1.2.3