1 //===--- BugReporterVisitors.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_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
16 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
18 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
19 #include "llvm/ADT/FoldingSet.h"
27 class BugReporterContext;
30 class PathDiagnosticPiece;
32 /// \brief BugReporterVisitors are used to add custom diagnostics along a path.
34 /// Custom visitors should subclass the BugReporterVisitorImpl class for a
35 /// default implementation of the clone() method.
36 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
37 /// default implementation of clone() will NOT do the right thing, and you
38 /// will have to provide your own implementation.)
39 class BugReporterVisitor : public llvm::FoldingSetNode {
41 BugReporterVisitor() = default;
42 BugReporterVisitor(const BugReporterVisitor &) = default;
43 BugReporterVisitor(BugReporterVisitor &&) {}
44 virtual ~BugReporterVisitor();
46 /// \brief Returns a copy of this BugReporter.
48 /// Custom BugReporterVisitors should not override this method directly.
49 /// Instead, they should inherit from BugReporterVisitorImpl and provide
50 /// a protected or public copy constructor.
52 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
53 /// default implementation of clone() will NOT do the right thing, and you
54 /// will have to provide your own implementation.)
55 virtual std::unique_ptr<BugReporterVisitor> clone() const = 0;
57 /// \brief Return a diagnostic piece which should be associated with the
60 /// The last parameter can be used to register a new visitor with the given
61 /// BugReport while processing a node.
62 virtual std::shared_ptr<PathDiagnosticPiece>
63 VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred,
64 BugReporterContext &BRC, BugReport &BR) = 0;
66 /// \brief Provide custom definition for the final diagnostic piece on the
67 /// path - the piece, which is displayed before the path is expanded.
69 /// If returns NULL the default implementation will be used.
70 /// Also note that at most one visitor of a BugReport should generate a
71 /// non-NULL end of path diagnostic piece.
72 virtual std::unique_ptr<PathDiagnosticPiece>
73 getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR);
75 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
77 /// \brief Generates the default final diagnostic piece.
78 static std::unique_ptr<PathDiagnosticPiece>
79 getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N,
83 /// This class provides a convenience implementation for clone() using the
84 /// Curiously-Recurring Template Pattern. If you are implementing a custom
85 /// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public
86 /// or protected copy constructor.
88 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
89 /// default implementation of clone() will NOT do the right thing, and you
90 /// will have to provide your own implementation.)
91 template <class DERIVED>
92 class BugReporterVisitorImpl : public BugReporterVisitor {
93 std::unique_ptr<BugReporterVisitor> clone() const override {
94 return llvm::make_unique<DERIVED>(*static_cast<const DERIVED *>(this));
98 class FindLastStoreBRVisitor final
99 : 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 override;
123 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
124 const ExplodedNode *PrevN,
125 BugReporterContext &BRC,
126 BugReport &BR) override;
129 class TrackConstraintBRVisitor final
130 : public BugReporterVisitorImpl<TrackConstraintBRVisitor> {
131 DefinedSVal Constraint;
136 /// We should start tracking from the last node along the path in which the
137 /// value is constrained.
138 bool IsTrackingTurnedOn;
141 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
142 : Constraint(constraint), Assumption(assumption), IsSatisfied(false),
143 IsZeroCheck(!Assumption && Constraint.getAs<Loc>()),
144 IsTrackingTurnedOn(false) {}
146 void Profile(llvm::FoldingSetNodeID &ID) const override;
148 /// Return the tag associated with this visitor. This tag will be used
149 /// to make all PathDiagnosticPieces created by this visitor.
150 static const char *getTag();
152 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
153 const ExplodedNode *PrevN,
154 BugReporterContext &BRC,
155 BugReport &BR) override;
158 /// Checks if the constraint is valid in the current state.
159 bool isUnderconstrained(const ExplodedNode *N) const;
163 /// \class NilReceiverBRVisitor
164 /// \brief Prints path notes when a message is sent to a nil receiver.
165 class NilReceiverBRVisitor final
166 : public BugReporterVisitorImpl<NilReceiverBRVisitor> {
169 void Profile(llvm::FoldingSetNodeID &ID) const override {
174 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
175 const ExplodedNode *PrevN,
176 BugReporterContext &BRC,
177 BugReport &BR) override;
179 /// If the statement is a message send expression with nil receiver, returns
180 /// the receiver expression. Returns NULL otherwise.
181 static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
184 /// Visitor that tries to report interesting diagnostics from conditions.
185 class ConditionBRVisitor final
186 : public BugReporterVisitorImpl<ConditionBRVisitor> {
188 // FIXME: constexpr initialization isn't supported by MSVC2013.
189 static const char *const GenericTrueMessage;
190 static const char *const GenericFalseMessage;
193 void Profile(llvm::FoldingSetNodeID &ID) const override {
198 /// Return the tag associated with this visitor. This tag will be used
199 /// to make all PathDiagnosticPieces created by this visitor.
200 static const char *getTag();
202 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
203 const ExplodedNode *Prev,
204 BugReporterContext &BRC,
205 BugReport &BR) override;
207 std::shared_ptr<PathDiagnosticPiece> VisitNodeImpl(const ExplodedNode *N,
208 const ExplodedNode *Prev,
209 BugReporterContext &BRC,
212 std::shared_ptr<PathDiagnosticPiece>
213 VisitTerminator(const Stmt *Term, const ExplodedNode *N,
214 const CFGBlock *srcBlk, const CFGBlock *dstBlk, BugReport &R,
215 BugReporterContext &BRC);
217 std::shared_ptr<PathDiagnosticPiece>
218 VisitTrueTest(const Expr *Cond, bool tookTrue, BugReporterContext &BRC,
219 BugReport &R, const ExplodedNode *N);
221 std::shared_ptr<PathDiagnosticPiece>
222 VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue,
223 BugReporterContext &BRC, BugReport &R, const ExplodedNode *N);
225 std::shared_ptr<PathDiagnosticPiece>
226 VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
227 const bool tookTrue, BugReporterContext &BRC, BugReport &R,
228 const ExplodedNode *N);
230 std::shared_ptr<PathDiagnosticPiece>
231 VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
232 const bool tookTrue, BugReporterContext &BRC,
233 BugReport &R, const ExplodedNode *N);
235 bool patternMatch(const Expr *Ex,
236 const Expr *ParentEx,
238 BugReporterContext &BRC,
240 const ExplodedNode *N,
241 Optional<bool> &prunable);
243 static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
246 /// \brief Suppress reports that might lead to known false positives.
248 /// Currently this suppresses reports based on locations of bugs.
249 class LikelyFalsePositiveSuppressionBRVisitor final
250 : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
252 static void *getTag() {
254 return static_cast<void *>(&Tag);
257 void Profile(llvm::FoldingSetNodeID &ID) const override {
258 ID.AddPointer(getTag());
261 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
262 const ExplodedNode *Prev,
263 BugReporterContext &BRC,
264 BugReport &BR) override {
268 std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
269 const ExplodedNode *N,
270 BugReport &BR) override;
273 /// \brief When a region containing undefined value or '0' value is passed
274 /// as an argument in a call, marks the call as interesting.
276 /// As a result, BugReporter will not prune the path through the function even
277 /// if the region's contents are not modified/accessed by the call.
278 class UndefOrNullArgVisitor final
279 : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
281 /// The interesting memory region this visitor is tracking.
285 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
287 void Profile(llvm::FoldingSetNodeID &ID) const override {
293 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
294 const ExplodedNode *PrevN,
295 BugReporterContext &BRC,
296 BugReport &BR) override;
299 class SuppressInlineDefensiveChecksVisitor final
300 : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> {
301 /// The symbolic value for which we are tracking constraints.
302 /// This value is constrained to null in the end of path.
305 /// Track if we found the node where the constraint was first added.
308 /// Since the visitors can be registered on nodes previous to the last
309 /// node in the BugReport, but the path traversal always starts with the last
310 /// node, the visitor invariant (that we start with a node in which V is null)
311 /// might not hold when node visitation starts. We are going to start tracking
312 /// from the last node in which the value is null.
313 bool IsTrackingTurnedOn;
316 SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
318 void Profile(llvm::FoldingSetNodeID &ID) const override;
320 /// Return the tag associated with this visitor. This tag will be used
321 /// to make all PathDiagnosticPieces created by this visitor.
322 static const char *getTag();
324 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
325 const ExplodedNode *Pred,
326 BugReporterContext &BRC,
327 BugReport &BR) override;
330 class CXXSelfAssignmentBRVisitor final
331 : public BugReporterVisitorImpl<CXXSelfAssignmentBRVisitor> {
336 CXXSelfAssignmentBRVisitor() : Satisfied(false) {}
338 void Profile(llvm::FoldingSetNodeID &ID) const override {}
340 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
341 const ExplodedNode *Pred,
342 BugReporterContext &BRC,
343 BugReport &BR) override;
346 namespace bugreporter {
348 /// Attempts to add visitors to trace a null or undefined value back to its
349 /// point of origin, whether it is a symbol constrained to null or an explicit
352 /// \param N A node "downstream" from the evaluation of the statement.
353 /// \param S The statement whose value is null or undefined.
354 /// \param R The bug report to which visitors should be attached.
355 /// \param IsArg Whether the statement is an argument to an inlined function.
356 /// If this is the case, \p N \em must be the CallEnter node for
358 /// \param EnableNullFPSuppression Whether we should employ false positive
359 /// suppression (inlined defensive checks, returned null).
361 /// \return Whether or not the function was able to add visitors for this
362 /// statement. Note that returning \c true does not actually imply
363 /// that any visitors were added.
364 bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R,
366 bool EnableNullFPSuppression = true);
368 const Expr *getDerefExpr(const Stmt *S);
369 const Stmt *GetDenomExpr(const ExplodedNode *N);
370 const Stmt *GetRetValExpr(const ExplodedNode *N);
371 bool isDeclRefExprToReference(const Expr *E);
374 } // end namespace clang
375 } // end namespace ento
376 } // end namespace bugreporter