Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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/Analysis/ProgramPoint.h"
18
#include "clang/Basic/LLVM.h"
19
#include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
20
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
21
#include "llvm/ADT/FoldingSet.h"
22
#include "llvm/ADT/IntrusiveRefCntPtr.h"
23
#include "llvm/ADT/STLExtras.h"
24
#include "llvm/ADT/SmallPtrSet.h"
25
#include "llvm/ADT/StringRef.h"
26
#include <list>
27
#include <memory>
28
#include <optional>
29
#include <utility>
30
 
31
namespace clang {
32
 
33
class BinaryOperator;
34
class CFGBlock;
35
class DeclRefExpr;
36
class Expr;
37
class Stmt;
38
 
39
namespace ento {
40
 
41
class PathSensitiveBugReport;
42
class BugReporterContext;
43
class ExplodedNode;
44
class MemRegion;
45
class PathDiagnosticPiece;
46
using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
47
 
48
/// BugReporterVisitors are used to add custom diagnostics along a path.
49
class BugReporterVisitor : public llvm::FoldingSetNode {
50
public:
51
  BugReporterVisitor() = default;
52
  BugReporterVisitor(const BugReporterVisitor &) = default;
53
  BugReporterVisitor(BugReporterVisitor &&) {}
54
  virtual ~BugReporterVisitor();
55
 
56
  /// Return a diagnostic piece which should be associated with the
57
  /// given node.
58
  /// Note that this function does *not* get run on the very last node
59
  /// of the report, as the PathDiagnosticPiece associated with the
60
  /// last node should be unique.
61
  /// Use \ref getEndPath to customize the note associated with the report
62
  /// end instead.
63
  ///
64
  /// The last parameter can be used to register a new visitor with the given
65
  /// BugReport while processing a node.
66
  virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
67
                                           BugReporterContext &BRC,
68
                                           PathSensitiveBugReport &BR) = 0;
69
 
70
  /// Last function called on the visitor, no further calls to VisitNode
71
  /// would follow.
72
  virtual void finalizeVisitor(BugReporterContext &BRC,
73
                               const ExplodedNode *EndPathNode,
74
                               PathSensitiveBugReport &BR);
75
 
76
  /// Provide custom definition for the final diagnostic piece on the
77
  /// path - the piece, which is displayed before the path is expanded.
78
  ///
79
  /// NOTE that this function can be implemented on at most one used visitor,
80
  /// and otherwise it crahes at runtime.
81
  virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
82
                                            const ExplodedNode *N,
83
                                            PathSensitiveBugReport &BR);
84
 
85
  virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
86
 
87
  /// Generates the default final diagnostic piece.
88
  static PathDiagnosticPieceRef
89
  getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N,
90
                    const PathSensitiveBugReport &BR);
91
};
92
 
