diff options
Diffstat (limited to 'include/clang/StaticAnalyzer')
20 files changed, 479 insertions, 642 deletions
diff --git a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td index e452ccf..11f1e5d 100644 --- a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td +++ b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td @@ -11,18 +11,19 @@ // //===----------------------------------------------------------------------===// +class CheckerGroup<string name> { + string GroupName = name; +} +class InGroup<CheckerGroup G> { CheckerGroup Group = G; } + class Package<string name> { string PackageName = name; bit Hidden = 0; Package ParentPackage; + CheckerGroup Group; } class InPackage<Package P> { Package ParentPackage = P; } -class CheckerGroup<string name> { - string GroupName = name; -} -class InGroup<CheckerGroup G> { CheckerGroup Group = G; } - // All checkers are an indirect subclass of this. class Checker<string name = ""> { string CheckerName = name; diff --git a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h index afba12d..2a3d43e 100644 --- a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h +++ b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h @@ -39,8 +39,6 @@ class ExprEngine; TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, const LangOptions& lopts); -void RegisterExperimentalChecks(ExprEngine &Eng); - void RegisterCallInliner(ExprEngine &Eng); } // end GR namespace diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 93d7958..3acbcd6 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -126,7 +126,7 @@ public: /// getLocation - Return the "definitive" location of the reported bug. /// While a bug can span an entire path, usually there is a specific - /// location that can be used to identify where the key issue occured. + /// location that can be used to identify where the key issue occurred. /// This location is used by clients rendering diagnostics. virtual SourceLocation getLocation() const; @@ -219,6 +219,18 @@ public: virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const { return std::make_pair(Ranges.begin(), Ranges.end()); } + + virtual void Profile(llvm::FoldingSetNodeID& hash) const { + BugReport::Profile(hash); + for (llvm::SmallVectorImpl<SourceRange>::const_iterator I = + Ranges.begin(), E = Ranges.end(); I != E; ++I) { + const SourceRange range = *I; + if (!range.isValid()) + continue; + hash.AddInteger(range.getBegin().getRawEncoding()); + hash.AddInteger(range.getEnd().getRawEncoding()); + } + } }; class EnhancedBugReport : public RangedBugReport { diff --git a/include/clang/StaticAnalyzer/Core/CheckerV2.h b/include/clang/StaticAnalyzer/Core/Checker.h index e080d19..8c2ffc6 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerV2.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -1,4 +1,4 @@ -//== CheckerV2.h - Registration mechanism for checkers -----------*- C++ -*--=// +//== Checker.h - Registration mechanism for checkers -------------*- C++ -*--=// // // The LLVM Compiler Infrastructure // @@ -7,14 +7,15 @@ // //===----------------------------------------------------------------------===// // -// This file defines CheckerV2, used to create and register checkers. +// This file defines Checker, used to create and register checkers. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SA_CORE_CHECKERV2 -#define LLVM_CLANG_SA_CORE_CHECKERV2 +#ifndef LLVM_CLANG_SA_CORE_CHECKER +#define LLVM_CLANG_SA_CORE_CHECKER #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/Support/Casting.h" namespace clang { @@ -145,6 +146,21 @@ public: } }; +class Bind { + template <typename CHECKER> + static void _checkBind(void *checker, const SVal &location, const SVal &val, + CheckerContext &C) { + ((const CHECKER *)checker)->checkBind(location, val, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBind( + CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>)); + } +}; + class EndAnalysis { template <typename CHECKER> static void _checkEndAnalysis(void *checker, ExplodedGraph &G, @@ -175,6 +191,22 @@ public: } }; +class BranchCondition { + template <typename CHECKER> + static void _checkBranchCondition(void *checker, const Stmt *condition, + BranchNodeBuilder &B, ExprEngine &Eng) { + ((const CHECKER *)checker)->checkBranchCondition(condition, B, Eng); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBranchCondition( + CheckerManager::CheckBranchConditionFunc(checker, + _checkBranchCondition<CHECKER>)); + } +}; + class LiveSymbols { template <typename CHECKER> static void _checkLiveSymbols(void *checker, const GRState *state, @@ -228,10 +260,39 @@ public: } }; +template <typename EVENT> +class Event { + template <typename CHECKER> + static void _checkEvent(void *checker, const void *event) { + ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerListenerForEvent<EVENT>( + CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>)); + } +}; + } // end check namespace namespace eval { +class Assume { + template <typename CHECKER> + static const GRState *_evalAssume(void *checker, const GRState *state, + const SVal &cond, bool assumption) { + return ((const CHECKER *)checker)->evalAssume(state, cond, assumption); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEvalAssume( + CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>)); + } +}; + class Call { template <typename CHECKER> static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) { @@ -254,25 +315,58 @@ template <typename CHECK1, typename CHECK2=check::_VoidCheck, typename CHECK7=check::_VoidCheck, typename CHECK8=check::_VoidCheck, typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck, typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck> -class CheckerV2 { +class Checker; + +template <> +class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck> { +public: + static void _register(void *checker, CheckerManager &mgr) { } +}; + +template <typename CHECK1, typename CHECK2, typename CHECK3, typename CHECK4, + typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8, + typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12> +class Checker + : public CHECK1, + public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8, + CHECK9, CHECK10, CHECK11, CHECK12> { public: template <typename CHECKER> static void _register(CHECKER *checker, CheckerManager &mgr) { CHECK1::_register(checker, mgr); - CHECK2::_register(checker, mgr); - CHECK3::_register(checker, mgr); - CHECK4::_register(checker, mgr); - CHECK5::_register(checker, mgr); - CHECK6::_register(checker, mgr); - CHECK7::_register(checker, mgr); - CHECK8::_register(checker, mgr); - CHECK9::_register(checker, mgr); - CHECK10::_register(checker, mgr); - CHECK11::_register(checker, mgr); - CHECK12::_register(checker, mgr); + Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8, CHECK9, + CHECK10, CHECK11,CHECK12>::_register(checker, mgr); + } +}; + +template <typename EVENT> +class EventDispatcher { + CheckerManager *Mgr; +public: + EventDispatcher() : Mgr(0) { } + + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerDispatcherForEvent<EVENT>(); + static_cast<EventDispatcher<EVENT> *>(checker)->Mgr = &mgr; + } + + void dispatchEvent(const EVENT &event) const { + Mgr->_dispatchEvent(event); } }; +/// \brief We dereferenced a location that may be null. +struct ImplicitNullDerefEvent { + SVal Location; + bool IsLoad; + ExplodedNode *SinkNode; + BugReporter *BR; +}; + } // end ento namespace } // end clang namespace diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 2768195..92ec038 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -37,6 +37,7 @@ namespace ento { class ExplodedGraph; class GRState; class EndOfFunctionNodeBuilder; + class BranchNodeBuilder; class MemRegion; class SymbolReaper; @@ -46,47 +47,46 @@ public: virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0; }; -struct VoidCheckerFnParm {}; -template <typename P1=VoidCheckerFnParm, typename P2=VoidCheckerFnParm, - typename P3=VoidCheckerFnParm, typename P4=VoidCheckerFnParm> -class CheckerFn { - typedef void (*Func)(void *, P1, P2, P3, P4); +template <typename T> class CheckerFn; + +template <typename RET, typename P1, typename P2, typename P3> +class CheckerFn<RET(P1, P2, P3)> { + typedef RET (*Func)(void *, P1, P2, P3); Func Fn; public: void *Checker; CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } - void operator()(P1 p1, P2 p2, P3 p3, P4 p4) { Fn(Checker, p1, p2, p3, p4); } + RET operator()(P1 p1, P2 p2, P3 p3) const { return Fn(Checker, p1, p2, p3); } }; -template <typename P1, typename P2, typename P3> -class CheckerFn<P1, P2, P3, VoidCheckerFnParm> { - typedef void (*Func)(void *, P1, P2, P3); +template <typename RET, typename P1, typename P2> +class CheckerFn<RET(P1, P2)> { + typedef RET (*Func)(void *, P1, P2); Func Fn; public: void *Checker; CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } - void operator()(P1 p1, P2 p2, P3 p3) { Fn(Checker, p1, p2, p3); } + RET operator()(P1 p1, P2 p2) const { return Fn(Checker, p1, p2); } }; -template <typename P1, typename P2> -class CheckerFn<P1, P2, VoidCheckerFnParm, VoidCheckerFnParm> { - typedef void (*Func)(void *, P1, P2); +template <typename RET, typename P1> +class CheckerFn<RET(P1)> { + typedef RET (*Func)(void *, P1); Func Fn; public: void *Checker; CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } - void operator()(P1 p1, P2 p2) { Fn(Checker, p1, p2); } + RET operator()(P1 p1) const { return Fn(Checker, p1); } }; -template <> -class CheckerFn<VoidCheckerFnParm, VoidCheckerFnParm, VoidCheckerFnParm, - VoidCheckerFnParm> { - typedef void (*Func)(void *); +template <typename RET> +class CheckerFn<RET()> { + typedef RET (*Func)(void *); Func Fn; public: void *Checker; CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } - void operator()() { Fn(Checker); } + RET operator()() const { return Fn(Checker); } }; class CheckerManager { @@ -96,21 +96,35 @@ public: CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { } ~CheckerManager(); + bool hasPathSensitiveCheckers() const; + + void finishedCheckerRegistration(); + const LangOptions &getLangOptions() const { return LangOpts; } typedef void *CheckerRef; - typedef CheckerFn<> CheckerDtor; + typedef void *CheckerTag; + typedef CheckerFn<void ()> CheckerDtor; //===----------------------------------------------------------------------===// // registerChecker //===----------------------------------------------------------------------===// /// \brief Used to register checkers. + /// + /// \returns a pointer to the checker object. template <typename CHECKER> - void registerChecker() { + CHECKER *registerChecker() { + CheckerTag tag = getTag<CHECKER>(); + CheckerRef &ref = CheckerTags[tag]; + if (ref) + return static_cast<CHECKER *>(ref); // already registered. + CHECKER *checker = new CHECKER(); CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); CHECKER::_register(checker, *this); + ref = checker; + return checker; } //===----------------------------------------------------------------------===// @@ -179,6 +193,12 @@ public: const Stmt *S, ExprEngine &Eng); + /// \brief Run checkers for binding of a value to a location. + void runCheckersForBind(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SVal location, SVal val, + const Stmt *S, ExprEngine &Eng); + /// \brief Run checkers for end of analysis. void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng); @@ -186,6 +206,10 @@ public: /// \brief Run checkers for end of path. void runCheckersForEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng); + /// \brief Run checkers for branch condition. + void runCheckersForBranchCondition(const Stmt *condition, + BranchNodeBuilder &B, ExprEngine &Eng); + /// \brief Run checkers for live symbols. void runCheckersForLiveSymbols(const GRState *state, SymbolReaper &SymReaper); @@ -204,6 +228,10 @@ public: const MemRegion * const *Begin, const MemRegion * const *End); + /// \brief Run checkers for handling assumptions on symbolic values. + const GRState *runCheckersForEvalAssume(const GRState *state, + SVal Cond, bool Assumption); + /// \brief Run checkers for evaluating a call. void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, @@ -217,9 +245,8 @@ public: // Functions used by the registration mechanism, checkers should not touch // these directly. - typedef CheckerFn<const Decl *, AnalysisManager&, BugReporter &> + typedef CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)> CheckDeclFunc; - typedef CheckerFn<const Stmt *, CheckerContext &> CheckStmtFunc; typedef bool (*HandlesDeclFunc)(const Decl *D); void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn); @@ -230,14 +257,44 @@ public: // Internal registration functions for path-sensitive checking. //===----------------------------------------------------------------------===// - typedef CheckerFn<const ObjCMessage &, CheckerContext &> CheckObjCMessageFunc; - typedef CheckerFn<const SVal &/*location*/, bool/*isLoad*/, CheckerContext &> + typedef CheckerFn<void (const Stmt *, CheckerContext &)> CheckStmtFunc; + + typedef CheckerFn<void (const ObjCMessage &, CheckerContext &)> + CheckObjCMessageFunc; + + typedef CheckerFn<void (const SVal &location, bool isLoad, CheckerContext &)> CheckLocationFunc; - typedef CheckerFn<ExplodedGraph &, BugReporter &, ExprEngine &> + + typedef CheckerFn<void (const SVal &location, const SVal &val, + CheckerContext &)> CheckBindFunc; + + typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)> CheckEndAnalysisFunc; - typedef CheckerFn<EndOfFunctionNodeBuilder &, ExprEngine &> CheckEndPathFunc; - typedef CheckerFn<SymbolReaper &, CheckerContext &> CheckDeadSymbolsFunc; - typedef CheckerFn<const GRState *, SymbolReaper &> CheckLiveSymbolsFunc; + + typedef CheckerFn<void (EndOfFunctionNodeBuilder &, ExprEngine &)> + CheckEndPathFunc; + + typedef CheckerFn<void (const Stmt *, BranchNodeBuilder &, ExprEngine &)> + CheckBranchConditionFunc; + + typedef CheckerFn<void (SymbolReaper &, CheckerContext &)> + CheckDeadSymbolsFunc; + + typedef CheckerFn<void (const GRState *,SymbolReaper &)> CheckLiveSymbolsFunc; + + typedef CheckerFn<const GRState * (const GRState *, + const MemRegion * const *begin, + const MemRegion * const *end)> + CheckRegionChangesFunc; + + typedef CheckerFn<bool (const GRState *)> WantsRegionChangeUpdateFunc; + + typedef CheckerFn<const GRState * (const GRState *, + const SVal &cond, bool assumption)> + EvalAssumeFunc; + + typedef CheckerFn<bool (const CallExpr *, CheckerContext &)> + EvalCallFunc; typedef bool (*HandlesStmtFunc)(const Stmt *D); void _registerForPreStmt(CheckStmtFunc checkfn, @@ -250,58 +307,55 @@ public: void _registerForLocation(CheckLocationFunc checkfn); + void _registerForBind(CheckBindFunc checkfn); + void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); void _registerForEndPath(CheckEndPathFunc checkfn); + void _registerForBranchCondition(CheckBranchConditionFunc checkfn); + void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn); void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn); - class CheckRegionChangesFunc { - typedef const GRState * (*Func)(void *, const GRState *, - const MemRegion * const *, - const MemRegion * const *); - Func Fn; - public: - void *Checker; - CheckRegionChangesFunc(void *checker, Func fn) : Fn(fn), Checker(checker) {} - const GRState *operator()(const GRState *state, - const MemRegion * const *begin, - const MemRegion * const *end) { - return Fn(Checker, state, begin, end); - } - }; - - class WantsRegionChangeUpdateFunc { - typedef bool (*Func)(void *, const GRState *); - Func Fn; - public: - void *Checker; - WantsRegionChangeUpdateFunc(void *checker, Func fn) - : Fn(fn), Checker(checker) { } - bool operator()(const GRState *state) { - return Fn(Checker, state); - } - }; - void _registerForRegionChanges(CheckRegionChangesFunc checkfn, WantsRegionChangeUpdateFunc wantUpdateFn); - class EvalCallFunc { - typedef bool (*Func)(void *, const CallExpr *, CheckerContext &); - Func Fn; - public: - void *Checker; - EvalCallFunc(void *checker, Func fn) : Fn(fn), Checker(checker) { } - bool operator()(const CallExpr *CE, CheckerContext &C) { - return Fn(Checker, CE, C); - } - }; + void _registerForEvalAssume(EvalAssumeFunc checkfn); void _registerForEvalCall(EvalCallFunc checkfn); //===----------------------------------------------------------------------===// +// Internal registration functions for events. +//===----------------------------------------------------------------------===// + + typedef void *EventTag; + typedef CheckerFn<void (const void *event)> CheckEventFunc; + + template <typename EVENT> + void _registerListenerForEvent(CheckEventFunc checkfn) { + EventInfo &info = Events[getTag<EVENT>()]; + info.Checkers.push_back(checkfn); + } + + template <typename EVENT> + void _registerDispatcherForEvent() { + EventInfo &info = Events[getTag<EVENT>()]; + info.HasDispatcher = true; + } + + template <typename EVENT> + void _dispatchEvent(const EVENT &event) const { + EventsTy::const_iterator I = Events.find(getTag<EVENT>()); + if (I == Events.end()) + return; + const EventInfo &info = I->second; + for (unsigned i = 0, e = info.Checkers.size(); i != e; ++i) + info.Checkers[i](&event); + } + +//===----------------------------------------------------------------------===// // Implementation details. //===----------------------------------------------------------------------===// @@ -309,6 +363,11 @@ private: template <typename CHECKER> static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } + template <typename T> + static void *getTag() { static int tag; return &tag; } + + llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags; + std::vector<CheckerDtor> CheckerDtors; struct DeclCheckerInfo { @@ -365,10 +424,14 @@ private: std::vector<CheckLocationFunc> LocationCheckers; + std::vector<CheckBindFunc> BindCheckers; + std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers; std::vector<CheckEndPathFunc> EndPathCheckers; + std::vector<CheckBranchConditionFunc> BranchConditionCheckers; + std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers; std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers; @@ -379,7 +442,18 @@ private: }; std::vector<RegionChangesCheckerInfo> RegionChangesCheckers; + std::vector<EvalAssumeFunc> EvalAssumeCheckers; + std::vector<EvalCallFunc> EvalCallCheckers; + + struct EventInfo { + llvm::SmallVector<CheckEventFunc, 4> Checkers; + bool HasDispatcher; + EventInfo() : HasDispatcher(false) { } + }; + + typedef llvm::DenseMap<EventTag, EventInfo> EventsTy; + EventsTy Events; }; } // end ento namespace diff --git a/include/clang/StaticAnalyzer/Core/CheckerProvider.h b/include/clang/StaticAnalyzer/Core/CheckerProvider.h index 40b838e..b8aaaa1 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerProvider.h +++ b/include/clang/StaticAnalyzer/Core/CheckerProvider.h @@ -15,7 +15,6 @@ #define LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H #include "llvm/ADT/StringRef.h" -#include <vector> namespace llvm { class raw_ostream; diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h index 2713e31..d02228f 100644 --- a/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h +++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H -#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLiENTS_H +#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H #include <string> diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index a4327e1..65fbfcc 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -16,6 +16,7 @@ #ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H #define LLVM_CLANG_GR_BASICVALUEFACTORY_H +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/AST/ASTContext.h" #include "llvm/ADT/FoldingSet.h" @@ -47,16 +48,17 @@ public: }; class LazyCompoundValData : public llvm::FoldingSetNode { - const void *store; + StoreRef store; const TypedRegion *region; public: - LazyCompoundValData(const void *st, const TypedRegion *r) + LazyCompoundValData(const StoreRef &st, const TypedRegion *r) : store(st), region(r) {} - const void *getStore() const { return store; } + const void *getStore() const { return store.getStore(); } const TypedRegion *getRegion() const { return region; } - static void Profile(llvm::FoldingSetNodeID& ID, const void *store, + static void Profile(llvm::FoldingSetNodeID& ID, + const StoreRef &store, const TypedRegion *region); void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); } @@ -170,7 +172,7 @@ public: const CompoundValData *getCompoundValData(QualType T, llvm::ImmutableList<SVal> Vals); - const LazyCompoundValData *getLazyCompoundValData(const void *store, + const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store, const TypedRegion *region); llvm::ImmutableList<SVal> getEmptySValList() { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h deleted file mode 100644 index 627bc0a..0000000 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h +++ /dev/null @@ -1,166 +0,0 @@ -//== Checker.h - Abstract interface for checkers -----------------*- 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 Checker and CheckerVisitor, classes used for creating -// domain-specific checks. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_GR_CHECKER -#define LLVM_CLANG_GR_CHECKER - -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" - -//===----------------------------------------------------------------------===// -// Checker interface. -//===----------------------------------------------------------------------===// - -namespace clang { - -namespace ento { - -class Checker { -private: - friend class ExprEngine; - - // FIXME: Remove the 'tag' option. - void GR_Visit(ExplodedNodeSet &Dst, - StmtNodeBuilder &Builder, - ExprEngine &Eng, - const Stmt *S, - ExplodedNode *Pred, void *tag, bool isPrevisit, - bool& respondsToCallback) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, &respondsToCallback, S); - if (isPrevisit) - _PreVisit(C, S); - else - _PostVisit(C, S); - } - - void GR_visitObjCMessage(ExplodedNodeSet &Dst, - StmtNodeBuilder &Builder, - ExprEngine &Eng, - const ObjCMessage &msg, - ExplodedNode *Pred, void *tag, bool isPrevisit) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, 0, msg.getOriginExpr()); - if (isPrevisit) - preVisitObjCMessage(C, msg); - else - postVisitObjCMessage(C, msg); - } - - bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder, - ExprEngine &Eng, const ObjCMessage &msg, - ExplodedNode *Pred, const GRState *state, void *tag) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, - 0, msg.getOriginExpr(), state); - return evalNilReceiver(C, msg); - } - - bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder, - ExprEngine &Eng, const CallExpr *CE, - ExplodedNode *Pred, void *tag) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, - 0, CE); - return evalCallExpr(C, CE); - } - - // FIXME: Remove the 'tag' option. - void GR_VisitBind(ExplodedNodeSet &Dst, - StmtNodeBuilder &Builder, ExprEngine &Eng, - const Stmt *StoreE, ExplodedNode *Pred, void *tag, - SVal location, SVal val, - bool isPrevisit) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, 0, StoreE); - assert(isPrevisit && "Only previsit supported for now."); - PreVisitBind(C, StoreE, location, val); - } - - // FIXME: Remove the 'tag' option. - void GR_visitLocation(ExplodedNodeSet &Dst, - StmtNodeBuilder &Builder, - ExprEngine &Eng, - const Stmt *S, - ExplodedNode *Pred, const GRState *state, - SVal location, - void *tag, bool isLoad) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - isLoad ? ProgramPoint::PreLoadKind : - ProgramPoint::PreStoreKind, 0, S, state); - visitLocation(C, S, location, isLoad); - } - - void GR_evalDeadSymbols(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder, - ExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, - SymbolReaper &SymReaper, void *tag) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - ProgramPoint::PostPurgeDeadSymbolsKind, 0, S); - evalDeadSymbols(C, SymReaper); - } - -public: - virtual ~Checker(); - virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} - virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} - virtual void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {} - virtual void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {} - virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location, - bool isLoad) {} - virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, - SVal location, SVal val) {} - virtual void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {} - virtual void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, - ExprEngine &Eng) {} - - virtual void MarkLiveSymbols(const GRState *state, SymbolReaper &SymReaper) {} - - virtual void VisitBranchCondition(BranchNodeBuilder &Builder, - ExprEngine &Eng, - const Stmt *Condition, void *tag) {} - - virtual bool evalNilReceiver(CheckerContext &C, ObjCMessage msg) { - return false; - } - - virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE) { - return false; - } - - virtual const GRState *evalAssume(const GRState *state, SVal Cond, - bool Assumption, bool *respondsToCallback) { - *respondsToCallback = false; - return state; - } - - virtual bool wantsRegionChangeUpdate(const GRState *state) { return false; } - - virtual const GRState *EvalRegionChanges(const GRState *state, - const MemRegion * const *Begin, - const MemRegion * const *End, - bool *respondsToCallback) { - *respondsToCallback = false; - return state; - } - - virtual void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, - ExprEngine &Eng) {} -}; - -} // end GR namespace - -} // end clang namespace - -#endif - diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def deleted file mode 100644 index 9b3c263..0000000 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def +++ /dev/null @@ -1,48 +0,0 @@ -//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===// -// -// 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 AST nodes accepted by the CheckerVisitor class. -// -//===---------------------------------------------------------------------===// - -#ifndef PREVISIT -#define PREVISIT(NODE, FALLBACK) -#endif - -#ifndef POSTVISIT -#define POSTVISIT(NODE, FALLBACK) -#endif - -PREVISIT(ArraySubscriptExpr, Stmt) -PREVISIT(BinaryOperator, Stmt) -PREVISIT(CallExpr, GenericCall) -PREVISIT(CompoundAssignOperator, BinaryOperator) -PREVISIT(CStyleCastExpr, CastExpr) -PREVISIT(CXXConstCastExpr, CastExpr) -PREVISIT(CXXDynamicCastExpr, CastExpr) -PREVISIT(CXXFunctionalCastExpr, CastExpr) -PREVISIT(CXXOperatorCallExpr, GenericCall) -PREVISIT(CXXMemberCallExpr, GenericCall) -PREVISIT(CXXReinterpretCastExpr, CastExpr) -PREVISIT(CXXStaticCastExpr, CastExpr) -PREVISIT(DeclStmt, Stmt) -PREVISIT(ImplicitCastExpr, CastExpr) -PREVISIT(ObjCAtSynchronizedStmt, Stmt) -PREVISIT(ReturnStmt, Stmt) - -POSTVISIT(BlockExpr, Stmt) -POSTVISIT(BinaryOperator, Stmt) -POSTVISIT(CallExpr, GenericCall) -POSTVISIT(CompoundAssignOperator, BinaryOperator) -POSTVISIT(CXXOperatorCallExpr, GenericCall) -POSTVISIT(CXXMemberCallExpr, GenericCall) -POSTVISIT(ObjCIvarRefExpr, Stmt) - -#undef PREVISIT -#undef POSTVISIT diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h deleted file mode 100644 index dc76c96..0000000 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h +++ /dev/null @@ -1,103 +0,0 @@ -//== CheckerVisitor.h - Abstract visitor for checkers ------------*- 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 CheckerVisitor. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_GR_CHECKERVISITOR -#define LLVM_CLANG_GR_CHECKERVISITOR -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" - -namespace clang { - -namespace ento { - -//===----------------------------------------------------------------------===// -// Checker visitor interface. Used by subclasses of Checker to specify their -// own checker visitor logic. -//===----------------------------------------------------------------------===// - -/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses. -/// Since Expr derives from Stmt, this also includes support for visiting Exprs. -template<typename ImplClass> -class CheckerVisitor : public Checker { -public: - virtual void _PreVisit(CheckerContext &C, const Stmt *S) { - PreVisit(C, S); - } - - virtual void _PostVisit(CheckerContext &C, const Stmt *S) { - PostVisit(C, S); - } - - void PreVisit(CheckerContext &C, const Stmt *S) { - switch (S->getStmtClass()) { - default: - assert(false && "Unsupport statement."); - return; - -#define PREVISIT(NAME, FALLBACK) \ -case Stmt::NAME ## Class:\ -static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\ -break; -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def" - } - } - - void PostVisit(CheckerContext &C, const Stmt *S) { - switch (S->getStmtClass()) { - default: - assert(false && "Unsupport statement."); - return; - -#define POSTVISIT(NAME, FALLBACK) \ -case Stmt::NAME ## Class:\ -static_cast<ImplClass*>(this)->\ -PostVisit ## NAME(C,static_cast<const NAME*>(S));\ -break; -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def" - } - } - - void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE) { - static_cast<ImplClass*>(this)->PreVisitStmt(C, CE); - } - void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE) { - static_cast<ImplClass*>(this)->PostVisitStmt(C, CE); - } - - void PreVisitStmt(CheckerContext &C, const Stmt *S) { - *C.respondsToCallback = false; - } - - void PostVisitStmt(CheckerContext &C, const Stmt *S) { - *C.respondsToCallback = false; - } - - void PreVisitCastExpr(CheckerContext &C, const CastExpr *E) { - static_cast<ImplClass*>(this)->PreVisitStmt(C, E); - } - -#define PREVISIT(NAME, FALLBACK) \ -void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\ - static_cast<ImplClass*>(this)->PreVisit ## FALLBACK(C, S);\ -} -#define POSTVISIT(NAME, FALLBACK) \ -void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\ - static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\ -} -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def" -}; - -} // end GR namespace - -} // end clang namespace - -#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 25c6447..2c1d07c 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -47,7 +47,11 @@ class CoreEngine { public: typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> > + BlocksExhausted; + + typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> > BlocksAborted; + private: SubEngine& SubEng; @@ -67,6 +71,10 @@ private: /// The locations where we stopped doing work because we visited a location /// too many times. + BlocksExhausted blocksExhausted; + + /// The locations where we stopped because the engine aborted analysis, + /// usually because it could not reason about something. BlocksAborted blocksAborted; void generateNode(const ProgramPoint& Loc, const GRState* State, @@ -110,7 +118,7 @@ public: ExplodedGraph& getGraph() { return *G.get(); } /// takeGraph - Returns the exploded graph. Ownership of the graph is - /// transfered to the caller. + /// transferred to the caller. ExplodedGraph* takeGraph() { return G.take(); } /// ExecuteWorkList - Run the worklist algorithm for a maximum number of @@ -123,10 +131,25 @@ public: // Functions for external checking of whether we have unfinished work bool wasBlockAborted() const { return !blocksAborted.empty(); } - bool hasWorkRemaining() const { return wasBlockAborted() || WList->hasWork(); } - + bool wasBlocksExhausted() const { return !blocksExhausted.empty(); } + bool hasWorkRemaining() const { return wasBlocksExhausted() || + WList->hasWork() || + wasBlockAborted(); } + + /// Inform the CoreEngine that a basic block was aborted because + /// it could not be completely analyzed. + void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) { + blocksAborted.push_back(std::make_pair(block, node)); + } + WorkList *getWorkList() const { return WList; } + BlocksExhausted::const_iterator blocks_exhausted_begin() const { + return blocksExhausted.begin(); + } + BlocksExhausted::const_iterator blocks_exhausted_end() const { + return blocksExhausted.end(); + } BlocksAborted::const_iterator blocks_aborted_begin() const { return blocksAborted.begin(); } @@ -219,11 +242,8 @@ public: /// getStmt - Return the current block-level expression associated with /// this builder. const Stmt* getStmt() const { - CFGStmt CS = B[Idx].getAs<CFGStmt>(); - if (CS) - return CS.getStmt(); - else - return 0; + const CFGStmt *CS = B[Idx].getAs<CFGStmt>(); + return CS ? CS->getStmt() : 0; } /// getBlock - Return the CFGBlock associated with the block-level expression @@ -287,6 +307,8 @@ public: BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + ExplodedNode* generateNode(const Stmt *Condition, const GRState* State); + ExplodedNode* generateNode(const GRState* State, bool branch); const CFGBlock* getTargetBlock(bool branch) const { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h index 732a40cb..193056e 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -51,9 +51,10 @@ public: iterator end() const { return ExprBindings.end(); } - /// GetSVal - Fetches the current binding of the expression in the + /// getSVal - Fetches the current binding of the expression in the /// Environment. - SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder) const; + SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder, + bool useOnlyDirectBindings = false) const; /// Profile - Profile the contents of an Environment object for use /// in a FoldingSet. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 16f54ee..8cd743f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -34,7 +34,6 @@ class ObjCForCollectionStmt; namespace ento { class AnalysisManager; -class Checker; class ExprEngine : public SubEngine { AnalysisManager &AMgr; @@ -74,39 +73,6 @@ class ExprEngine : public SubEngine { Selector* NSExceptionInstanceRaiseSelectors; Selector RaiseSel; - enum CallbackKind { - PreVisitStmtCallback, - PostVisitStmtCallback, - processAssumeCallback, - EvalRegionChangesCallback - }; - - typedef uint32_t CallbackTag; - - /// GetCallbackTag - Create a tag for a certain kind of callback. The 'Sub' - /// argument can be used to differentiate callbacks that depend on another - /// value from a small set of possibilities, such as statement classes. - static inline CallbackTag GetCallbackTag(CallbackKind K, uint32_t Sub = 0) { - assert(Sub == ((Sub << 8) >> 8) && "Tag sub-kind must fit into 24 bits"); - return K | (Sub << 8); - } - - typedef llvm::DenseMap<void *, unsigned> CheckerMap; - typedef std::vector<std::pair<void *, Checker*> > CheckersOrdered; - typedef llvm::DenseMap<CallbackTag, CheckersOrdered *> CheckersOrderedCache; - - /// A registration map from checker tag to the index into the - /// ordered checkers vector. - CheckerMap CheckerM; - - /// An ordered vector of checkers that are called when evaluating - /// various expressions and statements. - CheckersOrdered Checkers; - - /// A map used for caching the checkers that respond to the callback for - /// a particular callback tag. - CheckersOrderedCache COCache; - /// The BugReporter associated with this engine. It is important that /// this object be placed at the very end of member variables so that its /// destructor is called before the rest of the ExprEngine is destroyed. @@ -165,21 +131,6 @@ public: ExplodedGraph& getGraph() { return G; } const ExplodedGraph& getGraph() const { return G; } - template <typename CHECKER> - void registerCheck(CHECKER *check) { - unsigned entry = Checkers.size(); - void *tag = CHECKER::getTag(); - Checkers.push_back(std::make_pair(tag, check)); - CheckerM[tag] = entry; - } - - Checker *lookupChecker(void *tag) const; - - template <typename CHECKER> - CHECKER *getChecker() const { - return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag())); - } - /// processCFGElement - Called by CoreEngine. Used to generate new successor /// nodes by processing the 'effects' of a CFG element. void processCFGElement(const CFGElement E, StmtNodeBuilder& builder); @@ -262,11 +213,9 @@ public: const SymbolManager& getSymbolManager() const { return SymMgr; } // Functions for external checking of whether we have unfinished work - bool wasBlockAborted() const { return Engine.wasBlockAborted(); } + bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); } bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); } - bool hasWorkRemaining() const { - return wasBlockAborted() || Engine.getWorkList()->hasWork(); - } + bool hasWorkRemaining() const { return Engine.hasWorkRemaining(); } const CoreEngine &getCoreEngine() const { return Engine; } @@ -281,27 +230,6 @@ public: ProgramPoint::Kind K = ProgramPoint::PostStmtKind, const void *tag = 0); - /// CheckerVisit - Dispatcher for performing checker-specific logic - /// at specific statements. - void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, - CallbackKind Kind); - - void CheckerVisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, bool isPrevisit); - - bool CheckerEvalCall(const CallExpr *CE, - ExplodedNodeSet &Dst, - ExplodedNode *Pred); - - void CheckerEvalNilReceiver(const ObjCMessage &msg, - ExplodedNodeSet &Dst, - const GRState *state, - ExplodedNode *Pred); - - void CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, SVal location, SVal val, - bool isPrevisit); - /// Visit - Transfer function logic for all statements. Dispatches to /// other functions that handle specific kinds of statements. void Visit(const Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst); @@ -334,10 +262,8 @@ public: /// VisitCall - Transfer function for function calls. - void VisitCall(const CallExpr* CE, ExplodedNode* Pred, - CallExpr::const_arg_iterator AI, - CallExpr::const_arg_iterator AE, - ExplodedNodeSet& Dst); + void VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, @@ -358,11 +284,6 @@ public: /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose void VisitGuardedExpr(const Expr* Ex, const Expr* L, const Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); - - /// VisitCondInit - Transfer function for handling the initialization - /// of a condition variable in an IfStmt, SwitchStmt, etc. - void VisitCondInit(const VarDecl *VD, const Stmt *S, ExplodedNode *Pred, - ExplodedNodeSet& Dst); void VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst); @@ -409,9 +330,9 @@ public: void VisitOffsetOfExpr(const OffsetOfExpr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); - /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. - void VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst); + /// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof. + void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr* Ex, + ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitUnaryOperator - Transfer function logic for unary operators. void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode* Pred, @@ -432,12 +353,6 @@ public: const MemRegion *Dest, const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); - void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred, - ExplodedNodeSet &Dst); - - void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C, - ExplodedNode *Pred, ExplodedNodeSet &Dst); - void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst); @@ -463,12 +378,10 @@ public: const FunctionProtoType *FnType, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool FstArgAsLValue = false); - - /// Evaluate method call itself. Used for CXXMethodCallExpr and - /// CXXOperatorCallExpr. - void evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, - const Expr *ThisExpr, ExplodedNode *Pred, - ExplodedNodeSet &Src, ExplodedNodeSet &Dst); + + /// Evaluate callee expression (for a function call). + void evalCallee(const CallExpr *callExpr, const ExplodedNodeSet &src, + ExplodedNodeSet &dest); /// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h index 37694da..a957c89 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h @@ -35,7 +35,6 @@ class ASTContext; namespace ento { class GRStateManager; -class Checker; typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&, SubEngine&); @@ -261,7 +260,7 @@ public: const llvm::APSInt *getSymVal(SymbolRef sym) const; /// Returns the SVal bound to the statement 'S' in the state's environment. - SVal getSVal(const Stmt* S) const; + SVal getSVal(const Stmt* S, bool useOnlyDirectBindings = false) const; SVal getSValAsScalarOrLoc(const Stmt *Ex) const; @@ -274,8 +273,6 @@ public: SVal getSValAsScalarOrLoc(const MemRegion *R) const; - const llvm::APSInt *getSymVal(SymbolRef sym); - bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; bool scanReachableSymbols(const SVal *I, const SVal *E, @@ -627,10 +624,6 @@ public: // Out-of-line method definitions for GRState. //===----------------------------------------------------------------------===// -inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) { - return getStateManager().getSymVal(this, sym); -} - inline const VarRegion* GRState::getRegion(const VarDecl *D, const LocationContext *LC) const { return getStateManager().getRegionManager().getVarRegion(D, LC); @@ -690,14 +683,15 @@ inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const { return getStateManager().getSymVal(this, sym); } -inline SVal GRState::getSVal(const Stmt* Ex) const { - return Env.getSVal(Ex, *getStateManager().svalBuilder); +inline SVal GRState::getSVal(const Stmt* Ex, bool useOnlyDirectBindings) const{ + return Env.getSVal(Ex, *getStateManager().svalBuilder, + useOnlyDirectBindings); } inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const { if (const Expr *Ex = dyn_cast<Expr>(S)) { QualType T = Ex->getType(); - if (Loc::isLocType(T) || T->isIntegerType()) + if (Ex->isLValue() || Loc::isLocType(T) || T->isIntegerType()) return getSVal(S); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 8d19b51..db7a930 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -769,7 +769,7 @@ public: } }; //===----------------------------------------------------------------------===// -// Auxillary data classes for use with MemRegions. +// Auxiliary data classes for use with MemRegions. //===----------------------------------------------------------------------===// class ElementRegion; @@ -960,7 +960,7 @@ public: getCompoundLiteralRegion(const CompoundLiteralExpr* CL, const LocationContext *LC); - /// getCXXThisRegion - Retrieve the [artifical] region associated with the + /// getCXXThisRegion - Retrieve the [artificial] region associated with the /// parameter 'this'. const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy, const LocationContext *LC); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h index 710fc6b..6d8fc89 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -72,6 +72,8 @@ public: return getType(ctx); } + ObjCMethodFamily getMethodFamily() const; + Selector getSelector() const; const Expr *getInstanceReceiver() const { @@ -169,14 +171,23 @@ class CallOrObjCMessage { const CallExpr *CallE; ObjCMessage Msg; const GRState *State; - public: CallOrObjCMessage(const CallExpr *callE, const GRState *state) - : CallE(callE), State(state) { } + : CallE(callE), State(state) {} CallOrObjCMessage(const ObjCMessage &msg, const GRState *state) - : CallE(0), Msg(msg), State(state) { } + : CallE(0), Msg(msg), State(state) {} QualType getResultType(ASTContext &ctx) const; + + bool isFunctionCall() const { + return (bool) CallE; + } + + bool isCXXCall() const { + return CallE && isa<CXXMemberCallExpr>(CallE); + } + + SVal getCXXCallee() const; unsigned getNumArgs() const { if (CallE) return CallE->getNumArgs(); @@ -185,7 +196,8 @@ public: SVal getArgSVal(unsigned i) const { assert(i < getNumArgs()); - if (CallE) return State->getSVal(CallE->getArg(i)); + if (CallE) + return State->getSVal(CallE->getArg(i)); return Msg.getArgSVal(i, State); } @@ -193,13 +205,15 @@ public: const Expr *getArg(unsigned i) const { assert(i < getNumArgs()); - if (CallE) return CallE->getArg(i); + if (CallE) + return CallE->getArg(i); return Msg.getArgExpr(i); } SourceRange getArgSourceRange(unsigned i) const { assert(i < getNumArgs()); - if (CallE) return CallE->getArg(i)->getSourceRange(); + if (CallE) + return CallE->getArg(i)->getSourceRange(); return Msg.getArgSourceRange(i); } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index fc2b76e..0f9e56a 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -49,10 +49,10 @@ protected: const unsigned ArrayIndexWidth; public: - // FIXME: Make these protected again one RegionStoreManager correctly - // handles loads from differening bound value types. - virtual SVal evalCastNL(NonLoc val, QualType castTy) = 0; - virtual SVal evalCastL(Loc val, QualType castTy) = 0; + // FIXME: Make these protected again once RegionStoreManager correctly + // handles loads from different bound value types. + virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0; + virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0; public: SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, @@ -66,30 +66,30 @@ public: virtual ~SValBuilder() {} - SVal evalCast(SVal V, QualType castTy, QualType originalType); + SVal evalCast(SVal val, QualType castTy, QualType originalType); virtual SVal evalMinus(NonLoc val) = 0; virtual SVal evalComplement(NonLoc val) = 0; - virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode Op, + virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; - virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode Op, + virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode op, Loc lhs, Loc rhs, QualType resultTy) = 0; - virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode Op, + virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy) = 0; /// getKnownValue - evaluates a given SVal. If the SVal has only one possible /// (integer) value, that value is returned. Otherwise, returns NULL. - virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V) = 0; + virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal val) = 0; - SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op, - SVal L, SVal R, QualType T); + SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op, + SVal lhs, SVal rhs, QualType type); - DefinedOrUnknownSVal evalEQ(const GRState *ST, DefinedOrUnknownSVal L, - DefinedOrUnknownSVal R); + DefinedOrUnknownSVal evalEQ(const GRState *state, DefinedOrUnknownSVal lhs, + DefinedOrUnknownSVal rhs); ASTContext &getContext() { return Context; } const ASTContext &getContext() const { return Context; } @@ -115,46 +115,48 @@ public: // Forwarding methods to SymbolManager. - const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, - unsigned VisitCount, - const void* SymbolTag = 0) { - return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag); + const SymbolConjured* getConjuredSymbol(const Stmt* stmt, QualType type, + unsigned visitCount, + const void* symbolTag = 0) { + return SymMgr.getConjuredSymbol(stmt, type, visitCount, symbolTag); } - const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, - const void* SymbolTag = 0) { - return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag); + const SymbolConjured* getConjuredSymbol(const Expr* expr, unsigned visitCount, + const void* symbolTag = 0) { + return SymMgr.getConjuredSymbol(expr, visitCount, symbolTag); } /// makeZeroVal - Construct an SVal representing '0' for the specified type. - DefinedOrUnknownSVal makeZeroVal(QualType T); + DefinedOrUnknownSVal makeZeroVal(QualType type); - /// getRegionValueSymbolVal - make a unique symbol for value of R. - DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *R); + /// getRegionValueSymbolVal - make a unique symbol for value of region. + DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *region); - DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, - const Expr *E, unsigned Count); - DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, - const Expr *E, QualType T, - unsigned Count); + DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag, + const Expr *expr, unsigned count); + DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag, + const Expr *expr, QualType type, + unsigned count); - DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, - const TypedRegion *R); + DefinedOrUnknownSVal getDerivedRegionValueSymbolVal( + SymbolRef parentSymbol, const TypedRegion *region); - DefinedSVal getMetadataSymbolVal(const void *SymbolTag, const MemRegion *MR, - const Expr *E, QualType T, unsigned Count); + DefinedSVal getMetadataSymbolVal( + const void *symbolTag, const MemRegion *region, + const Expr *expr, QualType type, unsigned count); - DefinedSVal getFunctionPointer(const FunctionDecl *FD); + DefinedSVal getFunctionPointer(const FunctionDecl *func); - DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy, - const LocationContext *LC); + DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy, + const LocationContext *locContext); - NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) { - return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals)); + NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) { + return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals)); } - NonLoc makeLazyCompoundVal(const void *store, const TypedRegion *R) { - return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(store, R)); + NonLoc makeLazyCompoundVal(const StoreRef &store, const TypedRegion *region) { + return nonloc::LazyCompoundVal( + BasicVals.getLazyCompoundValData(store, region)); } NonLoc makeZeroArrayIndex() { @@ -165,60 +167,63 @@ public: return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy)); } - SVal convertToArrayIndex(SVal V); + SVal convertToArrayIndex(SVal val); - nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) { - return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(), - I->getType()->isUnsignedIntegerType())); + nonloc::ConcreteInt makeIntVal(const IntegerLiteral* integer) { + return nonloc::ConcreteInt( + BasicVals.getValue(integer->getValue(), + integer->getType()->isUnsignedIntegerType())); } - nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *E) { - return makeTruthVal(E->getValue()); + nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean) { + return makeTruthVal(boolean->getValue()); } - nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) { - return nonloc::ConcreteInt(BasicVals.getValue(V)); + nonloc::ConcreteInt makeIntVal(const llvm::APSInt& integer) { + return nonloc::ConcreteInt(BasicVals.getValue(integer)); } - loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) { - return loc::ConcreteInt(BasicVals.getValue(v)); + loc::ConcreteInt makeIntLocVal(const llvm::APSInt &integer) { + return loc::ConcreteInt(BasicVals.getValue(integer)); } - NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned)); + NonLoc makeIntVal(const llvm::APInt& integer, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getValue(integer, isUnsigned)); } - DefinedSVal makeIntVal(uint64_t X, QualType T) { - if (Loc::isLocType(T)) - return loc::ConcreteInt(BasicVals.getValue(X, T)); + DefinedSVal makeIntVal(uint64_t integer, QualType type) { + if (Loc::isLocType(type)) + return loc::ConcreteInt(BasicVals.getValue(integer, type)); - return nonloc::ConcreteInt(BasicVals.getValue(X, T)); + return nonloc::ConcreteInt(BasicVals.getValue(integer, type)); } - NonLoc makeIntVal(uint64_t X, bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned)); + NonLoc makeIntVal(uint64_t integer, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getIntValue(integer, isUnsigned)); } - NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned)); + NonLoc makeIntValWithPtrWidth(uint64_t integer, bool isUnsigned) { + return nonloc::ConcreteInt( + BasicVals.getIntWithPtrWidth(integer, isUnsigned)); } - NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned)); + NonLoc makeIntVal(uint64_t integer, unsigned bitWidth, bool isUnsigned) { + return nonloc::ConcreteInt( + BasicVals.getValue(integer, bitWidth, isUnsigned)); } - NonLoc makeLocAsInteger(Loc V, unsigned Bits) { - return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(V, Bits)); + NonLoc makeLocAsInteger(Loc loc, unsigned bits) { + return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(loc, bits)); } NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType T); + const llvm::APSInt& rhs, QualType type); NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, - const SymExpr *rhs, QualType T); + const SymExpr *rhs, QualType type); - nonloc::ConcreteInt makeTruthVal(bool b, QualType T) { - return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T)); + nonloc::ConcreteInt makeTruthVal(bool b, QualType type) { + return nonloc::ConcreteInt(BasicVals.getTruthValue(b, type)); } nonloc::ConcreteInt makeTruthVal(bool b) { @@ -229,20 +234,20 @@ public: return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth()); } - Loc makeLoc(SymbolRef Sym) { - return loc::MemRegionVal(MemMgr.getSymbolicRegion(Sym)); + Loc makeLoc(SymbolRef sym) { + return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); } - Loc makeLoc(const MemRegion* R) { - return loc::MemRegionVal(R); + Loc makeLoc(const MemRegion* region) { + return loc::MemRegionVal(region); } - Loc makeLoc(const AddrLabelExpr *E) { - return loc::GotoLabel(E->getLabel()); + Loc makeLoc(const AddrLabelExpr *expr) { + return loc::GotoLabel(expr->getLabel()); } - Loc makeLoc(const llvm::APSInt& V) { - return loc::ConcreteInt(BasicVals.getValue(V)); + Loc makeLoc(const llvm::APSInt& integer) { + return loc::ConcreteInt(BasicVals.getValue(integer)); } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 0251311..21c6ae7 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_GR_STORE_H #define LLVM_CLANG_GR_STORE_H +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "llvm/ADT/DenseSet.h" @@ -28,36 +29,10 @@ class StackFrameContext; namespace ento { -/// Store - This opaque type encapsulates an immutable mapping from -/// locations to values. At a high-level, it represents the symbolic -/// memory model. Different subclasses of StoreManager may choose -/// different types to represent the locations and values. -typedef const void* Store; - class GRState; class GRStateManager; class SubRegionMap; -class StoreManager; - -class StoreRef { - Store store; - StoreManager &mgr; -public: - StoreRef(Store, StoreManager &); - StoreRef(const StoreRef &); - StoreRef &operator=(StoreRef const &); - - bool operator==(const StoreRef &x) const { - assert(&mgr == &x.mgr); - return x.store == store; - } - bool operator!=(const StoreRef &x) const { return !operator==(x); } - ~StoreRef(); - - Store getStore() const { return store; } -}; - class StoreManager { protected: SValBuilder &svalBuilder; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h new file mode 100644 index 0000000..0662ead --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h @@ -0,0 +1,50 @@ +//== StoreRef.h - Smart pointer for store objects ---------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the type StoreRef. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_STOREREF_H +#define LLVM_CLANG_GR_STOREREF_H + +#include <cassert> + +namespace clang { +namespace ento { + +/// Store - This opaque type encapsulates an immutable mapping from +/// locations to values. At a high-level, it represents the symbolic +/// memory model. Different subclasses of StoreManager may choose +/// different types to represent the locations and values. +typedef const void* Store; + +class StoreManager; + +class StoreRef { + Store store; + StoreManager &mgr; +public: + StoreRef(Store, StoreManager &); + StoreRef(const StoreRef &); + StoreRef &operator=(StoreRef const &); + + bool operator==(const StoreRef &x) const { + assert(&mgr == &x.mgr); + return x.store == store; + } + bool operator!=(const StoreRef &x) const { return !operator==(x); } + + ~StoreRef(); + + Store getStore() const { return store; } +}; + +}} +#endif |