diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
commit | 13cc256e404620c1de0cbcc4e43ce1e2dbbc4898 (patch) | |
tree | 2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /include/clang/StaticAnalyzer/Core/BugReporter | |
parent | 657bc3d9848e3be92029b2416031340988cd0111 (diff) | |
download | src-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.tar.gz src-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.zip |
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):vendor/clang/clang-release_32-r168974
Notes
Notes:
svn path=/vendor/clang/dist/; revision=243791
svn path=/vendor/clang/clang-release_32-r168974/; revision=243792; tag=vendor/clang/clang-release_32-r168974
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/BugReporter')
3 files changed, 229 insertions, 47 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 48393a379b39..b5a88ba9f6c6 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -24,6 +24,7 @@ #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/ImmutableSet.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallSet.h" namespace clang { @@ -95,6 +96,10 @@ protected: /// for multiple PathDiagnosticConsumers. llvm::SmallVector<Regions *, 2> interestingRegions; + /// A set of location contexts that correspoind to call sites which should be + /// considered "interesting". + llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts; + /// A set of custom visitors which generate "event" diagnostics at /// interesting points in the path. VisitorList Callbacks; @@ -111,6 +116,19 @@ protected: /// when reporting an issue. bool DoNotPrunePath; + /// Used to track unique reasons why a bug report might be invalid. + /// + /// \sa markInvalid + /// \sa removeInvalidation + typedef std::pair<const void *, const void *> InvalidationRecord; + + /// If non-empty, this bug report is likely a false positive and should not be + /// shown to the user. + /// + /// \sa markInvalid + /// \sa removeInvalidation + llvm::SmallSet<InvalidationRecord, 4> Invalidations; + private: // Used internally by BugReporter. Symbols &getInterestingSymbols(); @@ -147,7 +165,8 @@ public: PathDiagnosticLocation LocationToUnique) : BT(bt), DeclWithIssue(0), Description(desc), UniqueingLocation(LocationToUnique), - ErrorNode(errornode), ConfigurationChangeToken(0) {} + ErrorNode(errornode), ConfigurationChangeToken(0), + DoNotPrunePath(false) {} virtual ~BugReport(); @@ -158,8 +177,10 @@ public: const StringRef getDescription() const { return Description; } - const StringRef getShortDescription() const { - return ShortDescription.empty() ? Description : ShortDescription; + const StringRef getShortDescription(bool UseFallback = true) const { + if (ShortDescription.empty() && UseFallback) + return Description; + return ShortDescription; } /// Indicates whether or not any path pruning should take place @@ -172,14 +193,44 @@ public: void markInteresting(SymbolRef sym); void markInteresting(const MemRegion *R); void markInteresting(SVal V); + void markInteresting(const LocationContext *LC); bool isInteresting(SymbolRef sym); bool isInteresting(const MemRegion *R); bool isInteresting(SVal V); + bool isInteresting(const LocationContext *LC); unsigned getConfigurationChangeToken() const { return ConfigurationChangeToken; } + + /// Returns whether or not this report should be considered valid. + /// + /// Invalid reports are those that have been classified as likely false + /// positives after the fact. + bool isValid() const { + return Invalidations.empty(); + } + + /// Marks the current report as invalid, meaning that it is probably a false + /// positive and should not be reported to the user. + /// + /// The \p Tag and \p Data arguments are intended to be opaque identifiers for + /// this particular invalidation, where \p Tag represents the visitor + /// responsible for invalidation, and \p Data represents the reason this + /// visitor decided to invalidate the bug report. + /// + /// \sa removeInvalidation + void markInvalid(const void *Tag, const void *Data) { + Invalidations.insert(std::make_pair(Tag, Data)); + } + + /// Reverses the effects of a previous invalidation. + /// + /// \sa markInvalid + void removeInvalidation(const void *Tag, const void *Data) { + Invalidations.erase(std::make_pair(Tag, Data)); + } /// Return the canonical declaration, be it a method or class, where /// this issue semantically occurred. @@ -342,6 +393,11 @@ private: /// A vector of BugReports for tracking the allocated pointers and cleanup. std::vector<BugReportEquivClass *> EQClassesVector; + /// A map from PathDiagnosticPiece to the LocationContext of the inlined + /// function call it represents. + llvm::DenseMap<const PathDiagnosticCallPiece*, + const LocationContext*> LocationContextMap; + protected: BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), D(d) {} @@ -378,9 +434,14 @@ public: SourceManager& getSourceManager() { return D.getSourceManager(); } - virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic, + virtual bool generatePathDiagnostic(PathDiagnostic& pathDiagnostic, PathDiagnosticConsumer &PC, - ArrayRef<BugReport *> &bugReports) {} + ArrayRef<BugReport *> &bugReports) { + return true; + } + + bool RemoveUneededCalls(PathPieces &pieces, BugReport *R, + PathDiagnosticCallPiece *CallWithLoc = 0); void Register(BugType *BT); @@ -389,7 +450,7 @@ public: /// The reports are usually generated by the checkers. Further, they are /// folded based on the profile value, which is done to coalesce similar /// reports. - void EmitReport(BugReport *R); + void emitReport(BugReport *R); void EmitBasicReport(const Decl *DeclWithIssue, StringRef BugName, StringRef BugCategory, @@ -409,8 +470,10 @@ public: EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1); } - static bool classof(const BugReporter* R) { return true; } - + void addCallPieceLocationContextPair(const PathDiagnosticCallPiece *C, + const LocationContext *LC) { + LocationContextMap[C] = LC; + } private: llvm::StringMap<BugType *> StrBugTypes; @@ -440,7 +503,15 @@ public: /// engine. ProgramStateManager &getStateManager(); - virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, + /// Generates a path corresponding to one of the given bug reports. + /// + /// Which report is used for path generation is not specified. The + /// bug reporter will try to pick the shortest path, but this is not + /// guaranteed. + /// + /// \return True if the report was valid and a path was generated, + /// false if the reports should be considered invalid. + virtual bool generatePathDiagnostic(PathDiagnostic &PD, PathDiagnosticConsumer &PC, ArrayRef<BugReport*> &bugReports); diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h index f53c15f117c9..78e35ca82b89 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -100,7 +100,6 @@ class FindLastStoreBRVisitor const MemRegion *R; SVal V; bool satisfied; - const ExplodedNode *StoreSite; public: /// \brief Convenience method to create a visitor given only the MemRegion. @@ -114,7 +113,7 @@ public: static void registerStatementVarDecls(BugReport &BR, const Stmt *S); FindLastStoreBRVisitor(SVal v, const MemRegion *r) - : R(r), V(v), satisfied(false), StoreSite(0) { + : R(r), V(v), satisfied(false) { assert (!V.isUnknown() && "Cannot track unknown value."); // TODO: Does it make sense to allow undef values here? @@ -142,6 +141,10 @@ public: void Profile(llvm::FoldingSetNodeID &ID) const; + /// Return the tag associated with this visitor. This tag will be used + /// to make all PathDiagnosticPieces created by this visitor. + static const char *getTag(); + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, @@ -171,6 +174,9 @@ public: ID.AddPointer(&x); } + /// Return the tag associated with this visitor. This tag will be used + /// to make all PathDiagnosticPieces created by this visitor. + static const char *getTag(); virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, const ExplodedNode *Prev, @@ -223,15 +229,57 @@ public: const ExplodedNode *N, llvm::Optional<bool> &prunable); }; - + +/// \brief When a region containing undefined value or '0' value is passed +/// as an argument in a call, marks the call as interesting. +/// +/// 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> { + + /// The interesting memory region this visitor is tracking. + const MemRegion *R; + +public: + UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} + + virtual void Profile(llvm::FoldingSetNodeID &ID) const { + static int Tag = 0; + ID.AddPointer(&Tag); + ID.AddPointer(R); + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR); +}; + namespace bugreporter { -void addTrackNullOrUndefValueVisitor(const ExplodedNode *N, const Stmt *S, - BugReport *R); +/// Attempts to add visitors to trace a null or undefined value back to its +/// point of origin, whether it is a symbol constrained to null or an explicit +/// assignment. +/// +/// \param N A node "downstream" from the evaluation of the statement. +/// \param S The statement whose value is null or undefined. +/// \param R The bug report to which visitors should be attached. +/// \param IsArg Whether the statement is an argument to an inlined function. +/// If this is the case, \p N \em must be the CallEnter node for +/// the function. +/// +/// \return Whether or not the function was able to add visitors for this +/// statement. Note that returning \c true does not actually imply +/// that any visitors were added. +bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, + bool IsArg = false); const Stmt *GetDerefExpr(const ExplodedNode *N); const Stmt *GetDenomExpr(const ExplodedNode *N); const Stmt *GetRetValExpr(const ExplodedNode *N); +bool isDeclRefExprToReference(const Expr *E); + } // end namespace clang } // end namespace ento diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 973cfb109c05..6dc26e670344 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -52,7 +52,31 @@ class PathDiagnostic; class PathDiagnosticConsumer { public: - typedef std::vector<std::pair<StringRef, std::string> > FilesMade; + class PDFileEntry : public llvm::FoldingSetNode { + public: + PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {} + + typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles; + + /// \brief A vector of <consumer,file> pairs. + ConsumerFiles files; + + /// \brief A precomputed hash tag used for uniquing PDFileEntry objects. + const llvm::FoldingSetNodeID NodeID; + + /// \brief Used for profiling in the FoldingSet. + void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; } + }; + + struct FilesMade : public llvm::FoldingSet<PDFileEntry> { + llvm::BumpPtrAllocator Alloc; + + void addDiagnostic(const PathDiagnostic &PD, + StringRef ConsumerName, + StringRef fileName); + + PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD); + }; private: virtual void anchor(); @@ -73,7 +97,6 @@ public: virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } virtual bool supportsAllBlockEdges() const { return false; } - virtual bool useVerboseDescription() const { return true; } /// Return true if the PathDiagnosticConsumer supports individual /// PathDiagnostics that span multiple files. @@ -114,8 +137,6 @@ private: Kind kind) : K(kind), S(0), D(0), SM(&sm), Loc(genLocation(L)), Range(genRange()) { - assert(Loc.isValid()); - assert(Range.isValid()); } FullSourceLoc @@ -134,12 +155,14 @@ public: PathDiagnosticLocation(const Stmt *s, const SourceManager &sm, LocationOrAnalysisDeclContext lac) - : K(StmtK), S(s), D(0), SM(&sm), + : K(s->getLocStart().isValid() ? StmtK : SingleLocK), + S(K == StmtK ? s : 0), + D(0), SM(&sm), Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) { - assert(S); - assert(Loc.isValid()); - assert(Range.isValid()); + assert(K == SingleLocK || S); + assert(K == SingleLocK || Loc.isValid()); + assert(K == SingleLocK || Range.isValid()); } /// Create a location corresponding to the given declaration. @@ -297,12 +320,18 @@ private: const std::string str; const Kind kind; const DisplayHint Hint; + + /// A constant string that can be used to tag the PathDiagnosticPiece, + /// typically with the identification of the creator. The actual pointer + /// value is meant to be an identifier; the string itself is useful for + /// debugging. + StringRef Tag; + std::vector<SourceRange> ranges; - // Do not implement: - PathDiagnosticPiece(); - PathDiagnosticPiece(const PathDiagnosticPiece &P); - PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); + PathDiagnosticPiece() LLVM_DELETED_FUNCTION; + PathDiagnosticPiece(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION; + void operator=(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION; protected: PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); @@ -312,8 +341,18 @@ protected: public: virtual ~PathDiagnosticPiece(); - const std::string& getString() const { return str; } + llvm::StringRef getString() const { return str; } + /// Tag this PathDiagnosticPiece with the given C-string. + void setTag(const char *tag) { Tag = tag; } + + /// Return the opaque tag (if any) on the PathDiagnosticPiece. + const void *getTag() const { return Tag.data(); } + + /// Return the string representation of the tag. This is useful + /// for debugging. + StringRef getTagStr() const { return Tag; } + /// getDisplayHint - Return a hint indicating where the diagnostic should /// be displayed by the PathDiagnosticConsumer. DisplayHint getDisplayHint() const { return Hint; } @@ -338,10 +377,6 @@ public: /// Return the SourceRanges associated with this PathDiagnosticPiece. ArrayRef<SourceRange> getRanges() const { return ranges; } - static inline bool classof(const PathDiagnosticPiece *P) { - return true; - } - virtual void Profile(llvm::FoldingSetNodeID &ID) const; }; @@ -377,6 +412,10 @@ public: virtual void flattenLocations() { Pos.flatten(); } virtual void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == Event || P->getKind() == Macro; + } }; /// \brief Interface for classes constructing Stack hints. @@ -410,10 +449,6 @@ public: /// 'getMessageForX()' methods to construct a specific message. virtual std::string getMessage(const ExplodedNode *N); - /// Prints the ordinal form of the given integer, - /// only valid for ValNo : ValNo > 0. - void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out); - /// Produces the message of the following form: /// 'Msg via Nth parameter' virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex); @@ -629,14 +664,22 @@ public: class PathDiagnostic : public llvm::FoldingSetNode { const Decl *DeclWithIssue; std::string BugType; - std::string Desc; + std::string VerboseDesc; + std::string ShortDesc; std::string Category; std::deque<std::string> OtherDesc; + PathDiagnosticLocation Loc; PathPieces pathImpl; llvm::SmallVector<PathPieces *, 3> pathStack; PathDiagnostic(); // Do not implement. public: + PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype, + StringRef verboseDesc, StringRef shortDesc, + StringRef category); + + ~PathDiagnostic(); + const PathPieces &path; /// Return the path currently used by builders for constructing the @@ -659,16 +702,24 @@ public: void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } bool isWithinCall() const { return !pathStack.empty(); } - - // PathDiagnostic(); - PathDiagnostic(const Decl *DeclWithIssue, - StringRef bugtype, - StringRef desc, - StringRef category); - ~PathDiagnostic(); + void setEndOfPath(PathDiagnosticPiece *EndPiece) { + assert(!Loc.isValid() && "End location already set!"); + Loc = EndPiece->getLocation(); + assert(Loc.isValid() && "Invalid location for end-of-path piece"); + getActivePath().push_back(EndPiece); + } - StringRef getDescription() const { return Desc; } + void resetPath() { + pathStack.clear(); + pathImpl.clear(); + Loc = PathDiagnosticLocation(); + } + + StringRef getVerboseDescription() const { return VerboseDesc; } + StringRef getShortDescription() const { + return ShortDesc.empty() ? VerboseDesc : ShortDesc; + } StringRef getBugType() const { return BugType; } StringRef getCategory() const { return Category; } @@ -682,15 +733,27 @@ public: meta_iterator meta_end() const { return OtherDesc.end(); } void addMeta(StringRef s) { OtherDesc.push_back(s); } - PathDiagnosticLocation getLocation() const; + PathDiagnosticLocation getLocation() const { + assert(Loc.isValid() && "No end-of-path location set yet!"); + return Loc; + } void flattenLocations() { + Loc.flatten(); for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); I != E; ++I) (*I)->flattenLocations(); } - + + /// Profiles the diagnostic, independent of the path it references. + /// + /// This can be used to merge diagnostics that refer to the same issue + /// along different paths. void Profile(llvm::FoldingSetNodeID &ID) const; - + + /// Profiles the diagnostic, including its path. + /// + /// Two diagnostics with the same issue along different paths will generate + /// different profiles. void FullProfile(llvm::FoldingSetNodeID &ID) const; }; |