93
namespace bugreporter {
94
 
95
/// Specifies the type of tracking for an expression.
96
enum class TrackingKind {
97
  /// Default tracking kind -- specifies that as much information should be
98
  /// gathered about the tracked expression value as possible.
99
  Thorough,
100
  /// Specifies that a more moderate tracking should be used for the expression
101
  /// value. This will essentially make sure that functions relevant to it
102
  /// aren't pruned, but otherwise relies on the user reading the code or
103
  /// following the arrows.
104
  Condition
105
};
106
 
107
/// Defines a set of options altering tracking behavior.
108
struct TrackingOptions {
109
  /// Specifies the kind of tracking.
110
  TrackingKind Kind = TrackingKind::Thorough;
111
  /// Specifies whether we should employ false positive suppression
112
  /// (inlined defensive checks, returned null).
113
  bool EnableNullFPSuppression = true;
114
};
115
 
116
/// Describes an event when the value got stored into a memory region.
117
///
118
/// As opposed to checker checkBind API, it reacts also to binds
119
/// generated by the checker as well.  It can be useful when the binding
120
/// happened as a result of evalCall, for example.
121
struct StoreInfo {
122
  enum Kind {
123
    /// The value got stored into the region during initialization:
124
    ///   int x = 42;
125
    Initialization,
126
    /// The value got stored into the region during assignment:
127
    ///   int x;
128
    ///   x = 42;
129
    Assignment,
130
    /// The value got stored into the parameter region as the result
131
    /// of a call.
132
    CallArgument,
133
    /// The value got stored into the region as block capture.
134
    /// Block data is modeled as a separate region, thus whenever
135
    /// the analyzer sees a captured variable, its value is copied
136
    /// into a special block region.
137
    BlockCapture
138
  };
139
 
140
  /// The type of store operation.
141
  Kind StoreKind;
142
  /// The node where the store happened.
143
  const ExplodedNode *StoreSite;
144
  /// The expression where the value comes from.
145
  /// NOTE: might be null.
146
  const Expr *SourceOfTheValue;
147
  /// Symbolic value that is being stored.
148
  SVal Value;
149
  /// Memory regions involved in the store operation.
150
  ///   Dest <- Origin
151
  /// NOTE: Origin might be null, when the stored value doesn't come
152
  ///       from another region.
153
  const MemRegion *Dest, *Origin;
154
};
155
 
156
class Tracker;
157
using TrackerRef = llvm::IntrusiveRefCntPtr<Tracker>;
158
 
159
class ExpressionHandler;
160
class StoreHandler;
161
 
162
/// A generalized component for tracking expressions, values, and stores.
163
///
164
/// Tracker aimes at providing a sensible set of default behaviors that can be
165
/// used by any checker, while providing mechanisms to hook into any part of the
166
/// tracking process and insert checker-specific logic.
167
class Tracker : public llvm::RefCountedBase<Tracker> {
168
private:
169
  using ExpressionHandlerPtr = std::unique_ptr<ExpressionHandler>;
170
  using StoreHandlerPtr = std::unique_ptr<StoreHandler>;
171
 
172
  PathSensitiveBugReport &Report;
173
  std::list<ExpressionHandlerPtr> ExpressionHandlers;
174
  std::list<StoreHandlerPtr> StoreHandlers;
175
 
176
protected:
177
  /// \param Report The bug report to which visitors should be attached.
178
  Tracker(PathSensitiveBugReport &Report);
179
 
180
public:
181
  virtual ~Tracker() = default;
182
 
183
  static TrackerRef create(PathSensitiveBugReport &Report) {
184
    return new Tracker(Report);
185
  }
186
 
187
  PathSensitiveBugReport &getReport() { return Report; }
188
 
189
  /// Describes a tracking result with the most basic information of what was
190
  /// actually done (or not done).
191
  struct Result {
192
    /// Usually it means that the tracker added visitors.
193
    bool FoundSomethingToTrack = false;
194
    /// Signifies that the tracking was interrupted at some point.
195
    /// Usually this information is important only for sub-trackers.
196
    bool WasInterrupted = false;
197
 
198
    /// Combines the current result with the given result.
199
    void combineWith(const Result &Other) {
200
      // If we found something in one of the cases, we can
201
      // say we found something overall.
202
      FoundSomethingToTrack |= Other.FoundSomethingToTrack;
203
      // The same goes to the interruption.
204
      WasInterrupted |= Other.WasInterrupted;
205
    }
206
  };
207
 
208
  /// Track expression value back to its point of origin.
209
  ///
210
  /// \param E The expression value which we are tracking
211
  /// \param N A node "downstream" from the evaluation of the statement.
212
  /// \param Opts Tracking options specifying how we want to track the value.
213
  virtual Result track(const Expr *E, const ExplodedNode *N,
214
                       TrackingOptions Opts = {});
215
 
216
  /// Track how the value got stored into the given region and where it came
217
  /// from.
218
  ///
219
  /// \param V We're searching for the store where \c R received this value.
220
  /// \param R The region we're tracking.
221
  /// \param Opts Tracking options specifying how we want to track the value.
222
  /// \param Origin Only adds notes when the last store happened in a
223
  ///        different stackframe to this one. Disregarded if the tracking kind
224
  ///        is thorough.
225
  ///        This is useful, because for non-tracked regions, notes about
226
  ///        changes to its value in a nested stackframe could be pruned, and
227
  ///        this visitor can prevent that without polluting the bugpath too
228
  ///        much.
229
  virtual Result track(SVal V, const MemRegion *R, TrackingOptions Opts = {},
230
                       const StackFrameContext *Origin = nullptr);
231
 
232
  /// Handle the store operation and produce the note.
233
  ///
234
  /// \param SI The information fully describing the store.
235
  /// \param Opts Tracking options specifying how we got to it.
236
  ///
237
  /// NOTE: this method is designed for sub-trackers and visitors.
238
  virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
239
                                        TrackingOptions Opts);
240
 
241
  /// Add custom expression handler with the highest priority.
242
  ///
243
  /// It means that it will be asked for handling first, and can prevent
244
  /// other handlers from running if decides to interrupt.
245
  void addHighPriorityHandler(ExpressionHandlerPtr SH) {
246
    ExpressionHandlers.push_front(std::move(SH));
247
  }
248
 
249
  /// Add custom expression handler with the lowest priority.
250
  ///
251
  /// It means that it will be asked for handling last, and other handlers can
252
  /// prevent it from running if any of them decides to interrupt.
253
  void addLowPriorityHandler(ExpressionHandlerPtr SH) {
254
    ExpressionHandlers.push_back(std::move(SH));
255
  }
256
 
257
  /// Add custom store handler with the highest priority.
258
  ///
259
  /// It means that it will be asked for handling first, and will prevent
260
  /// other handlers from running if it produces non-null note.
261
  void addHighPriorityHandler(StoreHandlerPtr SH) {
262
    StoreHandlers.push_front(std::move(SH));
263
  }
264
 
265
  /// Add custom store handler with the lowest priority.
266
  ///
267
  /// It means that it will be asked for handling last, only
268
  /// if all other handlers failed to produce the note.
269
  void addLowPriorityHandler(StoreHandlerPtr SH) {
270
    StoreHandlers.push_back(std::move(SH));
271
  }
272
 
273
  /// Add custom expression/store handler with the highest priority
274
  ///
275
  /// See other overloads for explanation.
276
  template <class HandlerType, class... Args>
277
  void addHighPriorityHandler(Args &&... ConstructorArgs) {
278
    addHighPriorityHandler(std::make_unique<HandlerType>(
279
        *this, std::forward<Args>(ConstructorArgs)...));
280
  }
281
 
282
  /// Add custom expression/store handler with the lowest priority
283
  ///
284
  /// See other overloads for explanation.
285
  template <class HandlerType, class... Args>
286
  void addLowPriorityHandler(Args &&... ConstructorArgs) {
287
    addLowPriorityHandler(std::make_unique<HandlerType>(
288
        *this, std::forward<Args>(ConstructorArgs)...));
289
  }
290
};
291
 
