aboutsummaryrefslogtreecommitdiffstats
path: root/include/clang/StaticAnalyzer/Core/BugReporter
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
commit13cc256e404620c1de0cbcc4e43ce1e2dbbc4898 (patch)
tree2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /include/clang/StaticAnalyzer/Core/BugReporter
parent657bc3d9848e3be92029b2416031340988cd0111 (diff)
downloadsrc-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')
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h89
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h58
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h129
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;
};