diff options
Diffstat (limited to 'include/clang/StaticAnalyzer/Core')
17 files changed, 466 insertions, 50 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index f02e48a4..3959de2 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -253,9 +253,18 @@ private: /// \sa getMaxTimesInlineLarge Optional<unsigned> MaxTimesInlineLarge; + /// \sa getMinCFGSizeTreatFunctionsAsLarge + Optional<unsigned> MinCFGSizeTreatFunctionsAsLarge; + /// \sa getMaxNodesPerTopLevelFunction Optional<unsigned> MaxNodesPerTopLevelFunction; + /// \sa shouldInlineLambdas + Optional<bool> InlineLambdas; + + /// \sa shouldWidenLoops + Optional<bool> WidenLoops; + /// A helper function that retrieves option for a given full-qualified /// checker name. /// Options for checkers can be specified via 'analyzer-config' command-line @@ -502,6 +511,13 @@ public: /// This is controlled by the 'max-times-inline-large' config option. unsigned getMaxTimesInlineLarge(); + /// Returns the number of basic blocks a function needs to have to be + /// considered large for the 'max-times-inline-large' config option. + /// + /// This is controlled by the 'min-cfg-size-treat-functions-as-large' config + /// option. + unsigned getMinCFGSizeTreatFunctionsAsLarge(); + /// Returns the maximum number of nodes the analyzer can generate while /// exploring a top level function (for each exploded graph). /// 150000 is default; 0 means no limit. @@ -509,6 +525,14 @@ public: /// This is controlled by the 'max-nodes' config option. unsigned getMaxNodesPerTopLevelFunction(); + /// Returns true if lambdas should be inlined. Otherwise a sink node will be + /// generated each time a LambdaExpr is visited. + bool shouldInlineLambdas(); + + /// Returns true if the analysis should try to widen loops. + /// This is controlled by the 'widen-loops' config option. + bool shouldWidenLoops(); + public: AnalyzerOptions() : AnalysisStoreOpt(RegionStoreModel), diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h index 83b05ec..197d27a 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -37,6 +37,9 @@ class PathDiagnosticPiece; /// will have to provide your own implementation.) class BugReporterVisitor : public llvm::FoldingSetNode { public: + BugReporterVisitor() = default; + BugReporterVisitor(const BugReporterVisitor &) = default; + BugReporterVisitor(BugReporterVisitor &&) {} virtual ~BugReporterVisitor(); /// \brief Returns a copy of this BugReporter. @@ -92,9 +95,8 @@ class BugReporterVisitorImpl : public BugReporterVisitor { } }; -class FindLastStoreBRVisitor - : public BugReporterVisitorImpl<FindLastStoreBRVisitor> -{ +class FindLastStoreBRVisitor final + : public BugReporterVisitorImpl<FindLastStoreBRVisitor> { const MemRegion *R; SVal V; bool Satisfied; @@ -124,9 +126,8 @@ public: BugReport &BR) override; }; -class TrackConstraintBRVisitor - : public BugReporterVisitorImpl<TrackConstraintBRVisitor> -{ +class TrackConstraintBRVisitor final + : public BugReporterVisitorImpl<TrackConstraintBRVisitor> { DefinedSVal Constraint; bool Assumption; bool IsSatisfied; @@ -161,8 +162,8 @@ private: /// \class NilReceiverBRVisitor /// \brief Prints path notes when a message is sent to a nil receiver. -class NilReceiverBRVisitor - : public BugReporterVisitorImpl<NilReceiverBRVisitor> { +class NilReceiverBRVisitor final + : public BugReporterVisitorImpl<NilReceiverBRVisitor> { public: void Profile(llvm::FoldingSetNodeID &ID) const override { @@ -181,7 +182,8 @@ public: }; /// Visitor that tries to report interesting diagnostics from conditions. -class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> { +class ConditionBRVisitor final + : public BugReporterVisitorImpl<ConditionBRVisitor> { public: void Profile(llvm::FoldingSetNodeID &ID) const override { static int x = 0; @@ -247,8 +249,8 @@ public: /// \brief Suppress reports that might lead to known false positives. /// /// Currently this suppresses reports based on locations of bugs. -class LikelyFalsePositiveSuppressionBRVisitor - : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> { +class LikelyFalsePositiveSuppressionBRVisitor final + : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> { public: static void *getTag() { static int Tag = 0; @@ -276,8 +278,8 @@ public: /// /// As a result, BugReporter will not prune the path through the function even /// if the region's contents are not modified/accessed by the call. -class UndefOrNullArgVisitor - : public BugReporterVisitorImpl<UndefOrNullArgVisitor> { +class UndefOrNullArgVisitor final + : public BugReporterVisitorImpl<UndefOrNullArgVisitor> { /// The interesting memory region this visitor is tracking. const MemRegion *R; @@ -297,9 +299,8 @@ public: BugReport &BR) override; }; -class SuppressInlineDefensiveChecksVisitor -: public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> -{ +class SuppressInlineDefensiveChecksVisitor final + : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> { /// The symbolic value for which we are tracking constraints. /// This value is constrained to null in the end of path. DefinedSVal V; diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 941d5240..35421f9 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -122,7 +122,7 @@ class PathDiagnosticRange : public SourceRange { public: bool isPoint; - PathDiagnosticRange(const SourceRange &R, bool isP = false) + PathDiagnosticRange(SourceRange R, bool isP = false) : SourceRange(R), isPoint(isP) {} PathDiagnosticRange() : isPoint(false) {} @@ -422,7 +422,6 @@ class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > { void flattenTo(PathPieces &Primary, PathPieces &Current, bool ShouldFlattenMacros) const; public: - ~PathPieces(); PathPieces flatten(bool ShouldFlattenMacros) const { PathPieces Result; diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index 099d763..1410af1 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -131,6 +131,21 @@ public: } }; +class ObjCMessageNil { + template <typename CHECKER> + static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkObjCMessageNil(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForObjCMessageNil( + CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); + } +}; + class PostObjCMessage { template <typename CHECKER> static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, @@ -514,6 +529,10 @@ struct ImplicitNullDerefEvent { bool IsLoad; ExplodedNode *SinkNode; BugReporter *BR; + // When true, the dereference is in the source code directly. When false, the + // dereference might happen later (for example pointer passed to a parameter + // that is marked with nonnull attribute.) + bool IsDirectDereference; }; /// \brief A helper class which wraps a boolean value set to false by default. diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 8a1a82b..bc9af49 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -89,11 +89,16 @@ class CheckName { explicit CheckName(StringRef Name) : Name(Name) {} public: - CheckName() {} - CheckName(const CheckName &Other) : Name(Other.Name) {} + CheckName() = default; StringRef getName() const { return Name; } }; +enum class ObjCMessageVisitKind { + Pre, + Post, + MessageNil +}; + class CheckerManager { const LangOptions LangOpts; AnalyzerOptionsRef AOptions; @@ -212,7 +217,7 @@ public: const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng) { - runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng); + runCheckersForObjCMessage(ObjCMessageVisitKind::Pre, Dst, Src, msg, Eng); } /// \brief Run checkers for post-visiting obj-c messages. @@ -221,12 +226,22 @@ public: const ObjCMethodCall &msg, ExprEngine &Eng, bool wasInlined = false) { - runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng, + runCheckersForObjCMessage(ObjCMessageVisitKind::Post, Dst, Src, msg, Eng, wasInlined); } + /// \brief Run checkers for visiting an obj-c message to nil. + void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMethodCall &msg, + ExprEngine &Eng) { + runCheckersForObjCMessage(ObjCMessageVisitKind::MessageNil, Dst, Src, msg, + Eng); + } + + /// \brief Run checkers for visiting obj-c messages. - void runCheckersForObjCMessage(bool isPreVisit, + void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng, @@ -458,6 +473,8 @@ public: void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); + void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn); + void _registerForPreCall(CheckCallFunc checkfn); void _registerForPostCall(CheckCallFunc checkfn); @@ -558,8 +575,14 @@ private: const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit); + /// Returns the checkers that have registered for callbacks of the + /// given \p Kind. + const std::vector<CheckObjCMessageFunc> & + getObjCMessageCheckers(ObjCMessageVisitKind Kind); + std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; + std::vector<CheckObjCMessageFunc> ObjCMessageNilCheckers; std::vector<CheckCallFunc> PreCallCheckers; std::vector<CheckCallFunc> PostCallCheckers; diff --git a/include/clang/StaticAnalyzer/Core/IssueHash.h b/include/clang/StaticAnalyzer/Core/IssueHash.h new file mode 100644 index 0000000..b3c4f14 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/IssueHash.h @@ -0,0 +1,51 @@ +//===---------- IssueHash.h - Generate identification hashes ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_STATICANALYZER_CORE_ISSUE_HASH_H +#define LLVM_CLANG_STATICANALYZER_CORE_ISSUE_HASH_H + +#include "llvm/ADT/SmallString.h" + +namespace clang { +class Decl; +class SourceManager; +class FullSourceLoc; +class LangOptions; + +/// \brief Get an MD5 hash to help identify bugs. +/// +/// This function returns a hash that helps identify bugs within a source file. +/// This identification can be utilized to diff diagnostic results on different +/// snapshots of a projects, or maintain a database of suppressed diagnotics. +/// +/// The hash contains the normalized text of the location associated with the +/// diagnostic. Normalization means removing the whitespaces. The associated +/// location is the either the last location of a diagnostic path or a uniqueing +/// location. The bugtype and the name of the checker is also part of the hash. +/// The last component is the string representation of the enclosing declaration +/// of the associated location. +/// +/// In case a new hash is introduced, the old one should still be maintained for +/// a while. One should not introduce a new hash for every change, it is +/// possible to introduce experimental hashes that may change in the future. +/// Such hashes should be marked as experimental using a comment in the plist +/// files. +llvm::SmallString<32> GetIssueHash(const SourceManager &SM, + FullSourceLoc &IssueLoc, + llvm::StringRef CheckerName, + llvm::StringRef BugType, const Decl *D, + const LangOptions &LangOpts); + +/// \brief Get the string representation of issue hash. See GetIssueHash() for +/// more information. +std::string GetIssueString(const SourceManager &SM, FullSourceLoc &IssueLoc, + llvm::StringRef CheckerName, llvm::StringRef BugType, + const Decl *D, const LangOptions &LangOpts); +} // namespace clang + +#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 63b8631..b09dffa 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -164,7 +164,8 @@ protected: /// \brief Used to specify non-argument regions that will be invalidated as a /// result of this call. - virtual void getExtraInvalidatedValues(ValueList &Values) const {} + virtual void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const {} public: virtual ~CallEvent() {} @@ -253,9 +254,16 @@ public: /// which the return value has already been bound to the origin expression. SVal getReturnValue() const; + /// \brief Returns true if the type of any of the non-null arguments satisfies + /// the condition. + bool hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const; + /// \brief Returns true if any of the arguments appear to represent callbacks. bool hasNonZeroCallbackArg() const; + /// \brief Returns true if any of the arguments is void*. + bool hasVoidPointerToNonConstArg() const; + /// \brief Returns true if any of the arguments are known to escape to long- /// term storage, even if this method will not modify them. // NOTE: The exact semantics of this are still being defined! @@ -472,7 +480,8 @@ protected: BlockCall(const BlockCall &Other) : CallEvent(Other) {} void cloneTo(void *Dest) const override { new (Dest) BlockCall(*this); } - void getExtraInvalidatedValues(ValueList &Values) const override; + void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const override; public: virtual const CallExpr *getOriginExpr() const { @@ -497,8 +506,55 @@ public: return BR->getDecl(); } + bool isConversionFromLambda() const { + const BlockDecl *BD = getDecl(); + if (!BD) + return false; + + return BD->isConversionFromLambda(); + } + + /// \brief For a block converted from a C++ lambda, returns the block + /// VarRegion for the variable holding the captured C++ lambda record. + const VarRegion *getRegionStoringCapturedLambda() const { + assert(isConversionFromLambda()); + const BlockDataRegion *BR = getBlockRegion(); + assert(BR && "Block converted from lambda must have a block region"); + + auto I = BR->referenced_vars_begin(); + assert(I != BR->referenced_vars_end()); + + return I.getCapturedRegion(); + } + RuntimeDefinition getRuntimeDefinition() const override { - return RuntimeDefinition(getDecl()); + if (!isConversionFromLambda()) + return RuntimeDefinition(getDecl()); + + // Clang converts lambdas to blocks with an implicit user-defined + // conversion operator method on the lambda record that looks (roughly) + // like: + // + // typedef R(^block_type)(P1, P2, ...); + // operator block_type() const { + // auto Lambda = *this; + // return ^(P1 p1, P2 p2, ...){ + // /* return Lambda(p1, p2, ...); */ + // }; + // } + // + // Here R is the return type of the lambda and P1, P2, ... are + // its parameter types. 'Lambda' is a fake VarDecl captured by the block + // that is initialized to a copy of the lambda. + // + // Sema leaves the body of a lambda-converted block empty (it is + // produced by CodeGen), so we can't analyze it directly. Instead, we skip + // the block body and analyze the operator() method on the captured lambda. + const VarDecl *LambdaVD = getRegionStoringCapturedLambda()->getDecl(); + const CXXRecordDecl *LambdaDecl = LambdaVD->getType()->getAsCXXRecordDecl(); + CXXMethodDecl* LambdaCallOperator = LambdaDecl->getLambdaCallOperator(); + + return RuntimeDefinition(LambdaCallOperator); } bool argumentsMayEscape() const override { @@ -521,7 +577,8 @@ public: /// it is written. class CXXInstanceCall : public AnyFunctionCall { protected: - void getExtraInvalidatedValues(ValueList &Values) const override; + void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const override; CXXInstanceCall(const CallExpr *CE, ProgramStateRef St, const LocationContext *LCtx) @@ -704,7 +761,8 @@ protected: CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){} void cloneTo(void *Dest) const override { new (Dest) CXXConstructorCall(*this); } - void getExtraInvalidatedValues(ValueList &Values) const override; + void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const override; public: virtual const CXXConstructExpr *getOriginExpr() const { @@ -803,7 +861,8 @@ protected: ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {} void cloneTo(void *Dest) const override { new (Dest) ObjCMethodCall(*this); } - void getExtraInvalidatedValues(ValueList &Values) const override; + void getExtraInvalidatedValues(ValueList &Values, + RegionAndSymbolInvalidationTraits *ETraits) const override; /// Check if the selector may have multiple definitions (may have overrides). virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index a4ff133..d4f014d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -224,13 +224,39 @@ public: } /// \brief Generate a sink node. Generating a sink stops exploration of the - /// given path. - ExplodedNode *generateSink(ProgramStateRef State = nullptr, - ExplodedNode *Pred = nullptr, + /// given path. To create a sink node for the purpose of reporting an error, + /// checkers should use generateErrorNode() instead. + ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred, const ProgramPointTag *Tag = nullptr) { return addTransitionImpl(State ? State : getState(), true, Pred, Tag); } + /// \brief Generate a transition to a node that will be used to report + /// an error. This node will be a sink. That is, it will stop exploration of + /// the given path. + /// + /// @param State The state of the generated node. + /// @param Tag The tag to uniquely identify the creation site. If null, + /// the default tag for the checker will be used. + ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr, + const ProgramPointTag *Tag = nullptr) { + return generateSink(State, Pred, + (Tag ? Tag : Location.getTag())); + } + + /// \brief Generate a transition to a node that will be used to report + /// an error. This node will not be a sink. That is, exploration will + /// continue along this path. + /// + /// @param State The state of the generated node. + /// @param Tag The tag to uniquely identify the creation site. If null, + /// the default tag for the checker will be used. + ExplodedNode * + generateNonFatalErrorNode(ProgramStateRef State = nullptr, + const ProgramPointTag *Tag = nullptr) { + return addTransition(State, (Tag ? Tag : Location.getTag())); + } + /// \brief Emit the diagnostics report. void emitReport(std::unique_ptr<BugReport> R) { Changed = true; @@ -287,6 +313,18 @@ private: bool MarkAsSink, ExplodedNode *P = nullptr, const ProgramPointTag *Tag = nullptr) { + // The analyzer may stop exploring if it sees a state it has previously + // visited ("cache out"). The early return here is a defensive check to + // prevent accidental caching out by checker API clients. Unless there is a + // tag or the client checker has requested that the generated node be + // marked as a sink, we assume that a client requesting a transition to a + // state that is the same as the predecessor state has made a mistake. We + // return the predecessor rather than cache out. + // + // TODO: We could potentially change the return to an assertion to alert + // clients to their mistake, but several checkers (including + // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation) + // rely upon the defensive behavior and would need to be updated. if (!State || (State == Pred->getState() && !Tag && !MarkAsSink)) return Pred; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h index e7ec1f4..8dda636 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h @@ -15,9 +15,13 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H #include "clang/AST/Stmt.h" +#include <tuple> namespace clang { +class Expr; +class VarDecl; + namespace ento { bool containsMacro(const Stmt *S); @@ -35,6 +39,9 @@ template <class T> bool containsStmt(const Stmt *S) { return false; } +std::pair<const clang::VarDecl *, const clang::Expr *> +parseAssignment(const Stmt *S); + } // end GR namespace } // end clang namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index f876096..9a858c2 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -99,6 +99,35 @@ public: return ProgramStatePair(StTrue, StFalse); } + virtual ProgramStateRef assumeWithinInclusiveRange(ProgramStateRef State, + NonLoc Value, + const llvm::APSInt &From, + const llvm::APSInt &To, + bool InBound) = 0; + + virtual ProgramStatePair assumeWithinInclusiveRangeDual( + ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, + const llvm::APSInt &To) { + ProgramStateRef StInRange = assumeWithinInclusiveRange(State, Value, From, + To, true); + + // If StTrue is infeasible, asserting the falseness of Cond is unnecessary + // because the existing constraints already establish this. + if (!StInRange) + return ProgramStatePair((ProgramStateRef)nullptr, State); + + ProgramStateRef StOutOfRange = assumeWithinInclusiveRange(State, Value, + From, To, false); + if (!StOutOfRange) { + // We are careful to return the original state, /not/ StTrue, + // because we want to avoid having callers generate a new node + // in the ExplodedGraph. + return ProgramStatePair(State, (ProgramStateRef)nullptr); + } + + return ProgramStatePair(StInRange, StOutOfRange); + } + /// \brief If a symbol is perfectly constrained to a constant, attempt /// to return the concrete value. /// diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h new file mode 100644 index 0000000..555191d --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h @@ -0,0 +1,57 @@ +//== DynamicTypeMap.h - Dynamic type map ----------------------- -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides APIs for tracking dynamic type information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "llvm/ADT/ImmutableMap.h" + +namespace clang { +namespace ento { + +/// The GDM component containing the dynamic type info. This is a map from a +/// symbol to its most likely type. +struct DynamicTypeMap {}; +typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo> + DynamicTypeMapImpl; +template <> +struct ProgramStateTrait<DynamicTypeMap> + : public ProgramStatePartialTrait<DynamicTypeMapImpl> { + static void *GDMIndex() { + static int index = 0; + return &index; + } +}; + +/// \brief Get dynamic type information for a region. +DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, + const MemRegion *Reg); + +/// \brief Set dynamic type information of the region; return the new state. +ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg, + DynamicTypeInfo NewTy); + +/// \brief Set dynamic type information of the region; return the new state. +inline ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, + const MemRegion *Reg, QualType NewTy, + bool CanBeSubClassed = true) { + return setDynamicTypeInfo(State, Reg, + DynamicTypeInfo(NewTy, CanBeSubClassed)); +} + +} // ento +} // clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index d8f1c34..99083c9 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -341,6 +341,10 @@ public: void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst); + /// VisitLambdaExpr - Transfer function logic for LambdaExprs. + void VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst); @@ -600,6 +604,28 @@ private: const LocationContext *LC, const Expr *E, const Expr *ResultE = nullptr); + + /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG + /// block to find the constructor expression that directly constructed into + /// the storage for this statement. Returns null if the constructor for this + /// statement created a temporary object region rather than directly + /// constructing into an existing region. + const CXXConstructExpr *findDirectConstructorForCurrentCFGElement(); + + /// For a CXXConstructExpr, walk forward in the current CFG block to find the + /// CFGElement for the DeclStmt or CXXInitCtorInitializer for which is + /// directly constructed by this constructor. Returns None if the current + /// constructor expression did not directly construct into an existing + /// region. + Optional<CFGElement> findElementDirectlyInitializedByCurrentConstructor(); + + /// For a given constructor, look forward in the current CFG block to + /// determine the region into which an object will be constructed by \p CE. + /// Returns either a field or local variable region if the object will be + /// directly constructed in an existing region or a temporary object region + /// if not. + const MemRegion *getRegionForConstructedObject(const CXXConstructExpr *CE, + ExplodedNode *Pred); }; /// Traits for storing the call processing policy inside GDM. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h index faa3500..ce81c98 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H +#include "clang/AST/Decl.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -22,7 +23,6 @@ #include <deque> namespace clang { -class Decl; namespace ento { typedef std::deque<Decl*> SetOfDecls; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h new file mode 100644 index 0000000..3168733 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h @@ -0,0 +1,36 @@ +//===--- LoopWidening.h - Widen loops ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This header contains the declarations of functions which are used to widen +/// loops which do not otherwise exit. The widening is done by invalidating +/// anything which might be modified by the body of the loop. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H + +#include "clang/Analysis/CFG.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" + +namespace clang { +namespace ento { + +/// \brief Get the states that result from widening the loop. +/// +/// Widen the loop by invalidating anything that might be modified +/// by the loop body in any iteration. +ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, + const LocationContext *LCtx, + unsigned BlockCount, const Stmt *LoopStmt); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 4f07129..bb835c4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -19,6 +19,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" @@ -46,7 +47,7 @@ class RegionOffset { /// The base region. const MemRegion *R; - /// The bit offset within the base region. It shouldn't be negative. + /// The bit offset within the base region. Can be negative. int64_t Offset; public: @@ -1333,7 +1334,12 @@ public: /// Tells that a region's contents is not changed. TK_PreserveContents = 0x1, /// Suppress pointer-escaping of a region. - TK_SuppressEscape = 0x2 + TK_SuppressEscape = 0x2, + // Do not invalidate super region. + TK_DoNotInvalidateSuperRegion = 0x4, + /// When applied to a MemSpaceRegion, indicates the entire memory space + /// should be invalidated. + TK_EntireMemSpace = 0x8 // Do not forget to extend StorageTypeForKinds if number of traits exceed // the number of bits StorageTypeForKinds can store. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index ac4e452..c4a62ec 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -190,6 +190,27 @@ public: DefinedOrUnknownSVal upperBound, bool assumption, QualType IndexType = QualType()) const; + + /// Assumes that the value of \p Val is bounded with [\p From; \p To] + /// (if \p assumption is "true") or it is fully out of this range + /// (if \p assumption is "false"). + /// + /// This returns a new state with the added constraint on \p cond. + /// If no new state is feasible, NULL is returned. + ProgramStateRef assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, + const llvm::APSInt &From, + const llvm::APSInt &To, + bool assumption) const; + + /// Assumes given range both "true" and "false" for \p Val, and returns both + /// corresponding states (respectively). + /// + /// This is more efficient than calling assume() twice. Note that one (but not + /// both) of the returned states may be NULL. + std::pair<ProgramStateRef, ProgramStateRef> + assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, const llvm::APSInt &From, + const llvm::APSInt &To) const; + /// \brief Check if the given SVal is constrained to zero or is a zero /// constant. @@ -337,20 +358,6 @@ public: bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const; bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const; - /// \brief Get dynamic type information for a region. - DynamicTypeInfo getDynamicTypeInfo(const MemRegion *Reg) const; - - /// \brief Set dynamic type information of the region; return the new state. - ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg, - DynamicTypeInfo NewTy) const; - - /// \brief Set dynamic type information of the region; return the new state. - ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg, - QualType NewTy, - bool CanBeSubClassed = true) const { - return setDynamicTypeInfo(Reg, DynamicTypeInfo(NewTy, CanBeSubClassed)); - } - //==---------------------------------------------------------------------==// // Accessing the Generic Data Map (GDM). //==---------------------------------------------------------------------==// @@ -650,6 +657,33 @@ ProgramState::assume(DefinedOrUnknownSVal Cond) const { ->assumeDual(this, Cond.castAs<DefinedSVal>()); } +inline ProgramStateRef +ProgramState::assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, + const llvm::APSInt &From, + const llvm::APSInt &To, + bool Assumption) const { + if (Val.isUnknown()) + return this; + + assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!"); + + return getStateManager().ConstraintMgr->assumeWithinInclusiveRange( + this, Val.castAs<NonLoc>(), From, To, Assumption); +} + +inline std::pair<ProgramStateRef, ProgramStateRef> +ProgramState::assumeWithinInclusiveRange(DefinedOrUnknownSVal Val, + const llvm::APSInt &From, + const llvm::APSInt &To) const { + if (Val.isUnknown()) + return std::make_pair(this, this); + + assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!"); + + return getStateManager().ConstraintMgr + ->assumeWithinInclusiveRangeDual(this, Val.castAs<NonLoc>(), From, To); +} + inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const { if (Optional<Loc> L = LV.getAs<Loc>()) return bindLoc(*L, V); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 1ca96a2..9dbfab2 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -639,6 +639,7 @@ public: } void markLive(const MemRegion *region); + void markElementIndicesLive(const MemRegion *region); /// \brief Set to the value of the symbolic store after /// StoreManager::removeDeadBindings has been called. @@ -650,14 +651,20 @@ private: }; class SymbolVisitor { +protected: + ~SymbolVisitor() = default; + public: + SymbolVisitor() = default; + SymbolVisitor(const SymbolVisitor &) = default; + SymbolVisitor(SymbolVisitor &&) {} + /// \brief A visitor method invoked by ProgramStateManager::scanReachableSymbols. /// /// The method returns \c true if symbols should continue be scanned and \c /// false otherwise. virtual bool VisitSymbol(SymbolRef sym) = 0; virtual bool VisitMemRegion(const MemRegion *region) { return true; } - virtual ~SymbolVisitor(); }; } // end GR namespace |