292
/// Handles expressions during the tracking.
293
class ExpressionHandler {
294
private:
295
  Tracker &ParentTracker;
296
 
297
public:
298
  ExpressionHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
299
  virtual ~ExpressionHandler() {}
300
 
301
  /// Handle the given expression from the given node.
302
  ///
303
  /// \param E The expression value which we are tracking
304
  /// \param Original A node "downstream" where the tracking started.
305
  /// \param ExprNode A node where the evaluation of \c E actually happens.
306
  /// \param Opts Tracking options specifying how we are tracking the value.
307
  virtual Tracker::Result handle(const Expr *E, const ExplodedNode *Original,
308
                                 const ExplodedNode *ExprNode,
309
                                 TrackingOptions Opts) = 0;
310
 
311
  /// \Return the tracker that initiated the process.
312
  Tracker &getParentTracker() { return ParentTracker; }
313
};
314
 
315
/// Handles stores during the tracking.
316
class StoreHandler {
317
private:
318
  Tracker &ParentTracker;
319
 
320
public:
321
  StoreHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
322
  virtual ~StoreHandler() {}
323
 
324
  /// Handle the given store and produce the node.
325
  ///
326
  /// \param SI The information fully describing the store.
327
  /// \param Opts Tracking options specifying how we are tracking the value.
328
  ///
329
  /// \return the produced note, null if the handler doesn't support this kind
330
  ///         of stores.
331
  virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
332
                                        TrackingOptions Opts) = 0;
