clang  7.0.0svn
BugReporterVisitors.h
Go to the documentation of this file.
1 //===- BugReporterVisitors.h - Generate PathDiagnostics ---------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file declares BugReporterVisitors, which are used to generate enhanced
11 // diagnostic traces.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
16 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
17 
18 #include "clang/Basic/LLVM.h"
21 #include "llvm/ADT/FoldingSet.h"
22 #include "llvm/ADT/STLExtras.h"
23 #include "llvm/ADT/StringRef.h"
24 #include <memory>
25 
26 namespace clang {
27 
28 class BinaryOperator;
29 class CFGBlock;
30 class DeclRefExpr;
31 class Expr;
32 class Stmt;
33 
34 namespace ento {
35 
36 class BugReport;
37 class BugReporterContext;
38 class ExplodedNode;
39 class MemRegion;
40 class PathDiagnosticPiece;
41 
42 /// BugReporterVisitors are used to add custom diagnostics along a path.
43 ///
44 /// Custom visitors should subclass the BugReporterVisitorImpl class for a
45 /// default implementation of the clone() method.
46 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
47 /// default implementation of clone() will NOT do the right thing, and you
48 /// will have to provide your own implementation.)
49 class BugReporterVisitor : public llvm::FoldingSetNode {
50 public:
51  BugReporterVisitor() = default;
52  BugReporterVisitor(const BugReporterVisitor &) = default;
54  virtual ~BugReporterVisitor();
55 
56  /// Returns a copy of this BugReporter.
57  ///
58  /// Custom BugReporterVisitors should not override this method directly.
59  /// Instead, they should inherit from BugReporterVisitorImpl and provide
60  /// a protected or public copy constructor.
61  ///
62  /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
63  /// default implementation of clone() will NOT do the right thing, and you
64  /// will have to provide your own implementation.)
65  virtual std::unique_ptr<BugReporterVisitor> clone() const = 0;
66 
67  /// Return a diagnostic piece which should be associated with the
68  /// given node.
69  ///
70  /// The last parameter can be used to register a new visitor with the given
71  /// BugReport while processing a node.
72  virtual std::shared_ptr<PathDiagnosticPiece>
73  VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred,
74  BugReporterContext &BRC, BugReport &BR) = 0;
75 
76  /// Last function called on the visitor, no further calls to VisitNode
77  /// would follow.
78  virtual void finalizeVisitor(BugReporterContext &BRC,
79  const ExplodedNode *EndPathNode,
80  BugReport &BR);
81 
82  /// Provide custom definition for the final diagnostic piece on the
83  /// path - the piece, which is displayed before the path is expanded.
84  ///
85  /// NOTE that this function can be implemented on at most one used visitor,
86  /// and otherwise it crahes at runtime.
87  virtual std::unique_ptr<PathDiagnosticPiece>
89 
90  virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
91 
92  /// Generates the default final diagnostic piece.
93  static std::unique_ptr<PathDiagnosticPiece>
95  BugReport &BR);
96 };
97 
98 /// This class provides a convenience implementation for clone() using the
99 /// Curiously-Recurring Template Pattern. If you are implementing a custom
100 /// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public
101 /// or protected copy constructor.
102 ///
103 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
104 /// default implementation of clone() will NOT do the right thing, and you
105 /// will have to provide your own implementation.)
106 template <class DERIVED>
108  std::unique_ptr<BugReporterVisitor> clone() const override {
109  return llvm::make_unique<DERIVED>(*static_cast<const DERIVED *>(this));
110  }
111 };
112 
114  : public BugReporterVisitorImpl<FindLastStoreBRVisitor> {
115  const MemRegion *R;
116  SVal V;
117  bool Satisfied = false;
118 
119  /// If the visitor is tracking the value directly responsible for the
120  /// bug, we are going to employ false positive suppression.
121  bool EnableNullFPSuppression;
122 
123 public:
124  /// Creates a visitor for every VarDecl inside a Stmt and registers it with
125  /// the BugReport.
126  static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
127  bool EnableNullFPSuppression);
128 
130  bool InEnableNullFPSuppression)
131  : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression) {}
132 
133  void Profile(llvm::FoldingSetNodeID &ID) const override;
134 
135  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
136  const ExplodedNode *PrevN,
137  BugReporterContext &BRC,
138  BugReport &BR) override;
139 };
140 
142  : public BugReporterVisitorImpl<TrackConstraintBRVisitor> {
143  DefinedSVal Constraint;
144  bool Assumption;
145  bool IsSatisfied = false;
146  bool IsZeroCheck;
147 
148  /// We should start tracking from the last node along the path in which the
149  /// value is constrained.
150  bool IsTrackingTurnedOn = false;
151 
152 public:
153  TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
154  : Constraint(constraint), Assumption(assumption),
155  IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {}
156 
157  void Profile(llvm::FoldingSetNodeID &ID) const override;
158 
159  /// Return the tag associated with this visitor. This tag will be used
160  /// to make all PathDiagnosticPieces created by this visitor.
161  static const char *getTag();
162 
163  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
164  const ExplodedNode *PrevN,
165  BugReporterContext &BRC,
166  BugReport &BR) override;
167 
168 private:
169  /// Checks if the constraint is valid in the current state.
170  bool isUnderconstrained(const ExplodedNode *N) const;
171 };
172 
173 /// \class NilReceiverBRVisitor
174 /// Prints path notes when a message is sent to a nil receiver.
176  : public BugReporterVisitorImpl<NilReceiverBRVisitor> {
177 public:
178  void Profile(llvm::FoldingSetNodeID &ID) const override {
179  static int x = 0;
180  ID.AddPointer(&x);
181  }
182 
183  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
184  const ExplodedNode *PrevN,
185  BugReporterContext &BRC,
186  BugReport &BR) override;
187 
188  /// If the statement is a message send expression with nil receiver, returns
189  /// the receiver expression. Returns NULL otherwise.
190  static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
191 };
192 
193 /// Visitor that tries to report interesting diagnostics from conditions.
195  : public BugReporterVisitorImpl<ConditionBRVisitor> {
196  // FIXME: constexpr initialization isn't supported by MSVC2013.
197  static const char *const GenericTrueMessage;
198  static const char *const GenericFalseMessage;
199 
200 public:
201  void Profile(llvm::FoldingSetNodeID &ID) const override {
202  static int x = 0;
203  ID.AddPointer(&x);
204  }
205 
206  /// Return the tag associated with this visitor. This tag will be used
207  /// to make all PathDiagnosticPieces created by this visitor.
208  static const char *getTag();
209 
210  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
211  const ExplodedNode *Prev,
212  BugReporterContext &BRC,
213  BugReport &BR) override;
214 
215  std::shared_ptr<PathDiagnosticPiece> VisitNodeImpl(const ExplodedNode *N,
216  const ExplodedNode *Prev,
217  BugReporterContext &BRC,
218  BugReport &BR);
219 
220  std::shared_ptr<PathDiagnosticPiece>
221  VisitTerminator(const Stmt *Term, const ExplodedNode *N,
222  const CFGBlock *srcBlk, const CFGBlock *dstBlk, BugReport &R,
223  BugReporterContext &BRC);
224 
225  std::shared_ptr<PathDiagnosticPiece>
226  VisitTrueTest(const Expr *Cond, bool tookTrue, BugReporterContext &BRC,
227  BugReport &R, const ExplodedNode *N);
228 
229  std::shared_ptr<PathDiagnosticPiece>
230  VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue,
231  BugReporterContext &BRC, BugReport &R, const ExplodedNode *N);
232 
233  std::shared_ptr<PathDiagnosticPiece>
234  VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
235  const bool tookTrue, BugReporterContext &BRC, BugReport &R,
236  const ExplodedNode *N);
237 
238  std::shared_ptr<PathDiagnosticPiece>
239  VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
240  const bool tookTrue, BugReporterContext &BRC,
241  BugReport &R, const ExplodedNode *N);
242 
243  bool patternMatch(const Expr *Ex,
244  const Expr *ParentEx,
245  raw_ostream &Out,
246  BugReporterContext &BRC,
247  BugReport &R,
248  const ExplodedNode *N,
249  Optional<bool> &prunable);
250 
251  static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
252 };
253 
254 /// Suppress reports that might lead to known false positives.
255 ///
256 /// Currently this suppresses reports based on locations of bugs.
258  : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
259 public:
260  static void *getTag() {
261  static int Tag = 0;
262  return static_cast<void *>(&Tag);
263  }
264 
265  void Profile(llvm::FoldingSetNodeID &ID) const override {
266  ID.AddPointer(getTag());
267  }
268 
269  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
270  const ExplodedNode *Prev,
271  BugReporterContext &BRC,
272  BugReport &BR) override {
273  return nullptr;
274  }
275 
276  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
277  BugReport &BR) override;
278 };
279 
280 /// When a region containing undefined value or '0' value is passed
281 /// as an argument in a call, marks the call as interesting.
282 ///
283 /// As a result, BugReporter will not prune the path through the function even
284 /// if the region's contents are not modified/accessed by the call.
286  : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
287  /// The interesting memory region this visitor is tracking.
288  const MemRegion *R;
289 
290 public:
291  UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
292 
293  void Profile(llvm::FoldingSetNodeID &ID) const override {
294  static int Tag = 0;
295  ID.AddPointer(&Tag);
296  ID.AddPointer(R);
297  }
298 
299  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
300  const ExplodedNode *PrevN,
301  BugReporterContext &BRC,
302  BugReport &BR) override;
303 };
304 
306  : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> {
307  /// The symbolic value for which we are tracking constraints.
308  /// This value is constrained to null in the end of path.
309  DefinedSVal V;
310 
311  /// Track if we found the node where the constraint was first added.
312  bool IsSatisfied = false;
313 
314  /// Since the visitors can be registered on nodes previous to the last
315  /// node in the BugReport, but the path traversal always starts with the last
316  /// node, the visitor invariant (that we start with a node in which V is null)
317  /// might not hold when node visitation starts. We are going to start tracking
318  /// from the last node in which the value is null.
319  bool IsTrackingTurnedOn = false;
320 
321 public:
323 
324  void Profile(llvm::FoldingSetNodeID &ID) const override;
325 
326  /// Return the tag associated with this visitor. This tag will be used
327  /// to make all PathDiagnosticPieces created by this visitor.
328  static const char *getTag();
329 
330  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
331  const ExplodedNode *Pred,
332  BugReporterContext &BRC,
333  BugReport &BR) override;
334 };
335 
337  : public BugReporterVisitorImpl<CXXSelfAssignmentBRVisitor> {
338  bool Satisfied = false;
339 
340 public:
341  CXXSelfAssignmentBRVisitor() = default;
342 
343  void Profile(llvm::FoldingSetNodeID &ID) const override {}
344 
345  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
346  const ExplodedNode *Pred,
347  BugReporterContext &BRC,
348  BugReport &BR) override;
349 };
350 
351 /// The bug visitor prints a diagnostic message at the location where a given
352 /// variable was tainted.
353 class TaintBugVisitor final : public BugReporterVisitorImpl<TaintBugVisitor> {
354 private:
355  const SVal V;
356 
357 public:
358  TaintBugVisitor(const SVal V) : V(V) {}
359  void Profile(llvm::FoldingSetNodeID &ID) const override { ID.Add(V); }
360 
361  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
362  const ExplodedNode *PrevN,
363  BugReporterContext &BRC,
364  BugReport &BR) override;
365 };
366 
367 /// The bug visitor will walk all the nodes in a path and collect all the
368 /// constraints. When it reaches the root node, will create a refutation
369 /// manager and check if the constraints are satisfiable
371  : public BugReporterVisitorImpl<FalsePositiveRefutationBRVisitor> {
372 private:
373  /// Holds the constraints in a given path
374  // TODO: should we use a set?
376 
377 public:
379 
380  void Profile(llvm::FoldingSetNodeID &ID) const override;
381 
382  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
383  const ExplodedNode *PrevN,
384  BugReporterContext &BRC,
385  BugReport &BR) override;
386 };
387 
388 namespace bugreporter {
389 
390 /// Attempts to add visitors to trace a null or undefined value back to its
391 /// point of origin, whether it is a symbol constrained to null or an explicit
392 /// assignment.
393 ///
394 /// \param N A node "downstream" from the evaluation of the statement.
395 /// \param S The statement whose value is null or undefined.
396 /// \param R The bug report to which visitors should be attached.
397 /// \param IsArg Whether the statement is an argument to an inlined function.
398 /// If this is the case, \p N \em must be the CallEnter node for
399 /// the function.
400 /// \param EnableNullFPSuppression Whether we should employ false positive
401 /// suppression (inlined defensive checks, returned null).
402 ///
403 /// \return Whether or not the function was able to add visitors for this
404 /// statement. Note that returning \c true does not actually imply
405 /// that any visitors were added.
406 bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R,
407  bool IsArg = false,
408  bool EnableNullFPSuppression = true);
409 
410 const Expr *getDerefExpr(const Stmt *S);
411 const Stmt *GetDenomExpr(const ExplodedNode *N);
412 const Stmt *GetRetValExpr(const ExplodedNode *N);
413 bool isDeclRefExprToReference(const Expr *E);
414 
415 } // namespace bugreporter
416 
417 } // namespace ento
418 
419 } // namespace clang
420 
421 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:94
UndefOrNullArgVisitor(const MemRegion *InR)
Stmt - This represents one statement.
Definition: Stmt.h:66
void Profile(llvm::FoldingSetNodeID &ID) const override
virtual void Profile(llvm::FoldingSetNodeID &ID) const =0
TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
void Profile(llvm::FoldingSetNodeID &ID) const override
The bug visitor prints a diagnostic message at the location where a given variable was tainted...
Prints path notes when a message is sent to a nil receiver.
const Stmt * GetDenomExpr(const ExplodedNode *N)
Visitor that tries to report interesting diagnostics from conditions.
void Profile(llvm::FoldingSetNodeID &ID) const override
This class provides a convenience implementation for clone() using the Curiously-Recurring Template P...
virtual std::unique_ptr< PathDiagnosticPiece > getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR)
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
void Profile(llvm::FoldingSetNodeID &ID) const override
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3065
When a region containing undefined value or &#39;0&#39; value is passed as an argument in a call...
void Profile(llvm::FoldingSetNodeID &ID) const override
void Profile(llvm::FoldingSetNodeID &ID) const override
CFGBlock - Represents a single basic block in a source-level CFG.
Definition: CFG.h:548
Expr - This represents one expression.
Definition: Expr.h:106
BugReporterVisitors are used to add custom diagnostics along a path.
static std::unique_ptr< PathDiagnosticPiece > getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR)
Generates the default final diagnostic piece.
Suppress reports that might lead to known false positives.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:76
virtual std::unique_ptr< BugReporterVisitor > clone() const =0
Returns a copy of this BugReporter.
virtual std::shared_ptr< PathDiagnosticPiece > VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, BugReporterContext &BRC, BugReport &BR)=0
Return a diagnostic piece which should be associated with the given node.
bool isDeclRefExprToReference(const Expr *E)
Dataflow Directional Tag Classes.
virtual void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, BugReport &BR)
Last function called on the visitor, no further calls to VisitNode would follow.
std::shared_ptr< PathDiagnosticPiece > VisitNode(const ExplodedNode *N, const ExplodedNode *Prev, BugReporterContext &BRC, BugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
const Stmt * GetRetValExpr(const ExplodedNode *N)
Represents an SVal that is guaranteed to not be UnknownVal.
Definition: SVals.h:282
BugReporterVisitor(BugReporterVisitor &&)
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, bool IsArg=false, bool EnableNullFPSuppression=true)
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.
The bug visitor will walk all the nodes in a path and collect all the constraints.
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:972
This class provides an interface through which checkers can create individual bug reports...
Definition: BugReporter.h:70
FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R, bool InEnableNullFPSuppression)