clang  10.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 
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 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
42 
43 /// BugReporterVisitors are used to add custom diagnostics along a path.
44 class BugReporterVisitor : public llvm::FoldingSetNode {
45 public:
46  BugReporterVisitor() = default;
47  BugReporterVisitor(const BugReporterVisitor &) = default;
49  virtual ~BugReporterVisitor();
50 
51  /// Return a diagnostic piece which should be associated with the
52  /// given node.
53  /// Note that this function does *not* get run on the very last node
54  /// of the report, as the PathDiagnosticPiece associated with the
55  /// last node should be unique.
56  /// Use {@code getEndPath} to customize the note associated with the report
57  /// end instead.
58  ///
59  /// The last parameter can be used to register a new visitor with the given
60  /// BugReport while processing a node.
61  virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
62  BugReporterContext &BRC,
63  BugReport &BR) = 0;
64 
65  /// Last function called on the visitor, no further calls to VisitNode
66  /// would follow.
67  virtual void finalizeVisitor(BugReporterContext &BRC,
68  const ExplodedNode *EndPathNode,
69  BugReport &BR);
70 
71  /// Provide custom definition for the final diagnostic piece on the
72  /// path - the piece, which is displayed before the path is expanded.
73  ///
74  /// NOTE that this function can be implemented on at most one used visitor,
75  /// and otherwise it crahes at runtime.
77  getEndPath(BugReporterContext &BRC, const ExplodedNode *N,
78  BugReport &BR);
79 
80  virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
81 
82  /// Generates the default final diagnostic piece.
83  static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC,
84  const ExplodedNode *N,
85  const BugReport &BR);
86 };
87 
88 namespace bugreporter {
89 
90 /// Specifies the type of tracking for an expression.
91 enum class TrackingKind {
92  /// Default tracking kind -- specifies that as much information should be
93  /// gathered about the tracked expression value as possible.
94  Thorough,
95  /// Specifies that a more moderate tracking should be used for the expression
96  /// value. This will essentially make sure that functions relevant to the it
97  /// aren't pruned, but otherwise relies on the user reading the code or
98  /// following the arrows.
99  Condition
100 };
101 
102 /// Attempts to add visitors to track expression value back to its point of
103 /// origin.
104 ///
105 /// \param N A node "downstream" from the evaluation of the statement.
106 /// \param E The expression value which we are tracking
107 /// \param R The bug report to which visitors should be attached.
108 /// \param EnableNullFPSuppression Whether we should employ false positive
109 /// suppression (inlined defensive checks, returned null).
110 ///
111 /// \return Whether or not the function was able to add visitors for this
112 /// statement. Note that returning \c true does not actually imply
113 /// that any visitors were added.
114 bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R,
115  TrackingKind TKind = TrackingKind::Thorough,
116  bool EnableNullFPSuppression = true);
117 
118 const Expr *getDerefExpr(const Stmt *S);
119 
120 } // namespace bugreporter
121 
122 /// Finds last store into the given region,
123 /// which is different from a given symbolic value.
124 class FindLastStoreBRVisitor final : public BugReporterVisitor {
125  const MemRegion *R;
126  SVal V;
127  bool Satisfied = false;
128 
129  /// If the visitor is tracking the value directly responsible for the
130  /// bug, we are going to employ false positive suppression.
131  bool EnableNullFPSuppression;
132 
133  using TrackingKind = bugreporter::TrackingKind;
134  TrackingKind TKind;
135  const StackFrameContext *OriginSFC;
136 
137 public:
138  /// Creates a visitor for every VarDecl inside a Stmt and registers it with
139  /// the BugReport.
140  static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
141  bool EnableNullFPSuppression,
142  TrackingKind TKind);
143 
144  /// \param V We're searching for the store where \c R received this value.
145  /// \param R The region we're tracking.
146  /// \param TKind May limit the amount of notes added to the bug report.
147  /// \param OriginSFC Only adds notes when the last store happened in a
148  /// different stackframe to this one. Disregarded if the tracking kind
149  /// is thorough.
150  /// This is useful, because for non-tracked regions, notes about
151  /// changes to its value in a nested stackframe could be pruned, and
152  /// this visitor can prevent that without polluting the bugpath too
153  /// much.
154  FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
155  bool InEnableNullFPSuppression, TrackingKind TKind,
156  const StackFrameContext *OriginSFC = nullptr)
157  : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression),
158  TKind(TKind), OriginSFC(OriginSFC) {
159  assert(R);
160  }
161 
162  void Profile(llvm::FoldingSetNodeID &ID) const override;
163 
164  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
165  BugReporterContext &BRC,
166  BugReport &BR) override;
167 };
168 
169 class TrackConstraintBRVisitor final : public BugReporterVisitor {
170  DefinedSVal Constraint;
171  bool Assumption;
172  bool IsSatisfied = false;
173  bool IsZeroCheck;
174 
175  /// We should start tracking from the last node along the path in which the
176  /// value is constrained.
177  bool IsTrackingTurnedOn = false;
178 
179 public:
180  TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
181  : Constraint(constraint), Assumption(assumption),
182  IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {}
183 
184  void Profile(llvm::FoldingSetNodeID &ID) const override;
185 
186  /// Return the tag associated with this visitor. This tag will be used
187  /// to make all PathDiagnosticPieces created by this visitor.
188  static const char *getTag();
189 
190  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
191  BugReporterContext &BRC,
192  BugReport &BR) override;
193 
194 private:
195  /// Checks if the constraint is valid in the current state.
196  bool isUnderconstrained(const ExplodedNode *N) const;
197 };
198 
199 /// \class NilReceiverBRVisitor
200 /// Prints path notes when a message is sent to a nil receiver.
201 class NilReceiverBRVisitor final : public BugReporterVisitor {
202 public:
203  void Profile(llvm::FoldingSetNodeID &ID) const override {
204  static int x = 0;
205  ID.AddPointer(&x);
206  }
207 
208  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
209  BugReporterContext &BRC,
210  BugReport &BR) override;
211 
212  /// If the statement is a message send expression with nil receiver, returns
213  /// the receiver expression. Returns NULL otherwise.
214  static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
215 };
216 
217 /// Visitor that tries to report interesting diagnostics from conditions.
218 class ConditionBRVisitor final : public BugReporterVisitor {
219  // FIXME: constexpr initialization isn't supported by MSVC2013.
220  static const char *const GenericTrueMessage;
221  static const char *const GenericFalseMessage;
222 
223 public:
224  void Profile(llvm::FoldingSetNodeID &ID) const override {
225  static int x = 0;
226  ID.AddPointer(&x);
227  }
228 
229  /// Return the tag associated with this visitor. This tag will be used
230  /// to make all PathDiagnosticPieces created by this visitor.
231  static const char *getTag();
232 
233  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
234  BugReporterContext &BRC,
235  BugReport &BR) override;
236 
237  PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N,
238  BugReporterContext &BRC, BugReport &BR);
239 
240  PathDiagnosticPieceRef VisitTerminator(const Stmt *Term,
241  const ExplodedNode *N,
242  const CFGBlock *SrcBlk,
243  const CFGBlock *DstBlk, BugReport &R,
244  BugReporterContext &BRC);
245 
246  PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
247  BugReporterContext &BRC, BugReport &R,
248  const ExplodedNode *N, bool TookTrue);
249 
250  PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
251  BugReporterContext &BRC, BugReport &R,
252  const ExplodedNode *N, bool TookTrue,
253  bool IsAssuming);
254 
255  PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
256  const BinaryOperator *BExpr,
257  BugReporterContext &BRC, BugReport &R,
258  const ExplodedNode *N, bool TookTrue,
259  bool IsAssuming);
260 
261  PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME,
262  BugReporterContext &BRC, BugReport &R,
263  const ExplodedNode *N, bool TookTrue,
264  bool IsAssuming);
265 
267  VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
268  BugReporterContext &BRC, BugReport &R,
269  const ExplodedNode *N, bool TookTrue);
270 
271  /// Tries to print the value of the given expression.
272  ///
273  /// \param CondVarExpr The expression to print its value.
274  /// \param Out The stream to print.
275  /// \param N The node where we encountered the condition.
276  /// \param TookTrue Whether we took the \c true branch of the condition.
277  ///
278  /// \return Whether the print was successful. (The printing is successful if
279  /// we model the value and we could obtain it.)
280  bool printValue(const Expr *CondVarExpr, raw_ostream &Out,
281  const ExplodedNode *N, bool TookTrue, bool IsAssuming);
282 
283  bool patternMatch(const Expr *Ex,
284  const Expr *ParentEx,
285  raw_ostream &Out,
286  BugReporterContext &BRC,
287  BugReport &R,
288  const ExplodedNode *N,
289  Optional<bool> &prunable,
290  bool IsSameFieldName);
291 
292  static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
293 };
294 
295 /// Suppress reports that might lead to known false positives.
296 ///
297 /// Currently this suppresses reports based on locations of bugs.
298 class LikelyFalsePositiveSuppressionBRVisitor final
299  : public BugReporterVisitor {
300 public:
301  static void *getTag() {
302  static int Tag = 0;
303  return static_cast<void *>(&Tag);
304  }
305 
306  void Profile(llvm::FoldingSetNodeID &ID) const override {
307  ID.AddPointer(getTag());
308  }
309 
310  PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &,
311  BugReport &) override {
312  return nullptr;
313  }
314 
315  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
316  BugReport &BR) override;
317 };
318 
319 /// When a region containing undefined value or '0' value is passed
320 /// as an argument in a call, marks the call as interesting.
321 ///
322 /// As a result, BugReporter will not prune the path through the function even
323 /// if the region's contents are not modified/accessed by the call.
324 class UndefOrNullArgVisitor final : public BugReporterVisitor {
325  /// The interesting memory region this visitor is tracking.
326  const MemRegion *R;
327 
328 public:
329  UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
330 
331  void Profile(llvm::FoldingSetNodeID &ID) const override {
332  static int Tag = 0;
333  ID.AddPointer(&Tag);
334  ID.AddPointer(R);
335  }
336 
337  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
338  BugReporterContext &BRC,
339  BugReport &BR) override;
340 };
341 
342 class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
343  /// The symbolic value for which we are tracking constraints.
344  /// This value is constrained to null in the end of path.
345  DefinedSVal V;
346 
347  /// Track if we found the node where the constraint was first added.
348  bool IsSatisfied = false;
349 
350  /// Since the visitors can be registered on nodes previous to the last
351  /// node in the BugReport, but the path traversal always starts with the last
352  /// node, the visitor invariant (that we start with a node in which V is null)
353  /// might not hold when node visitation starts. We are going to start tracking
354  /// from the last node in which the value is null.
355  bool IsTrackingTurnedOn = false;
356 
357 public:
358  SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
359 
360  void Profile(llvm::FoldingSetNodeID &ID) const override;
361 
362  /// Return the tag associated with this visitor. This tag will be used
363  /// to make all PathDiagnosticPieces created by this visitor.
364  static const char *getTag();
365 
366  PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
367  BugReporterContext &BRC,
368  BugReport &BR) override;
369 };
370 
371 /// The bug visitor will walk all the nodes in a path and collect all the
372 /// constraints. When it reaches the root node, will create a refutation
373 /// manager and check if the constraints are satisfiable
374 class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor {
375 private:
376  /// Holds the constraints in a given path
377  ConstraintRangeTy Constraints;
378 
379 public:
380  FalsePositiveRefutationBRVisitor();
381 
382  void Profile(llvm::FoldingSetNodeID &ID) const override;
383 
384  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
385  BugReporterContext &BRC,
386  BugReport &BR) override;
387 
388  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
389  BugReport &BR) override;
390 };
391 
392 
393 /// The visitor detects NoteTags and displays the event notes they contain.
394 class TagVisitor : public BugReporterVisitor {
395 public:
396  void Profile(llvm::FoldingSetNodeID &ID) const override;
397 
398  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
399  BugReporterContext &BRC,
400  BugReport &R) override;
401 };
402 
403 } // namespace ento
404 
405 } // namespace clang
406 
407 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
llvm::ImmutableMap< SymbolRef, RangeSet > ConstraintRangeTy
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
#define V(N, I)
Definition: ASTContext.h:2898
Dataflow Directional Tag Classes.