333
 
334
  Tracker &getParentTracker() { return ParentTracker; }
335
 
336
protected:
337
  PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC,
338
                                       StringRef NodeText);
339
};
340
 
341
/// Visitor that tracks expressions and values.
342
class TrackingBugReporterVisitor : public BugReporterVisitor {
343
private:
344
  TrackerRef ParentTracker;
345
 
346
public:
347
  TrackingBugReporterVisitor(TrackerRef ParentTracker)
348
      : ParentTracker(ParentTracker) {}
349
 
350
  Tracker &getParentTracker() { return *ParentTracker; }
351
};
352
 
353
/// Attempts to add visitors to track expression value back to its point of
354
/// origin.
355
///
356
/// \param N A node "downstream" from the evaluation of the statement.
357
/// \param E The expression value which we are tracking
358
/// \param R The bug report to which visitors should be attached.
359
/// \param Opts Tracking options specifying how we are tracking the value.
360
///
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 trackExpressionValue(const ExplodedNode *N, const Expr *E,
365
                          PathSensitiveBugReport &R, TrackingOptions Opts = {});
366
 
367
/// Track how the value got stored into the given region and where it came
368
/// from.
369
///
370
/// \param V We're searching for the store where \c R received this value.
371
/// \param R The region we're tracking.
372
/// \param Opts Tracking options specifying how we want to track the value.
373
/// \param Origin Only adds notes when the last store happened in a
374
///        different stackframe to this one. Disregarded if the tracking kind
375
///        is thorough.
376
///        This is useful, because for non-tracked regions, notes about
377
///        changes to its value in a nested stackframe could be pruned, and
378
///        this visitor can prevent that without polluting the bugpath too
379
///        much.
380
void trackStoredValue(KnownSVal V, const MemRegion *R,
381
                      PathSensitiveBugReport &Report, TrackingOptions Opts = {},
382
                      const StackFrameContext *Origin = nullptr);
383
 
384
const Expr *getDerefExpr(const Stmt *S);
385
 
386
} // namespace bugreporter
387
 
388
class TrackConstraintBRVisitor final : public BugReporterVisitor {
389
  DefinedSVal Constraint;
390
  bool Assumption;
391
  bool IsSatisfied = false;
392
  bool IsZeroCheck;
393
 
394
  /// We should start tracking from the last node along the path in which the
395
  /// value is constrained.
396
  bool IsTrackingTurnedOn = false;
397
 
398
public:
399
  TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
400
      : Constraint(constraint), Assumption(assumption),
401
        IsZeroCheck(!Assumption && isa<Loc>(Constraint)) {}
402
 
403
  void Profile(llvm::FoldingSetNodeID &ID) const override;
404
 
405
  /// Return the tag associated with this visitor.  This tag will be used
406
  /// to make all PathDiagnosticPieces created by this visitor.
407
  static const char *getTag();
408
 
409
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
410
                                   BugReporterContext &BRC,
411
                                   PathSensitiveBugReport &BR) override;
412
 
413
private:
414
  /// Checks if the constraint is valid in the current state.
415
  bool isUnderconstrained(const ExplodedNode *N) const;
416
};
417
 
418
/// \class NilReceiverBRVisitor
419
/// Prints path notes when a message is sent to a nil receiver.
420
class NilReceiverBRVisitor final : public BugReporterVisitor {
421
public:
422
  void Profile(llvm::FoldingSetNodeID &ID) const override {
423
    static int x = 0;
424
    ID.AddPointer(&x);
425
  }
426
 
427
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
428
                                   BugReporterContext &BRC,
429
                                   PathSensitiveBugReport &BR) override;
430
 
431
  /// If the statement is a message send expression with nil receiver, returns
432
  /// the receiver expression. Returns NULL otherwise.
433
  static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
434
};
435
 
