clang  9.0.0svn
BugReporterVisitors.h
Go to the documentation of this file.
1 //===- BugReporterVisitors.h - Generate PathDiagnostics ---------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file declares BugReporterVisitors, which are used to generate enhanced
10 // diagnostic traces.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
15 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
16 
17 #include "clang/Basic/LLVM.h"
20 #include "llvm/ADT/FoldingSet.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/ADT/StringRef.h"
23 #include <memory>
24 
25 namespace clang {
26 
27 class BinaryOperator;
28 class CFGBlock;
29 class DeclRefExpr;
30 class Expr;
31 class Stmt;
32 
33 namespace ento {
34 
35 class BugReport;
36 class BugReporterContext;
37 class ExplodedNode;
38 class MemRegion;
39 class PathDiagnosticPiece;
40 
41 /// BugReporterVisitors are used to add custom diagnostics along a path.
42 class BugReporterVisitor : public llvm::FoldingSetNode {
43 public:
44  BugReporterVisitor() = default;
45  BugReporterVisitor(const BugReporterVisitor &) = default;
47  virtual ~BugReporterVisitor();
48 
49  /// Return a diagnostic piece which should be associated with the
50  /// given node.
51  /// Note that this function does *not* get run on the very last node
52  /// of the report, as the PathDiagnosticPiece associated with the
53  /// last node should be unique.
54  /// Use {@code getEndPath} to customize the note associated with the report
55  /// end instead.
56  ///
57  /// The last parameter can be used to register a new visitor with the given
58  /// BugReport while processing a node.
59  virtual std::shared_ptr<PathDiagnosticPiece>
60  VisitNode(const ExplodedNode *Succ,
61  BugReporterContext &BRC, BugReport &BR) = 0;
62 
63  /// Last function called on the visitor, no further calls to VisitNode
64  /// would follow.
65  virtual void finalizeVisitor(BugReporterContext &BRC,
66  const ExplodedNode *EndPathNode,
67  BugReport &BR);
68 
69  /// Provide custom definition for the final diagnostic piece on the
70  /// path - the piece, which is displayed before the path is expanded.
71  ///
72  /// NOTE that this function can be implemented on at most one used visitor,
73  /// and otherwise it crahes at runtime.
74  virtual std::shared_ptr<PathDiagnosticPiece>
75  getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR);
76 
77  virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
78 
79  /// Generates the default final diagnostic piece.
80  static std::shared_ptr<PathDiagnosticPiece>
81  getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N,
82  BugReport &BR);
83 };
84 
85 /// Finds last store into the given region,
86 /// which is different from a given symbolic value.
87 class FindLastStoreBRVisitor final : public BugReporterVisitor {
88  const MemRegion *R;
89  SVal V;
90  bool Satisfied = false;
91 
92  /// If the visitor is tracking the value directly responsible for the
93  /// bug, we are going to employ false positive suppression.
94  bool EnableNullFPSuppression;
95 
96 public:
97  /// Creates a visitor for every VarDecl inside a Stmt and registers it with
98  /// the BugReport.
99  static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
100  bool EnableNullFPSuppression);
101 
102  FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
103  bool InEnableNullFPSuppression)
104  : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression) {}
105 
106  void Profile(llvm::FoldingSetNodeID &ID) const override;
107 
108  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
109  BugReporterContext &BRC,
110  BugReport &BR) override;
111 };
112 
113 class TrackConstraintBRVisitor final : public BugReporterVisitor {
114  DefinedSVal Constraint;
115  bool Assumption;
116  bool IsSatisfied = false;
117  bool IsZeroCheck;
118 
119  /// We should start tracking from the last node along the path in which the
120  /// value is constrained.
121  bool IsTrackingTurnedOn = false;
122 
123 public:
124  TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
125  : Constraint(constraint), Assumption(assumption),
126  IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {}
127 
128  void Profile(llvm::FoldingSetNodeID &ID) const override;
129 
130  /// Return the tag associated with this visitor. This tag will be used
131  /// to make all PathDiagnosticPieces created by this visitor.
132  static const char *getTag();
133 
134  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
135  BugReporterContext &BRC,
136  BugReport &BR) override;
137 
138 private:
139  /// Checks if the constraint is valid in the current state.
140  bool isUnderconstrained(const ExplodedNode *N) const;
141 };
142 
143 /// \class NilReceiverBRVisitor
144 /// Prints path notes when a message is sent to a nil receiver.
145 class NilReceiverBRVisitor final : public BugReporterVisitor {
146 public:
147  void Profile(llvm::FoldingSetNodeID &ID) const override {
148  static int x = 0;
149  ID.AddPointer(&x);
150  }
151 
152  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
153  BugReporterContext &BRC,
154  BugReport &BR) override;
155 
156  /// If the statement is a message send expression with nil receiver, returns
157  /// the receiver expression. Returns NULL otherwise.
158  static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
159 };
160 
161 /// Visitor that tries to report interesting diagnostics from conditions.
162 class ConditionBRVisitor final : public BugReporterVisitor {
163  // FIXME: constexpr initialization isn't supported by MSVC2013.
164  static const char *const GenericTrueMessage;
165  static const char *const GenericFalseMessage;
166 
167 public:
168  void Profile(llvm::FoldingSetNodeID &ID) const override {
169  static int x = 0;
170  ID.AddPointer(&x);
171  }
172 
173  /// Return the tag associated with this visitor. This tag will be used
174  /// to make all PathDiagnosticPieces created by this visitor.
175  static const char *getTag();
176 
177  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
178  BugReporterContext &BRC,
179  BugReport &BR) override;
180 
181  std::shared_ptr<PathDiagnosticPiece> VisitNodeImpl(const ExplodedNode *N,
182  BugReporterContext &BRC,
183  BugReport &BR);
184 
185  std::shared_ptr<PathDiagnosticPiece>
186  VisitTerminator(const Stmt *Term, const ExplodedNode *N,
187  const CFGBlock *srcBlk, const CFGBlock *dstBlk, BugReport &R,
188  BugReporterContext &BRC);
189 
190  std::shared_ptr<PathDiagnosticPiece>
191  VisitTrueTest(const Expr *Cond, bool tookTrue, BugReporterContext &BRC,
192  BugReport &R, const ExplodedNode *N);
193 
194  std::shared_ptr<PathDiagnosticPiece>
195  VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue,
196  BugReporterContext &BRC, BugReport &R, const ExplodedNode *N);
197 
198  std::shared_ptr<PathDiagnosticPiece>
199  VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
200  const bool tookTrue, BugReporterContext &BRC, BugReport &R,
201  const ExplodedNode *N);
202 
203  std::shared_ptr<PathDiagnosticPiece>
204  VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
205  const bool tookTrue, BugReporterContext &BRC,
206  BugReport &R, const ExplodedNode *N);
207 
208  bool patternMatch(const Expr *Ex,
209  const Expr *ParentEx,
210  raw_ostream &Out,
211  BugReporterContext &BRC,
212  BugReport &R,
213  const ExplodedNode *N,
214  Optional<bool> &prunable);
215 
216  static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
217 };
218 
219 /// Suppress reports that might lead to known false positives.
220 ///
221 /// Currently this suppresses reports based on locations of bugs.
222 class LikelyFalsePositiveSuppressionBRVisitor final
223  : public BugReporterVisitor {
224 public:
225  static void *getTag() {
226  static int Tag = 0;
227  return static_cast<void *>(&Tag);
228  }
229 
230  void Profile(llvm::FoldingSetNodeID &ID) const override {
231  ID.AddPointer(getTag());
232  }
233 
234  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *,
235  BugReporterContext &,
236  BugReport &) override {
237  return nullptr;
238  }
239 
240  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
241  BugReport &BR) override;
242 };
243 
244 /// When a region containing undefined value or '0' value is passed
245 /// as an argument in a call, marks the call as interesting.
246 ///
247 /// As a result, BugReporter will not prune the path through the function even
248 /// if the region's contents are not modified/accessed by the call.
249 class UndefOrNullArgVisitor final : public BugReporterVisitor {
250  /// The interesting memory region this visitor is tracking.
251  const MemRegion *R;
252 
253 public:
254  UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
255 
256  void Profile(llvm::FoldingSetNodeID &ID) const override {
257  static int Tag = 0;
258  ID.AddPointer(&Tag);
259  ID.AddPointer(R);
260  }
261 
262  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
263  BugReporterContext &BRC,
264  BugReport &BR) override;
265 };
266 
267 class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
268  /// The symbolic value for which we are tracking constraints.
269  /// This value is constrained to null in the end of path.
270  DefinedSVal V;
271 
272  /// Track if we found the node where the constraint was first added.
273  bool IsSatisfied = false;
274 
275  /// Since the visitors can be registered on nodes previous to the last
276  /// node in the BugReport, but the path traversal always starts with the last
277  /// node, the visitor invariant (that we start with a node in which V is null)
278  /// might not hold when node visitation starts. We are going to start tracking
279  /// from the last node in which the value is null.
280  bool IsTrackingTurnedOn = false;
281 
282 public:
283  SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
284 
285  void Profile(llvm::FoldingSetNodeID &ID) const override;
286 
287  /// Return the tag associated with this visitor. This tag will be used
288  /// to make all PathDiagnosticPieces created by this visitor.
289  static const char *getTag();
290 
291  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
292  BugReporterContext &BRC,
293  BugReport &BR) override;
294 };
295 
296 class CXXSelfAssignmentBRVisitor final : public BugReporterVisitor {
297  bool Satisfied = false;
298 
299 public:
300  CXXSelfAssignmentBRVisitor() = default;
301 
302  void Profile(llvm::FoldingSetNodeID &ID) const override {}
303 
304  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
305  BugReporterContext &BRC,
306  BugReport &BR) override;
307 };
308 
309 /// The bug visitor prints a diagnostic message at the location where a given
310 /// variable was tainted.
311 class TaintBugVisitor final : public BugReporterVisitor {
312 private:
313  const SVal V;
314 
315 public:
316  TaintBugVisitor(const SVal V) : V(V) {}
317  void Profile(llvm::FoldingSetNodeID &ID) const override { ID.Add(V); }
318 
319  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
320  BugReporterContext &BRC,
321  BugReport &BR) override;
322 };
323 
324 /// The bug visitor will walk all the nodes in a path and collect all the
325 /// constraints. When it reaches the root node, will create a refutation
326 /// manager and check if the constraints are satisfiable
327 class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor {
328 private:
329  /// Holds the constraints in a given path
330  ConstraintRangeTy Constraints;
331 
332 public:
333  FalsePositiveRefutationBRVisitor();
334 
335  void Profile(llvm::FoldingSetNodeID &ID) const override;
336 
337  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
338  BugReporterContext &BRC,
339  BugReport &BR) override;
340 
341  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
342  BugReport &BR) override;
343 };
344 
345 namespace bugreporter {
346 
347 /// Attempts to add visitors to track expression value back to its point of
348 /// origin.
349 ///
350 /// \param N A node "downstream" from the evaluation of the statement.
351 /// \param E The expression value which we are tracking
352 /// \param R The bug report to which visitors should be attached.
353 /// \param EnableNullFPSuppression Whether we should employ false positive
354 /// suppression (inlined defensive checks, returned null).
355 ///
356 /// \return Whether or not the function was able to add visitors for this
357 /// statement. Note that returning \c true does not actually imply
358 /// that any visitors were added.
359 bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R,
360  bool EnableNullFPSuppression = true);
361 
362 const Expr *getDerefExpr(const Stmt *S);
363 
364 } // namespace bugreporter
365 
366 } // namespace ento
367 
368 } // namespace clang
369 
370 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
llvm::ImmutableMap< SymbolRef, RangeSet > ConstraintRangeTy
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
Dataflow Directional Tag Classes.