summaryrefslogtreecommitdiffstats
path: root/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
blob: c023ed5641a3837b86683f034b95b465cff423f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
//===- BugReporterVisitors.h - Generate PathDiagnostics ---------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file declares BugReporterVisitors, which are used to generate enhanced
//  diagnostic traces.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H

#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include <memory>

namespace clang {

class BinaryOperator;
class CFGBlock;
class DeclRefExpr;
class Expr;
class Stmt;

namespace ento {

class BugReport;
class BugReporterContext;
class ExplodedNode;
class MemRegion;
class PathDiagnosticPiece;

/// BugReporterVisitors are used to add custom diagnostics along a path.
class BugReporterVisitor : public llvm::FoldingSetNode {
public:
  BugReporterVisitor() = default;
  BugReporterVisitor(const BugReporterVisitor &) = default;
  BugReporterVisitor(BugReporterVisitor &&) {}
  virtual ~BugReporterVisitor();

  /// Return a diagnostic piece which should be associated with the
  /// given node.
  /// Note that this function does *not* get run on the very last node
  /// of the report, as the PathDiagnosticPiece associated with the
  /// last node should be unique.
  /// Use {@code getEndPath} to customize the note associated with the report
  /// end instead.
  ///
  /// The last parameter can be used to register a new visitor with the given
  /// BugReport while processing a node.
  virtual std::shared_ptr<PathDiagnosticPiece>
  VisitNode(const ExplodedNode *Succ, 
            BugReporterContext &BRC, BugReport &BR) = 0;

  /// Last function called on the visitor, no further calls to VisitNode
  /// would follow.
  virtual void finalizeVisitor(BugReporterContext &BRC,
                               const ExplodedNode *EndPathNode,
                               BugReport &BR);

  /// Provide custom definition for the final diagnostic piece on the
  /// path - the piece, which is displayed before the path is expanded.
  ///
  /// NOTE that this function can be implemented on at most one used visitor,
  /// and otherwise it crahes at runtime.
  virtual std::shared_ptr<PathDiagnosticPiece>
  getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR);

  virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;

  /// Generates the default final diagnostic piece.
  static std::shared_ptr<PathDiagnosticPiece>
  getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N,
                    BugReport &BR);
};

/// Finds last store into the given region,
/// which is different from a given symbolic value.
class FindLastStoreBRVisitor final : public BugReporterVisitor {
  const MemRegion *R;
  SVal V;
  bool Satisfied = false;

  /// If the visitor is tracking the value directly responsible for the
  /// bug, we are going to employ false positive suppression.
  bool EnableNullFPSuppression;

public:
  /// Creates a visitor for every VarDecl inside a Stmt and registers it with
  /// the BugReport.
  static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
                                        bool EnableNullFPSuppression);

  FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
                         bool InEnableNullFPSuppression)
      : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression) {}

  void Profile(llvm::FoldingSetNodeID &ID) const override;

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;
};

class TrackConstraintBRVisitor final : public BugReporterVisitor {
  DefinedSVal Constraint;
  bool Assumption;
  bool IsSatisfied = false;
  bool IsZeroCheck;

  /// We should start tracking from the last node along the path in which the
  /// value is constrained.
  bool IsTrackingTurnedOn = false;

public:
  TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
      : Constraint(constraint), Assumption(assumption),
        IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {}

  void Profile(llvm::FoldingSetNodeID &ID) const override;

  /// Return the tag associated with this visitor.  This tag will be used
  /// to make all PathDiagnosticPieces created by this visitor.
  static const char *getTag();

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;

private:
  /// Checks if the constraint is valid in the current state.
  bool isUnderconstrained(const ExplodedNode *N) const;
};

/// \class NilReceiverBRVisitor
/// Prints path notes when a message is sent to a nil receiver.
class NilReceiverBRVisitor final : public BugReporterVisitor {
public:
  void Profile(llvm::FoldingSetNodeID &ID) const override {
    static int x = 0;
    ID.AddPointer(&x);
  }

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;

  /// If the statement is a message send expression with nil receiver, returns
  /// the receiver expression. Returns NULL otherwise.
  static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
};

/// Visitor that tries to report interesting diagnostics from conditions.
class ConditionBRVisitor final : public BugReporterVisitor {
  // FIXME: constexpr initialization isn't supported by MSVC2013.
  static const char *const GenericTrueMessage;
  static const char *const GenericFalseMessage;

public:
  void Profile(llvm::FoldingSetNodeID &ID) const override {
    static int x = 0;
    ID.AddPointer(&x);
  }

  /// Return the tag associated with this visitor.  This tag will be used
  /// to make all PathDiagnosticPieces created by this visitor.
  static const char *getTag();

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;

  std::shared_ptr<PathDiagnosticPiece> VisitNodeImpl(const ExplodedNode *N,
                                                     BugReporterContext &BRC,
                                                     BugReport &BR);