436
/// Visitor that tries to report interesting diagnostics from conditions.
437
class ConditionBRVisitor final : public BugReporterVisitor {
438
  // FIXME: constexpr initialization isn't supported by MSVC2013.
439
  constexpr static llvm::StringLiteral GenericTrueMessage =
440
      "Assuming the condition is true";
441
  constexpr static llvm::StringLiteral GenericFalseMessage =
442
      "Assuming the condition is false";
443
 
444
public:
445
  void Profile(llvm::FoldingSetNodeID &ID) const override {
446
    static int x = 0;
447
    ID.AddPointer(&x);
448
  }
449
 
450
  /// Return the tag associated with this visitor.  This tag will be used
451
  /// to make all PathDiagnosticPieces created by this visitor.
452
  static const char *getTag();
453
 
454
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
455
                                   BugReporterContext &BRC,
456
                                   PathSensitiveBugReport &BR) override;
457
 
458
  PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N,
459
                                       BugReporterContext &BRC,
460
                                       PathSensitiveBugReport &BR);
461
 
462
  PathDiagnosticPieceRef
463
  VisitTerminator(const Stmt *Term, const ExplodedNode *N,
464
                  const CFGBlock *SrcBlk, const CFGBlock *DstBlk,
465
                  PathSensitiveBugReport &R, BugReporterContext &BRC);
466
 
467
  PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
468
                                       BugReporterContext &BRC,
469
                                       PathSensitiveBugReport &R,
470
                                       const ExplodedNode *N, bool TookTrue);
471
 
472
  PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
473
                                       BugReporterContext &BRC,
474
                                       PathSensitiveBugReport &R,
475
                                       const ExplodedNode *N, bool TookTrue,
476
                                       bool IsAssuming);
477
 
478
  PathDiagnosticPieceRef
479
  VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
480
                BugReporterContext &BRC, PathSensitiveBugReport &R,
481
                const ExplodedNode *N, bool TookTrue, bool IsAssuming);
482
 
483
  PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME,
484
                                       BugReporterContext &BRC,
485
                                       PathSensitiveBugReport &R,
486
                                       const ExplodedNode *N, bool TookTrue,
487
                                       bool IsAssuming);
488
 
489
  PathDiagnosticPieceRef
490
  VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
491
                         BugReporterContext &BRC, PathSensitiveBugReport &R,
492
                         const ExplodedNode *N, bool TookTrue);
493
 
494
  /// Tries to print the value of the given expression.
495
  ///
496
  /// \param CondVarExpr The expression to print its value.
497
  /// \param Out The stream to print.
498
  /// \param N The node where we encountered the condition.
499
  /// \param TookTrue Whether we took the \c true branch of the condition.
500
  ///
501
  /// \return Whether the print was successful. (The printing is successful if
502
  ///         we model the value and we could obtain it.)
503
  bool printValue(const Expr *CondVarExpr, raw_ostream &Out,
504
                  const ExplodedNode *N, bool TookTrue, bool IsAssuming);
505
 
506
  bool patternMatch(const Expr *Ex, const Expr *ParentEx, raw_ostream &Out,
507
                    BugReporterContext &BRC, PathSensitiveBugReport &R,
508
                    const ExplodedNode *N, std::optional<bool> &prunable,
509
                    bool IsSameFieldName);
510
 
511
  static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
512
};
513
 
514
/// Suppress reports that might lead to known false positives.
515
///
516
/// Currently this suppresses reports based on locations of bugs.
517
class LikelyFalsePositiveSuppressionBRVisitor final
518
    : public BugReporterVisitor {
519
public:
520
  static void *getTag() {
521
    static int Tag = 0;
522
    return static_cast<void *>(&Tag);
523
  }
524
 
525
  void Profile(llvm::FoldingSetNodeID &ID) const override {
526
    ID.AddPointer(getTag());
527
  }
528
 
529
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &,
530
                                   PathSensitiveBugReport &) override {
531
    return nullptr;
532
  }
533
 
534
  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
535
                       PathSensitiveBugReport &BR) override;
536
};
537
 
