1 //===--- BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file declares BugReporterVisitors, which are used to generate enhanced
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_GR_BUGREPORTERVISITOR
16 #define LLVM_CLANG_GR_BUGREPORTERVISITOR
18 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
19 #include "llvm/ADT/FoldingSet.h"
26 class BugReporterContext;
29 class PathDiagnosticPiece;
31 /// \brief BugReporterVisitors are used to add custom diagnostics along a path.
33 /// Custom visitors should subclass the BugReporterVisitorImpl class for a
34 /// default implementation of the clone() method.
35 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
36 /// default implementation of clone() will NOT do the right thing, and you
37 /// will have to provide your own implementation.)
38 class BugReporterVisitor : public llvm::FoldingSetNode {
40 virtual ~BugReporterVisitor();
42 /// \brief Returns a copy of this BugReporter.
44 /// Custom BugReporterVisitors should not override this method directly.
45 /// Instead, they should inherit from BugReporterVisitorImpl and provide
46 /// a protected or public copy constructor.
48 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
49 /// default implementation of clone() will NOT do the right thing, and you
50 /// will have to provide your own implementation.)
51 virtual BugReporterVisitor *clone() const = 0;
53 /// \brief Return a diagnostic piece which should be associated with the
56 /// The last parameter can be used to register a new visitor with the given
57 /// BugReport while processing a node.
58 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
59 const ExplodedNode *Pred,
60 BugReporterContext &BRC,
63 /// \brief Provide custom definition for the final diagnostic piece on the
64 /// path - the piece, which is displayed before the path is expanded.
66 /// If returns NULL the default implementation will be used.
67 /// Also note that at most one visitor of a BugReport should generate a
68 /// non-NULL end of path diagnostic piece.
69 virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
70 const ExplodedNode *N,
73 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
75 /// \brief Generates the default final diagnostic piece.
76 static PathDiagnosticPiece *getDefaultEndPath(BugReporterContext &BRC,
77 const ExplodedNode *N,
82 /// This class provides a convenience implementation for clone() using the
83 /// Curiously-Recurring Template Pattern. If you are implementing a custom
84 /// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public
85 /// or protected copy constructor.
87 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
88 /// default implementation of clone() will NOT do the right thing, and you
89 /// will have to provide your own implementation.)
90 template <class DERIVED>
91 class BugReporterVisitorImpl : public BugReporterVisitor {
92 virtual BugReporterVisitor *clone() const {
93 return new DERIVED(*static_cast<const DERIVED *>(this));
97 class FindLastStoreBRVisitor
98 : public BugReporterVisitorImpl<FindLastStoreBRVisitor>
104 /// If the visitor is tracking the value directly responsible for the
105 /// bug, we are going to employ false positive suppression.
106 bool EnableNullFPSuppression;
109 /// Creates a visitor for every VarDecl inside a Stmt and registers it with
111 static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
112 bool EnableNullFPSuppression);
114 FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
115 bool InEnableNullFPSuppression)
119 EnableNullFPSuppression(InEnableNullFPSuppression) {}
121 void Profile(llvm::FoldingSetNodeID &ID) const;
123 PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
124 const ExplodedNode *PrevN,
125 BugReporterContext &BRC,
129 class TrackConstraintBRVisitor
130 : public BugReporterVisitorImpl<TrackConstraintBRVisitor>
132 DefinedSVal Constraint;
137 /// We should start tracking from the last node along the path in which the
138 /// value is constrained.
139 bool IsTrackingTurnedOn;
142 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
143 : Constraint(constraint), Assumption(assumption), IsSatisfied(false),
144 IsZeroCheck(!Assumption && Constraint.getAs<Loc>()),
145 IsTrackingTurnedOn(false) {}
147 void Profile(llvm::FoldingSetNodeID &ID) const;
149 /// Return the tag associated with this visitor. This tag will be used
150 /// to make all PathDiagnosticPieces created by this visitor.
151 static const char *getTag();
153 PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
154 const ExplodedNode *PrevN,
155 BugReporterContext &BRC,
159 /// Checks if the constraint is valid in the current state.
160 bool isUnderconstrained(const ExplodedNode *N) const;
164 /// \class NilReceiverBRVisitor
165 /// \brief Prints path notes when a message is sent to a nil receiver.
166 class NilReceiverBRVisitor
167 : public BugReporterVisitorImpl<NilReceiverBRVisitor> {
170 void Profile(llvm::FoldingSetNodeID &ID) const {
175 PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
176 const ExplodedNode *PrevN,
177 BugReporterContext &BRC,
180 /// If the statement is a message send expression with nil receiver, returns
181 /// the receiver expression. Returns NULL otherwise.
182 static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
185 /// Visitor that tries to report interesting diagnostics from conditions.
186 class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> {
188 void Profile(llvm::FoldingSetNodeID &ID) const {
193 /// Return the tag associated with this visitor. This tag will be used
194 /// to make all PathDiagnosticPieces created by this visitor.
195 static const char *getTag();
197 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
198 const ExplodedNode *Prev,
199 BugReporterContext &BRC,
202 PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N,
203 const ExplodedNode *Prev,
204 BugReporterContext &BRC,
207 PathDiagnosticPiece *VisitTerminator(const Stmt *Term,
208 const ExplodedNode *N,
209 const CFGBlock *srcBlk,
210 const CFGBlock *dstBlk,
212 BugReporterContext &BRC);
214 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
216 BugReporterContext &BRC,
218 const ExplodedNode *N);
220 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
221 const DeclRefExpr *DR,
223 BugReporterContext &BRC,
225 const ExplodedNode *N);
227 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
228 const BinaryOperator *BExpr,
230 BugReporterContext &BRC,
232 const ExplodedNode *N);
234 PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString,
235 const Expr *CondVarExpr,
237 BugReporterContext &BRC,
239 const ExplodedNode *N);
241 bool patternMatch(const Expr *Ex,
243 BugReporterContext &BRC,
245 const ExplodedNode *N,
246 Optional<bool> &prunable);
249 /// \brief Suppress reports that might lead to known false positives.
251 /// Currently this suppresses reports based on locations of bugs.
252 class LikelyFalsePositiveSuppressionBRVisitor
253 : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
255 static void *getTag() {
257 return static_cast<void *>(&Tag);
260 void Profile(llvm::FoldingSetNodeID &ID) const {
261 ID.AddPointer(getTag());
264 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
265 const ExplodedNode *Prev,
266 BugReporterContext &BRC,
271 virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
272 const ExplodedNode *N,
276 /// \brief When a region containing undefined value or '0' value is passed
277 /// as an argument in a call, marks the call as interesting.
279 /// As a result, BugReporter will not prune the path through the function even
280 /// if the region's contents are not modified/accessed by the call.
281 class UndefOrNullArgVisitor
282 : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
284 /// The interesting memory region this visitor is tracking.
288 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
290 virtual void Profile(llvm::FoldingSetNodeID &ID) const {
296 PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
297 const ExplodedNode *PrevN,
298 BugReporterContext &BRC,
302 class SuppressInlineDefensiveChecksVisitor
303 : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor>
305 /// The symbolic value for which we are tracking constraints.
306 /// This value is constrained to null in the end of path.
309 /// Track if we found the node where the constraint was first added.
312 /// Since the visitors can be registered on nodes previous to the last
313 /// node in the BugReport, but the path traversal always starts with the last
314 /// node, the visitor invariant (that we start with a node in which V is null)
315 /// might not hold when node visitation starts. We are going to start tracking
316 /// from the last node in which the value is null.
317 bool IsTrackingTurnedOn;
320 SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
322 void Profile(llvm::FoldingSetNodeID &ID) const;
324 /// Return the tag associated with this visitor. This tag will be used
325 /// to make all PathDiagnosticPieces created by this visitor.
326 static const char *getTag();
328 PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
329 const ExplodedNode *Pred,
330 BugReporterContext &BRC,
334 namespace bugreporter {
336 /// Attempts to add visitors to trace a null or undefined value back to its
337 /// point of origin, whether it is a symbol constrained to null or an explicit
340 /// \param N A node "downstream" from the evaluation of the statement.
341 /// \param S The statement whose value is null or undefined.
342 /// \param R The bug report to which visitors should be attached.
343 /// \param IsArg Whether the statement is an argument to an inlined function.
344 /// If this is the case, \p N \em must be the CallEnter node for
346 /// \param EnableNullFPSuppression Whether we should employ false positive
347 /// suppression (inlined defensive checks, returned null).
349 /// \return Whether or not the function was able to add visitors for this
350 /// statement. Note that returning \c true does not actually imply
351 /// that any visitors were added.
352 bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R,
354 bool EnableNullFPSuppression = true);
356 const Expr *getDerefExpr(const Stmt *S);
357 const Stmt *GetDenomExpr(const ExplodedNode *N);
358 const Stmt *GetRetValExpr(const ExplodedNode *N);
359 bool isDeclRefExprToReference(const Expr *E);
362 } // end namespace clang
363 } // end namespace ento
364 } // end namespace bugreporter
367 #endif //LLVM_CLANG_GR__BUGREPORTERVISITOR