  std::shared_ptr<PathDiagnosticPiece>
  VisitTerminator(const Stmt *Term, const ExplodedNode *N,
                  const CFGBlock *srcBlk, const CFGBlock *dstBlk, BugReport &R,
                  BugReporterContext &BRC);

  std::shared_ptr<PathDiagnosticPiece>
  VisitTrueTest(const Expr *Cond, bool tookTrue, BugReporterContext &BRC,
                BugReport &R, const ExplodedNode *N);

  std::shared_ptr<PathDiagnosticPiece>
  VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue,
                BugReporterContext &BRC, BugReport &R, const ExplodedNode *N);

  std::shared_ptr<PathDiagnosticPiece>
  VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
                const bool tookTrue, BugReporterContext &BRC, BugReport &R,
                const ExplodedNode *N);

  std::shared_ptr<PathDiagnosticPiece>
  VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
                         const bool tookTrue, BugReporterContext &BRC,
                         BugReport &R, const ExplodedNode *N);

  bool patternMatch(const Expr *Ex,
                    const Expr *ParentEx,
                    raw_ostream &Out,
                    BugReporterContext &BRC,
                    BugReport &R,
                    const ExplodedNode *N,
                    Optional<bool> &prunable);

  static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
};

/// Suppress reports that might lead to known false positives.
///
/// Currently this suppresses reports based on locations of bugs.
class LikelyFalsePositiveSuppressionBRVisitor final
    : public BugReporterVisitor {
public:
  static void *getTag() {
    static int Tag = 0;
    return static_cast<void *>(&Tag);
  }

  void Profile(llvm::FoldingSetNodeID &ID) const override {
    ID.AddPointer(getTag());
  }

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *,
                                                 BugReporterContext &,
                                                 BugReport &) override {
    return nullptr;
  }

  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
                       BugReport &BR) override;
};

/// When a region containing undefined value or '0' value is passed
/// as an argument in a call, marks the call as interesting.
///
/// As a result, BugReporter will not prune the path through the function even
/// if the region's contents are not modified/accessed by the call.
class UndefOrNullArgVisitor final : public BugReporterVisitor {
  /// The interesting memory region this visitor is tracking.
  const MemRegion *R;

public:
  UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}

  void Profile(llvm::FoldingSetNodeID &ID) const override {
    static int Tag = 0;
    ID.AddPointer(&Tag);
    ID.AddPointer(R);
  }

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;
};

class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
  /// The symbolic value for which we are tracking constraints.
  /// This value is constrained to null in the end of path.
  DefinedSVal V;

  /// Track if we found the node where the constraint was first added.
  bool IsSatisfied = false;

  /// Since the visitors can be registered on nodes previous to the last
  /// node in the BugReport, but the path traversal always starts with the last
  /// node, the visitor invariant (that we start with a node in which V is null)
  /// might not hold when node visitation starts. We are going to start tracking
  /// from the last node in which the value is null.
  bool IsTrackingTurnedOn = false;

public:
  SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);

  void Profile(llvm::FoldingSetNodeID &ID) const override;

  /// Return the tag associated with this visitor.  This tag will be used
  /// to make all PathDiagnosticPieces created by this visitor.
  static const char *getTag();

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;
};

class CXXSelfAssignmentBRVisitor final : public BugReporterVisitor {
  bool Satisfied = false;

public:
  CXXSelfAssignmentBRVisitor() = default;

  void Profile(llvm::FoldingSetNodeID &ID) const override {}

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;
};

/// The bug visitor prints a diagnostic message at the location where a given
/// variable was tainted.
class TaintBugVisitor final : public BugReporterVisitor {
private:
  const SVal V;

public:
  TaintBugVisitor(const SVal V) : V(V) {}
  void Profile(llvm::FoldingSetNodeID &ID) const override { ID.Add(V); }

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;
};

/// The bug visitor will walk all the nodes in a path and collect all the
/// constraints. When it reaches the root node, will create a refutation
/// manager and check if the constraints are satisfiable
class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor {
private:
  /// Holds the constraints in a given path
  ConstraintRangeTy Constraints;

public:
  FalsePositiveRefutationBRVisitor();

  void Profile(llvm::FoldingSetNodeID &ID) const override;

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;

  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
                       BugReport &BR) override;
};

namespace bugreporter {

/// Attempts to add visitors to track expression value back to its point of
/// origin.
///
/// \param N A node "downstream" from the evaluation of the statement.
/// \param E The expression value which we are tracking
/// \param R The bug report to which visitors should be attached.
/// \param EnableNullFPSuppression Whether we should employ false positive
///         suppression (inlined defensive checks, returned null).
///
/// \return Whether or not the function was able to add visitors for this
///         statement. Note that returning \c true does not actually imply
///         that any visitors were added.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R,
                          bool EnableNullFPSuppression = true);

const Expr *getDerefExpr(const Stmt *S);

} // namespace bugreporter

} // namespace ento

} // namespace clang

#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H