538
/// When a region containing undefined value or '0' value is passed
539
/// as an argument in a call, marks the call as interesting.
540
///
541
/// As a result, BugReporter will not prune the path through the function even
542
/// if the region's contents are not modified/accessed by the call.
543
class UndefOrNullArgVisitor final : public BugReporterVisitor {
544
  /// The interesting memory region this visitor is tracking.
545
  const MemRegion *R;
546
 
547
public:
548
  UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
549
 
550
  void Profile(llvm::FoldingSetNodeID &ID) const override {
551
    static int Tag = 0;
552
    ID.AddPointer(&Tag);
553
    ID.AddPointer(R);
554
  }
555
 
556
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
557
                                   BugReporterContext &BRC,
558
                                   PathSensitiveBugReport &BR) override;
559
};
560
 
561
class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
562
  /// The symbolic value for which we are tracking constraints.
563
  /// This value is constrained to null in the end of path.
564
  DefinedSVal V;
565
 
566
  /// Track if we found the node where the constraint was first added.
567
  bool IsSatisfied = false;
568
 
569
  /// Since the visitors can be registered on nodes previous to the last
570
  /// node in the BugReport, but the path traversal always starts with the last
571
  /// node, the visitor invariant (that we start with a node in which V is null)
572
  /// might not hold when node visitation starts. We are going to start tracking
573
  /// from the last node in which the value is null.
574
  bool IsTrackingTurnedOn = false;
575
 
576
public:
577
  SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
578
 
579
  void Profile(llvm::FoldingSetNodeID &ID) const override;
580
 
581
  /// Return the tag associated with this visitor.  This tag will be used
582
  /// to make all PathDiagnosticPieces created by this visitor.
583
  static const char *getTag();
584
 
585
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
586
                                   BugReporterContext &BRC,
587
                                   PathSensitiveBugReport &BR) override;
588
};
589
 
590
/// The bug visitor will walk all the nodes in a path and collect all the
591
/// constraints. When it reaches the root node, will create a refutation
592
/// manager and check if the constraints are satisfiable
593
class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor {
594
private:
595
  /// Holds the constraints in a given path
596
  ConstraintMap Constraints;
597
 
598
public:
599
  FalsePositiveRefutationBRVisitor();
600
 
601
  void Profile(llvm::FoldingSetNodeID &ID) const override;
602
 
603
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
604
                                   BugReporterContext &BRC,
605
                                   PathSensitiveBugReport &BR) override;
606
 
607
  void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
608
                       PathSensitiveBugReport &BR) override;
609
  void addConstraints(const ExplodedNode *N,
610
                      bool OverwriteConstraintsOnExistingSyms);
611
};
612
 
613
/// The visitor detects NoteTags and displays the event notes they contain.
614
class TagVisitor : public BugReporterVisitor {
615
public:
616
  void Profile(llvm::FoldingSetNodeID &ID) const override;
617
 
618
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
619
                                   BugReporterContext &BRC,
620
                                   PathSensitiveBugReport &R) override;
621
};
622
 
623
class ObjCMethodCall;
624
class CXXConstructorCall;
625
 
