clang 24.0.0git
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/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
31namespace clang {
32
33class BinaryOperator;
34class CFGBlock;
35class DeclRefExpr;
36class Expr;
37class Stmt;
38
39namespace ento {
40
43class CallEvent;
44class ExplodedNode;
45class MemRegion;
47using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
48
49/// BugReporterVisitors are used to add custom diagnostics along a path.
50class BugReporterVisitor : public llvm::FoldingSetNode {
51public:
52 BugReporterVisitor() = default;
55
56 // The copy and move assignment operator is defined as deleted pending further
57 // motivation.
60
62
63 /// Return a diagnostic piece which should be associated with the
64 /// given node.
65 /// Note that this function does *not* get run on the very last node
66 /// of the report, as the PathDiagnosticPiece associated with the
67 /// last node should be unique.
68 /// Use \ref getEndPath to customize the note associated with the report
69 /// end instead.
70 ///
71 /// The last parameter can be used to register a new visitor with the given
72 /// BugReport while processing a node.
76
77 /// Last function called on the visitor, no further calls to VisitNode
78 /// would follow.
79 virtual void finalizeVisitor(const ExplodedNode *EndPathNode,
82
83 /// Provide custom definition for the final diagnostic piece on the
84 /// path - the piece, which is displayed before the path is expanded.
85 ///
86 /// NOTE that this function can be implemented on at most one used visitor,
87 /// and otherwise it crahes at runtime.
91
92 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
93
94 /// Generates the default final diagnostic piece.
97 const PathSensitiveBugReport &BR);
98};
99
100namespace bugreporter {
101
102/// Specifies the type of tracking for an expression.
103enum class TrackingKind {
104 /// Default tracking kind -- specifies that as much information should be
105 /// gathered about the tracked expression value as possible.
107 /// Specifies that a more moderate tracking should be used for the expression
108 /// value. This will essentially make sure that functions relevant to it
109 /// aren't pruned, but otherwise relies on the user reading the code or
110 /// following the arrows.
112};
113
114/// Defines a set of options altering tracking behavior.
116 /// Specifies the kind of tracking.
118 /// Specifies whether we should employ false positive suppression
119 /// (inlined defensive checks, returned null).
121};
122
123/// Describes an event when the value got stored into a memory region.
124///
125/// As opposed to checker checkBind API, it reacts also to binds
126/// generated by the checker as well. It can be useful when the binding
127/// happened as a result of evalCall, for example.
128struct StoreInfo {
129 enum Kind {
130 /// The value got stored into the region during initialization:
131 /// int x = 42;
133 /// The value got stored into the region during assignment:
134 /// int x;
135 /// x = 42;
137 /// The value got stored into the parameter region as the result
138 /// of a call.
140 /// The value got stored into the region as block capture.
141 /// Block data is modeled as a separate region, thus whenever
142 /// the analyzer sees a captured variable, its value is copied
143 /// into a special block region.
145 };
146
147 /// The type of store operation.
149 /// The node where the store happened.
151 /// The expression where the value comes from.
152 /// NOTE: might be null.
154 /// Symbolic value that is being stored.
156 /// Memory regions involved in the store operation.
157 /// Dest <- Origin
158 /// NOTE: Origin might be null, when the stored value doesn't come
159 /// from another region.
161};
162
163class Tracker;
165
167class StoreHandler;
168
169/// A generalized component for tracking expressions, values, and stores.
170///
171/// Tracker aimes at providing a sensible set of default behaviors that can be
172/// used by any checker, while providing mechanisms to hook into any part of the
173/// tracking process and insert checker-specific logic.
174class Tracker : public llvm::RefCountedBase<Tracker> {
175private:
176 using ExpressionHandlerPtr = std::unique_ptr<ExpressionHandler>;
177 using StoreHandlerPtr = std::unique_ptr<StoreHandler>;
178
180 std::list<ExpressionHandlerPtr> ExpressionHandlers;
181 std::list<StoreHandlerPtr> StoreHandlers;
182
183protected:
184 /// \param Report The bug report to which visitors should be attached.
186
187public:
188 virtual ~Tracker() = default;
189
191 return new Tracker(Report);
192 }
193
194 PathSensitiveBugReport &getReport() { return Report; }
195
196 /// Describes a tracking result with the most basic information of what was
197 /// actually done (or not done).
198 struct Result {
199 /// Usually it means that the tracker added visitors.
201 /// Signifies that the tracking was interrupted at some point.
202 /// Usually this information is important only for sub-trackers.
203 bool WasInterrupted = false;
204
205 /// Combines the current result with the given result.
206 void combineWith(const Result &Other) {
207 // If we found something in one of the cases, we can
208 // say we found something overall.
209 FoundSomethingToTrack |= Other.FoundSomethingToTrack;
210 // The same goes to the interruption.
211 WasInterrupted |= Other.WasInterrupted;
212 }
213 };
214
215 /// Track expression value back to its point of origin.
216 ///
217 /// \param E The expression value which we are tracking
218 /// \param N A node "downstream" from the evaluation of the statement.
219 /// \param Opts Tracking options specifying how we want to track the value.
220 virtual Result track(const Expr *E, const ExplodedNode *N,
221 TrackingOptions Opts = {});
222
223 /// Track how the value got stored into the given region and where it came
224 /// from.
225 ///
226 /// \param V We're searching for the store where \c R received this value.
227 /// \param R The region we're tracking.
228 /// \param Opts Tracking options specifying how we want to track the value.
229 /// \param Origin Only adds notes when the last store happened in a
230 /// different stackframe to this one. Disregarded if the tracking kind
231 /// is thorough.
232 /// This is useful, because for non-tracked regions, notes about
233 /// changes to its value in a nested stackframe could be pruned, and
234 /// this visitor can prevent that without polluting the bugpath too
235 /// much.
236 virtual Result track(SVal V, const MemRegion *R, TrackingOptions Opts = {},
237 const StackFrame *Origin = nullptr);
238
239 /// Handle the store operation and produce the note.
240 ///
241 /// \param SI The information fully describing the store.
242 /// \param Opts Tracking options specifying how we got to it.
243 ///
244 /// NOTE: this method is designed for sub-trackers and visitors.
245 virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
246 TrackingOptions Opts);
247
248 /// Add custom expression handler with the highest priority.
249 ///
250 /// It means that it will be asked for handling first, and can prevent
251 /// other handlers from running if decides to interrupt.
252 void addHighPriorityHandler(ExpressionHandlerPtr SH) {
253 ExpressionHandlers.push_front(std::move(SH));
254 }
255
256 /// Add custom expression handler with the lowest priority.
257 ///
258 /// It means that it will be asked for handling last, and other handlers can
259 /// prevent it from running if any of them decides to interrupt.
260 void addLowPriorityHandler(ExpressionHandlerPtr SH) {
261 ExpressionHandlers.push_back(std::move(SH));
262 }
263
264 /// Add custom store handler with the highest priority.
265 ///
266 /// It means that it will be asked for handling first, and will prevent
267 /// other handlers from running if it produces non-null note.
268 void addHighPriorityHandler(StoreHandlerPtr SH) {
269 StoreHandlers.push_front(std::move(SH));
270 }
271
272 /// Add custom store handler with the lowest priority.
273 ///
274 /// It means that it will be asked for handling last, only
275 /// if all other handlers failed to produce the note.
276 void addLowPriorityHandler(StoreHandlerPtr SH) {
277 StoreHandlers.push_back(std::move(SH));
278 }
279
280 /// Add custom expression/store handler with the highest priority
281 ///
282 /// See other overloads for explanation.
283 template <class HandlerType, class... Args>
284 void addHighPriorityHandler(Args &&... ConstructorArgs) {
285 addHighPriorityHandler(std::make_unique<HandlerType>(
286 *this, std::forward<Args>(ConstructorArgs)...));
287 }
288
289 /// Add custom expression/store handler with the lowest priority
290 ///
291 /// See other overloads for explanation.
292 template <class HandlerType, class... Args>
293 void addLowPriorityHandler(Args &&... ConstructorArgs) {
294 addLowPriorityHandler(std::make_unique<HandlerType>(
295 *this, std::forward<Args>(ConstructorArgs)...));
296 }
297};
298
299/// Handles expressions during the tracking.
301private:
302 Tracker &ParentTracker;
303
304public:
305 ExpressionHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
307
308 /// Handle the given expression from the given node.
309 ///
310 /// \param E The expression value which we are tracking
311 /// \param Original A node "downstream" where the tracking started.
312 /// \param ExprNode A node where the evaluation of \c E actually happens.
313 /// \param Opts Tracking options specifying how we are tracking the value.
314 virtual Tracker::Result handle(const Expr *E, const ExplodedNode *Original,
315 const ExplodedNode *ExprNode,
316 TrackingOptions Opts) = 0;
317
318 /// \Return the tracker that initiated the process.
319 Tracker &getParentTracker() { return ParentTracker; }
320};
321
322/// Handles stores during the tracking.
324private:
325 Tracker &ParentTracker;
326
327public:
328 StoreHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
329 virtual ~StoreHandler() {}
330
331 /// Handle the given store and produce the node.
332 ///
333 /// \param SI The information fully describing the store.
334 /// \param Opts Tracking options specifying how we are tracking the value.
335 ///
336 /// \return the produced note, null if the handler doesn't support this kind
337 /// of stores.
339 TrackingOptions Opts) = 0;
340
341 Tracker &getParentTracker() { return ParentTracker; }
342
343protected:
345 StringRef NodeText);
346};
347
348/// Visitor that tracks expressions and values.
350private:
351 TrackerRef ParentTracker;
352
353public:
355 : ParentTracker(ParentTracker) {}
356
357 Tracker &getParentTracker() { return *ParentTracker; }
358};
359
360/// Attempts to add visitors to track expression value back to its point of
361/// origin.
362///
363/// \param N A node "downstream" from the evaluation of the statement.
364/// \param E The expression value which we are tracking
365/// \param R The bug report to which visitors should be attached.
366/// \param Opts Tracking options specifying how we are tracking the value.
367///
368/// \return Whether or not the function was able to add visitors for this
369/// statement. Note that returning \c true does not actually imply
370/// that any visitors were added.
371bool trackExpressionValue(const ExplodedNode *N, const Expr *E,
372 PathSensitiveBugReport &R, TrackingOptions Opts = {});
373
374/// Track how the value got stored into the given region and where it came
375/// from.
376///
377/// \param V We're searching for the store where \c R received this value.
378/// It may be either defined or undefined, but should not be unknown.
379/// \param R The region we're tracking.
380/// \param Opts Tracking options specifying how we want to track the value.
381/// \param Origin Only adds notes when the last store happened in a
382/// different stackframe to this one. Disregarded if the tracking kind
383/// is thorough.
384/// This is useful, because for non-tracked regions, notes about
385/// changes to its value in a nested stackframe could be pruned, and
386/// this visitor can prevent that without polluting the bugpath too
387/// much.
388void trackStoredValue(SVal V, const MemRegion *R,
389 PathSensitiveBugReport &Report, TrackingOptions Opts = {},
390 const StackFrame *Origin = nullptr);
391
392const Expr *getDerefExpr(const Stmt *S);
393
394} // namespace bugreporter
395
397 const SmallString<64> Message;
398 const DefinedSVal Constraint;
399 const bool Assumption;
400 bool IsSatisfied = false;
401
402 /// We should start tracking from the last node along the path in which the
403 /// value is constrained.
404 bool IsTrackingTurnedOn = false;
405
406public:
407 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption,
408 StringRef Message)
409 : Message(Message), Constraint(constraint), Assumption(assumption) {}
410
411 void Profile(llvm::FoldingSetNodeID &ID) const override;
412
413 /// Return the tag associated with this visitor. This tag will be used
414 /// to make all PathDiagnosticPieces created by this visitor.
415 static const char *getTag();
416
419 PathSensitiveBugReport &BR) override;
420
421private:
422 /// Checks if the constraint refers to a null-location.
423 bool isZeroCheck() const;
424
425 /// Checks if the constraint is valid in the current state.
426 bool isUnderconstrained(const ExplodedNode *N) const;
427};
428
429/// \class NilReceiverBRVisitor
430/// Prints path notes when a message is sent to a nil receiver.
432public:
433 void Profile(llvm::FoldingSetNodeID &ID) const override {
434 static int x = 0;
435 ID.AddPointer(&x);
436 }
437
440 PathSensitiveBugReport &BR) override;
441
442 /// If the statement is a message send expression with nil receiver, returns
443 /// the receiver expression. Returns NULL otherwise.
444 static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
445};
446
447/// Visitor that tries to report interesting diagnostics from conditions.
449 // FIXME: constexpr initialization isn't supported by MSVC2013.
450 constexpr static llvm::StringLiteral GenericTrueMessage =
451 "Assuming the condition is true";
452 constexpr static llvm::StringLiteral GenericFalseMessage =
453 "Assuming the condition is false";
454
455public:
456 void Profile(llvm::FoldingSetNodeID &ID) const override {
457 static int x = 0;
458 ID.AddPointer(&x);
459 }
460
461 /// Return the tag associated with this visitor. This tag will be used
462 /// to make all PathDiagnosticPieces created by this visitor.
463 static const char *getTag();
464
467 PathSensitiveBugReport &BR) override;
468
472
474 VisitTerminator(const Stmt *Term, const ExplodedNode *N,
475 const CFGBlock *SrcBlk, const CFGBlock *DstBlk,
477
481 const ExplodedNode *N, bool TookTrue);
482
486 const ExplodedNode *N, bool TookTrue,
487 bool IsAssuming);
488
490 VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
492 const ExplodedNode *N, bool TookTrue, bool IsAssuming);
493
497 const ExplodedNode *N, bool TookTrue,
498 bool IsAssuming);
499
501 VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
503 const ExplodedNode *N, bool TookTrue);
504
505 /// Tries to print the value of the given expression.
506 ///
507 /// \param CondVarExpr The expression to print its value.
508 /// \param Out The stream to print.
509 /// \param N The node where we encountered the condition.
510 /// \param TookTrue Whether we took the \c true branch of the condition.
511 ///
512 /// \return Whether the print was successful. (The printing is successful if
513 /// we model the value and we could obtain it.)
514 bool printValue(const Expr *CondVarExpr, raw_ostream &Out,
515 const ExplodedNode *N, bool TookTrue, bool IsAssuming);
516
517 bool patternMatch(const Expr *Ex, const Expr *ParentEx, const Expr *OtherEx,
518 raw_ostream &Out, BugReporterContext &BRC,
520 std::optional<bool> &prunable, bool IsSameFieldName);
521
522 static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
523};
524
525/// Suppress reports that might lead to known false positives.
526///
527/// Currently this suppresses reports based on locations of bugs.
529 : public BugReporterVisitor {
530public:
531 static void *getTag() {
532 static int Tag = 0;
533 return static_cast<void *>(&Tag);
534 }
535
536 void Profile(llvm::FoldingSetNodeID &ID) const override {
537 ID.AddPointer(getTag());
538 }
539
541 PathSensitiveBugReport &) override {
542 return nullptr;
543 }
544
546 PathSensitiveBugReport &BR) override;
547};
548
549/// When a region containing undefined value or '0' value is passed
550/// as an argument in a call, marks the call as interesting.
551///
552/// As a result, BugReporter will not prune the path through the function even
553/// if the region's contents are not modified/accessed by the call.
555 /// The interesting memory region this visitor is tracking.
556 const MemRegion *R;
557
558public:
559 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
560
561 void Profile(llvm::FoldingSetNodeID &ID) const override {
562 static int Tag = 0;
563 ID.AddPointer(&Tag);
564 ID.AddPointer(R);
565 }
566
569 PathSensitiveBugReport &BR) override;
570};
571
573 /// The symbolic value for which we are tracking constraints.
574 /// This value is constrained to null in the end of path.
575 DefinedSVal V;
576
577 /// Track if we found the node where the constraint was first added.
578 bool IsSatisfied = false;
579
580 /// Since the visitors can be registered on nodes previous to the last
581 /// node in the BugReport, but the path traversal always starts with the last
582 /// node, the visitor invariant (that we start with a node in which V is null)
583 /// might not hold when node visitation starts. We are going to start tracking
584 /// from the last node in which the value is null.
585 bool IsTrackingTurnedOn = false;
586
587public:
589
590 void Profile(llvm::FoldingSetNodeID &ID) const override;
591
592 /// Return the tag associated with this visitor. This tag will be used
593 /// to make all PathDiagnosticPieces created by this visitor.
594 static const char *getTag();
595
598 PathSensitiveBugReport &BR) override;
599};
600
601/// The visitor detects NoteTags and displays the event notes they contain.
603public:
604 void Profile(llvm::FoldingSetNodeID &ID) const override;
605
608 PathSensitiveBugReport &R) override;
609};
610
611class ObjCMethodCall;
613
614/// Put a diagnostic on return statement (or on } in its absence) of all inlined
615/// functions for which some property remained unchanged.
616/// Resulting diagnostics may read such as "Returning without writing to X".
617///
618/// Descendants can define what a "state change is", like a change of value
619/// to a memory region, liveness, etc. For function calls where the state did
620/// not change as defined, a custom note may be constructed.
621///
622/// For a minimal example, check out
623/// clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp.
625private:
626 /// Frames modifying the state as defined in \c wasModifiedBeforeCallExit.
627 /// This visitor generates a note only if a function does *not* change the
628 /// state that way. This information is not immediately available
629 /// by looking at the node associated with the exit from the function
630 /// (usually the return statement). To avoid recomputing the same information
631 /// many times (going up the path for each node and checking whether the
632 /// region was written into) we instead lazily compute the stack frames
633 /// along the path.
634 // TODO: Can't we just use a map instead? This is likely not as cheap as it
635 // makes the code difficult to read.
637 llvm::SmallPtrSet<const StackFrame *, 32> FramesModifyingCalculated;
638
639 /// Check and lazily calculate whether the state is modified in the stack
640 /// frame to which \p CallExitBeginN belongs.
641 /// The calculation is cached in FramesModifying.
642 bool isModifiedInFrame(const ExplodedNode *CallExitBeginN);
643
644 void markFrameAsModifying(const StackFrame *SF);
645
646 /// Write to \c FramesModifying all stack frames along the path in the current
647 /// stack frame which modifies the state.
648 void findModifyingFrames(const ExplodedNode *const CallExitBeginN);
649
650protected:
652
653 /// \return Whether the state was modified from the current node, \p CurrN, to
654 /// the end of the stack frame, at \p CallExitBeginN. \p CurrN and
655 /// \p CallExitBeginN are always in the same stack frame.
656 /// Clients should override this callback when a state change is important
657 /// not only on the entire function call, but inside of it as well.
658 /// Example: we may want to leave a note about the lack of locking/unlocking
659 /// on a particular mutex, but not if inside the function its state was
660 /// changed, but also restored. wasModifiedInFunction() wouldn't know of this
661 /// change.
662 virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
663 const ExplodedNode *CallExitBeginN) {
664 return false;
665 }
666
667 /// \return Whether the state was modified in the inlined function call in
668 /// between \p CallEnterN and \p CallExitEndN. Mind that the stack frame
669 /// retrieved from a CallEnterN and CallExitEndN is the *caller's* stack
670 /// frame! The inlined function's stack should be retrieved from either the
671 /// immediate successor to \p CallEnterN or immediate predecessor to
672 /// \p CallExitEndN.
673 /// Clients should override this function if a state changes local to the
674 /// inlined function are not interesting, only the change occuring as a
675 /// result of it.
676 /// Example: we want to leave a not about a leaked resource object not being
677 /// deallocated / its ownership changed inside a function, and we don't care
678 /// if it was assigned to a local variable (its change in ownership is
679 /// inconsequential).
680 virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
681 const ExplodedNode *CallExitEndN) {
682 return false;
683 }
684
685 /// Consume the information on the non-modifying stack frame in order to
686 /// either emit a note or not. May suppress the report entirely.
687 /// \return Diagnostics piece for the unmodified state in the current
688 /// function, if it decides to emit one. A good description might start with
689 /// "Returning without...".
692 const ObjCMethodCall &Call,
693 const ExplodedNode *N) = 0;
694
695 /// Consume the information on the non-modifying stack frame in order to
696 /// either emit a note or not. May suppress the report entirely.
697 /// \return Diagnostics piece for the unmodified state in the current
698 /// function, if it decides to emit one. A good description might start with
699 /// "Returning without...".
703 const ExplodedNode *N) = 0;
704
705 /// Consume the information on the non-modifying stack frame in order to
706 /// either emit a note or not. May suppress the report entirely.
707 /// \return Diagnostics piece for the unmodified state in the current
708 /// function, if it decides to emit one. A good description might start with
709 /// "Returning without...".
712 const ExplodedNode *N) = 0;
713
714public:
716
719 PathSensitiveBugReport &R) final;
720};
721
722/// Put a diagnostic on return statement of all inlined functions
723/// for which the region of interest \p RegionOfInterest was passed into,
724/// but not written inside, and it has caused an undefined read or a null
725/// pointer dereference outside.
727 const SubRegion *RegionOfInterest;
728 MemRegionManager &MmrMgr;
729 const SourceManager &SM;
730 const PrintingPolicy &PP;
731
732 /// Recursion limit for dereferencing fields when looking for the
733 /// region of interest.
734 /// The limit of two indicates that we will dereference fields only once.
735 static const unsigned DEREFERENCE_LIMIT = 2;
736
737 using RegionVector = SmallVector<const MemRegion *, 5>;
738
739public:
741 const SubRegion *R,
743 : NoStateChangeFuncVisitor(TKind), RegionOfInterest(R),
744 MmrMgr(R->getMemRegionManager()),
745 SM(MmrMgr.getContext().getSourceManager()),
746 PP(MmrMgr.getContext().getPrintingPolicy()) {}
747
748 void Profile(llvm::FoldingSetNodeID &ID) const override {
749 static int Tag = 0;
750 ID.AddPointer(&Tag);
751 ID.AddPointer(RegionOfInterest);
752 }
753
754private:
755 /// \return Whether \c RegionOfInterest was modified at \p CurrN compared to
756 /// the value it holds in \p CallExitBeginN.
757 bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
758 const ExplodedNode *CallExitBeginN) override;
759
760 /// Attempts to find the region of interest in a given record decl,
761 /// by either following the base classes or fields.
762 /// Dereferences fields up to a given recursion limit.
763 /// Note that \p Vec is passed by value, leading to quadratic copying cost,
764 /// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
765 /// \return A chain fields leading to the region of interest or std::nullopt.
766 const std::optional<RegionVector>
767 findRegionOfInterestInRecord(const RecordDecl *RD, ProgramStateRef State,
768 const MemRegion *R, const RegionVector &Vec = {},
769 int depth = 0);
770
771 // Region of interest corresponds to an IVar, exiting a method
772 // which could have written into that IVar, but did not.
773 PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
774 const ObjCMethodCall &Call,
775 const ExplodedNode *N) final;
776
777 PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
778 const CXXConstructorCall &Call,
779 const ExplodedNode *N) final;
780
782 maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
783 const ExplodedNode *N) final;
784
785 /// Consume the information on the no-store stack frame in order to
786 /// either emit a note or suppress the report entirely.
787 /// \return Diagnostics piece for region not modified in the current function,
788 /// if it decides to emit one.
790 maybeEmitNote(PathSensitiveBugReport &R, const CallEvent &Call,
791 const ExplodedNode *N, const RegionVector &FieldChain,
792 const MemRegion *MatchedRegion, StringRef FirstElement,
793 bool FirstIsReferenceType, unsigned IndirectionLevel);
794
795 bool prettyPrintRegionName(const RegionVector &FieldChain,
796 const MemRegion *MatchedRegion,
797 StringRef FirstElement, bool FirstIsReferenceType,
798 unsigned IndirectionLevel,
799 llvm::raw_svector_ostream &os);
800
801 StringRef prettyPrintFirstElement(StringRef FirstElement,
802 bool MoreItemsExpected,
803 int IndirectionLevel,
804 llvm::raw_svector_ostream &os);
805};
806
807} // namespace ento
808} // namespace clang
809
810#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
#define V(N, I)
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:4107
Represents a single basic block in a source-level CFG.
Definition CFG.h:651
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1315
This represents one expression.
Definition Expr.h:114
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3433
Represents a struct/union/class.
Definition Decl.h:4506
This class handles loading and caching of source files into memory.
It represents a stack frame of the call stack.
Stmt - This represents one statement.
Definition Stmt.h:85
virtual void Profile(llvm::FoldingSetNodeID &ID) const =0
BugReporterVisitor(BugReporterVisitor &&)
virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR)=0
Return a diagnostic piece which should be associated with the given node.
virtual PathDiagnosticPieceRef getEndPath(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR)
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
BugReporterVisitor & operator=(BugReporterVisitor &&)=delete
BugReporterVisitor(const BugReporterVisitor &)=default
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)
Generates the default final diagnostic piece.
BugReporterVisitor & operator=(const BugReporterVisitor &)=delete
virtual void finalizeVisitor(const ExplodedNode *EndPathNode, BugReporterContext &BRC, PathSensitiveBugReport &BR)
Last function called on the visitor, no further calls to VisitNode would follow.
Represents a call to a C++ constructor.
Definition CallEvent.h:988
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:152
Visitor that tries to report interesting diagnostics from conditions.
PathDiagnosticPieceRef VisitTerminator(const Stmt *Term, const ExplodedNode *N, const CFGBlock *SrcBlk, const CFGBlock *DstBlk, PathSensitiveBugReport &R, BugReporterContext &BRC)
bool printValue(const Expr *CondVarExpr, raw_ostream &Out, const ExplodedNode *N, bool TookTrue, bool IsAssuming)
Tries to print the value of the given expression.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
PathDiagnosticPieceRef VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)
bool patternMatch(const Expr *Ex, const Expr *ParentEx, const Expr *OtherEx, raw_ostream &Out, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, std::optional< bool > &prunable, bool IsSameFieldName)
PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, BugReporterContext &BRC, PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue)
static const char * getTag()
Return the tag associated with this visitor.
PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR)
void Profile(llvm::FoldingSetNodeID &ID) const override
Suppress reports that might lead to known false positives.
void Profile(llvm::FoldingSetNodeID &ID) const override
void finalizeVisitor(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Last function called on the visitor, no further calls to VisitNode would follow.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &, PathSensitiveBugReport &) override
Return a diagnostic piece which should be associated with the given node.
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:97
Prints path notes when a message is sent to a nil receiver.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
void Profile(llvm::FoldingSetNodeID &ID) const override
static const Expr * getNilReceiver(const Stmt *S, const ExplodedNode *N)
If the statement is a message send expression with nil receiver, returns the receiver expression.
virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN, const ExplodedNode *CallExitBeginN)
virtual PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R, const ObjCMethodCall &Call, const ExplodedNode *N)=0
Consume the information on the non-modifying stack frame in order to either emit a note or not.
virtual PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R, const CXXConstructorCall &Call, const ExplodedNode *N)=0
Consume the information on the non-modifying stack frame in order to either emit a note or not.
NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind)
virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN, const ExplodedNode *CallExitEndN)
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) final
Return a diagnostic piece which should be associated with the given node.
virtual PathDiagnosticPieceRef maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N)=0
Consume the information on the non-modifying stack frame in order to either emit a note or not.
void Profile(llvm::FoldingSetNodeID &ID) const override
NoStoreFuncVisitor(const SubRegion *R, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Represents any expression that calls an Objective-C method.
Definition CallEvent.h:1249
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:57
SubRegion - A region that subsets another larger region.
Definition MemRegion.h:480
PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N)
static const char * getTag()
Return the tag associated with this visitor.
void Profile(llvm::FoldingSetNodeID &ID) const override
The visitor detects NoteTags and displays the event notes they contain.
void Profile(llvm::FoldingSetNodeID &ID) const override
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &R) override
Return a diagnostic piece which should be associated with the given node.
void Profile(llvm::FoldingSetNodeID &ID) const override
static const char * getTag()
Return the tag associated with this visitor.
TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption, StringRef Message)
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
void Profile(llvm::FoldingSetNodeID &ID) const override
Handles expressions during the tracking.
virtual Tracker::Result handle(const Expr *E, const ExplodedNode *Original, const ExplodedNode *ExprNode, TrackingOptions Opts)=0
Handle the given expression from the given node.
Tracker & getParentTracker()
\Return the tracker that initiated the process.
Handles stores during the tracking.
virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, TrackingOptions Opts)=0
Handle the given store and produce the node.
PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC, StringRef NodeText)
A generalized component for tracking expressions, values, and stores.
void addLowPriorityHandler(ExpressionHandlerPtr SH)
Add custom expression handler with the lowest priority.
static TrackerRef create(PathSensitiveBugReport &Report)
PathSensitiveBugReport & getReport()
void addHighPriorityHandler(Args &&... ConstructorArgs)
Add custom expression/store handler with the highest priority.
virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, TrackingOptions Opts)
Handle the store operation and produce the note.
void addHighPriorityHandler(StoreHandlerPtr SH)
Add custom store handler with the highest priority.
void addHighPriorityHandler(ExpressionHandlerPtr SH)
Add custom expression handler with the highest priority.
void addLowPriorityHandler(Args &&... ConstructorArgs)
Add custom expression/store handler with the lowest priority.
void addLowPriorityHandler(StoreHandlerPtr SH)
Add custom store handler with the lowest priority.
Tracker(PathSensitiveBugReport &Report)
virtual Result track(const Expr *E, const ExplodedNode *N, TrackingOptions Opts={})
Track expression value back to its point of origin.
llvm::IntrusiveRefCntPtr< Tracker > TrackerRef
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrame *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
@ Condition
Specifies that a more moderate tracking should be used for the expression value.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
Top level wrappers for InstallAPI frontend operations.
@ Result
The result type of a method or function.
Definition TypeBase.h:906
Describes how types, statements, expressions, and declarations should be printed.
Describes an event when the value got stored into a memory region.
@ Assignment
The value got stored into the region during assignment: int x; x = 42;.
@ CallArgument
The value got stored into the parameter region as the result of a call.
@ BlockCapture
The value got stored into the region as block capture.
@ Initialization
The value got stored into the region during initialization: int x = 42;.
const Expr * SourceOfTheValue
The expression where the value comes from.
const ExplodedNode * StoreSite
The node where the store happened.
Kind StoreKind
The type of store operation.
SVal Value
Symbolic value that is being stored.
const MemRegion * Dest
Memory regions involved in the store operation.
Describes a tracking result with the most basic information of what was actually done (or not done).
bool FoundSomethingToTrack
Usually it means that the tracker added visitors.
void combineWith(const Result &Other)
Combines the current result with the given result.
bool WasInterrupted
Signifies that the tracking was interrupted at some point.
Defines a set of options altering tracking behavior.
bool EnableNullFPSuppression
Specifies whether we should employ false positive suppression (inlined defensive checks,...
TrackingKind Kind
Specifies the kind of tracking.