626
/// Put a diagnostic on return statement (or on } in its absence) of all inlined
627
/// functions for which some property remained unchanged.
628
/// Resulting diagnostics may read such as "Returning without writing to X".
629
///
630
/// Descendants can define what a "state change is", like a change of value
631
/// to a memory region, liveness, etc. For function calls where the state did
632
/// not change as defined, a custom note may be constructed.
633
///
634
/// For a minimal example, check out
635
/// clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp.
636
class NoStateChangeFuncVisitor : public BugReporterVisitor {
637
private:
638
  /// Frames modifying the state as defined in \c wasModifiedBeforeCallExit.
639
  /// This visitor generates a note only if a function does *not* change the
640
  /// state that way. This information is not immediately available
641
  /// by looking at the node associated with the exit from the function
642
  /// (usually the return statement). To avoid recomputing the same information
643
  /// many times (going up the path for each node and checking whether the
644
  /// region was written into) we instead lazily compute the stack frames
645
  /// along the path.
646
  // TODO: Can't we just use a map instead? This is likely not as cheap as it
647
  // makes the code difficult to read.
648
  llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifying;
649
  llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifyingCalculated;
650
 
651
  /// Check and lazily calculate whether the state is modified in the stack
652
  /// frame to which \p CallExitBeginN belongs.
653
  /// The calculation is cached in FramesModifying.
654
  bool isModifiedInFrame(const ExplodedNode *CallExitBeginN);
655
 
656
  void markFrameAsModifying(const StackFrameContext *SCtx);
657
 
658
  /// Write to \c FramesModifying all stack frames along the path in the current
659
  /// stack frame which modifies the state.
660
  void findModifyingFrames(const ExplodedNode *const CallExitBeginN);
661
 
662
protected:
663
  bugreporter::TrackingKind TKind;
664
 
665
  /// \return Whether the state was modified from the current node, \p CurrN, to
666
  /// the end of the stack frame, at \p CallExitBeginN. \p CurrN and
667
  /// \p CallExitBeginN are always in the same stack frame.
668
  /// Clients should override this callback when a state change is important
669
  /// not only on the entire function call, but inside of it as well.
670
  /// Example: we may want to leave a note about the lack of locking/unlocking
671
  /// on a particular mutex, but not if inside the function its state was
672
  /// changed, but also restored. wasModifiedInFunction() wouldn't know of this
673
  /// change.
674
  virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
675
                                         const ExplodedNode *CallExitBeginN) {
676
    return false;
677
  }
678
 
679
  /// \return Whether the state was modified in the inlined function call in
680
  /// between \p CallEnterN and \p CallExitEndN. Mind that the stack frame
681
  /// retrieved from a CallEnterN and CallExitEndN is the *caller's* stack
682
  /// frame! The inlined function's stack should be retrieved from either the
683
  /// immediate successor to \p CallEnterN or immediate predecessor to
684
  /// \p CallExitEndN.
685
  /// Clients should override this function if a state changes local to the
686
  /// inlined function are not interesting, only the change occuring as a
687
  /// result of it.
688
  /// Example: we want to leave a not about a leaked resource object not being
689
  /// deallocated / its ownership changed inside a function, and we don't care
690
  /// if it was assigned to a local variable (its change in ownership is
691
  /// inconsequential).
692
  virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
693
                                     const ExplodedNode *CallExitEndN) {
694
    return false;
695
  }
696
 
697
  /// Consume the information on the non-modifying stack frame in order to
698
  /// either emit a note or not. May suppress the report entirely.
699
  /// \return Diagnostics piece for the unmodified state in the current
700
  /// function, if it decides to emit one. A good description might start with
701
  /// "Returning without...".
702
  virtual PathDiagnosticPieceRef
703
  maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
704
                           const ObjCMethodCall &Call,
705
                           const ExplodedNode *N) = 0;
706
 
707
  /// Consume the information on the non-modifying stack frame in order to
708
  /// either emit a note or not. May suppress the report entirely.
709
  /// \return Diagnostics piece for the unmodified state in the current
710
  /// function, if it decides to emit one. A good description might start with
711
  /// "Returning without...".
712
  virtual PathDiagnosticPieceRef
713
  maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
714
                          const CXXConstructorCall &Call,
715
                          const ExplodedNode *N) = 0;
716
 
717
  /// Consume the information on the non-modifying stack frame in order to
718
  /// either emit a note or not. May suppress the report entirely.
719
  /// \return Diagnostics piece for the unmodified state in the current
720
  /// function, if it decides to emit one. A good description might start with
721
  /// "Returning without...".
722
  virtual PathDiagnosticPieceRef
723
  maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
724
                             const ExplodedNode *N) = 0;
725
 
726
public:
727
  NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind) : TKind(TKind) {}
728
 
729
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
730
                                   BugReporterContext &BR,
731
                                   PathSensitiveBugReport &R) final;
732
};
733
 
734
} // namespace ento
735
} // namespace clang
736
 
737
#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H