#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include <list>
#include <memory>
+#include <utility>
namespace clang {
Condition
};
+/// Defines a set of options altering tracking behavior.
+struct TrackingOptions {
+ /// Specifies the kind of tracking.
+ TrackingKind Kind = TrackingKind::Thorough;
+ /// Specifies whether we should employ false positive suppression
+ /// (inlined defensive checks, returned null).
+ bool EnableNullFPSuppression = true;
+};
+
+/// Describes an event when the value got stored into a memory region.
+///
+/// As opposed to checker checkBind API, it reacts also to binds
+/// generated by the checker as well. It can be useful when the binding
+/// happened as a result of evalCall, for example.
+struct StoreInfo {
+ enum Kind {
+ /// The value got stored into the region during initialization:
+ /// int x = 42;
+ Initialization,
+ /// The value got stored into the region during assignment:
+ /// int x;
+ /// x = 42;
+ Assignment,
+ /// The value got stored into the region as block capture.
+ /// Block data is modeled as a separate region, thus whenever
+ /// the analyzer sees a captured variable, its value is copied
+ /// into a special block region.
+ BlockCapture
+ };
+
+ /// The type of store operation.
+ Kind StoreKind;
+ /// The node where the store happened.
+ const ExplodedNode *StoreSite;
+ /// The expression where the value comes from.
+ /// NOTE: might be null.
+ Expr *SourceOfTheValue;
+ /// Symbolic value that is being stored.
+ SVal Value;
+ /// Memory regions involved in the store operation.
+ /// Dest <- Origin
+ /// NOTE: Origin might be null, when the stored value doesn't come
+ /// from another region.
+ const MemRegion *Dest, *Origin;
+};
+
+class ExpressionHandler;
+class StoreHandler;
+
+/// A generalized component for tracking expressions, values, and stores.
+///
+/// Tracker aimes at providing a sensible set of default behaviors that can be
+/// used by any checker, while providing mechanisms to hook into any part of the
+/// tracking process and insert checker-specific logic.
+class Tracker {
+private:
+ using ExpressionHandlerPtr = std::unique_ptr<ExpressionHandler>;
+ using StoreHandlerPtr = std::unique_ptr<StoreHandler>;
+
+ PathSensitiveBugReport &Report;
+ std::list<ExpressionHandlerPtr> ExpressionHandlers;
+ std::list<StoreHandlerPtr> StoreHandlers;
+
+public:
+ /// \param Report The bug report to which visitors should be attached.
+ Tracker(PathSensitiveBugReport &Report);
+ virtual ~Tracker() = default;
+
+ PathSensitiveBugReport &getReport() { return Report; }
+
+ /// Describes a tracking result with the most basic information of what was
+ /// actually done (or not done).
+ struct Result {
+ /// Usually it means that the tracker added visitors.
+ bool FoundSomethingToTrack = false;
+ /// Signifies that the tracking was interrupted at some point.
+ /// Usually this information is important only for sub-trackers.
+ bool WasInterrupted = false;
+
+ /// Combines the current result with the given result.
+ void combineWith(const Result &Other) {
+ // If we found something in one of the cases, we can
+ // say we found something overall.
+ FoundSomethingToTrack |= Other.FoundSomethingToTrack;
+ // The same goes to the interruption.
+ WasInterrupted |= Other.WasInterrupted;
+ }
+ };
+
+ /// Track expression value back to its point of origin.
+ ///
+ /// \param E The expression value which we are tracking
+ /// \param N A node "downstream" from the evaluation of the statement.
+ /// \param Opts Tracking options specifying how we want to track the value.
+ virtual Result track(const Expr *E, const ExplodedNode *N,
+ TrackingOptions Opts = {});
+
+ /// Track how the value got stored into the given region and where it came
+ /// from.
+ ///
+ /// \param V We're searching for the store where \c R received this value.
+ /// \param R The region we're tracking.
+ /// \param Opts Tracking options specifying how we want to track the value.
+ /// \param Origin Only adds notes when the last store happened in a
+ /// different stackframe to this one. Disregarded if the tracking kind
+ /// is thorough.
+ /// This is useful, because for non-tracked regions, notes about
+ /// changes to its value in a nested stackframe could be pruned, and
+ /// this visitor can prevent that without polluting the bugpath too
+ /// much.
+ virtual Result track(SVal V, const MemRegion *R, TrackingOptions Opts = {},
+ const StackFrameContext *Origin = nullptr);
+
+ /// Handle the store operation and produce the note.
+ ///
+ /// \param SI The information fully describing the store.
+ /// \param Opts Tracking options specifying how we got to it.
+ ///
+ /// NOTE: this method is designed for sub-trackers and visitors.
+ virtual PathDiagnosticPieceRef handle(StoreInfo SI, TrackingOptions Opts);
+
+ /// Add custom expression handler with the highest priority.
+ ///
+ /// It means that it will be asked for handling first, and can prevent
+ /// other handlers from running if decides to interrupt.
+ void addHighPriorityHandler(ExpressionHandlerPtr SH) {
+ ExpressionHandlers.push_front(std::move(SH));
+ }
+
+ /// Add custom expression handler with the lowest priority.
+ ///
+ /// It means that it will be asked for handling last, and other handlers can
+ /// prevent it from running if any of them decides to interrupt.
+ void addLowPriorityHandler(ExpressionHandlerPtr SH) {
+ ExpressionHandlers.push_back(std::move(SH));
+ }
+
+ /// Add custom store handler with the highest priority.
+ ///
+ /// It means that it will be asked for handling first, and will prevent
+ /// other handlers from running if it produces non-null note.
+ void addHighPriorityHandler(StoreHandlerPtr SH) {
+ StoreHandlers.push_front(std::move(SH));
+ }
+
+ /// Add custom store handler with the lowest priority.
+ ///
+ /// It means that it will be asked for handling last, only
+ /// if all other handlers failed to produce the note.
+ void addLowPriorityHandler(StoreHandlerPtr SH) {
+ StoreHandlers.push_back(std::move(SH));
+ }
+
+ /// Add custom expression/store handler with the highest priority
+ ///
+ /// See other overloads for explanation.
+ template <class HandlerType, class... Args>
+ void addHighPriorityHandler(Args &&... ConstructorArgs) {
+ addHighPriorityHandler(std::make_unique<HandlerType>(
+ *this, std::forward<Args>(ConstructorArgs)...));
+ }
+
+ /// Add custom expression/store handler with the lowest priority
+ ///
+ /// See other overloads for explanation.
+ template <class HandlerType, class... Args>
+ void addLowPriorityHandler(Args &&... ConstructorArgs) {
+ addLowPriorityHandler(std::make_unique<HandlerType>(
+ *this, std::forward<Args>(ConstructorArgs)...));
+ }
+};
+
+/// Handles expressions during the tracking.
+class ExpressionHandler {
+private:
+ Tracker &ParentTracker;
+
+public:
+ ExpressionHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
+ virtual ~ExpressionHandler() {}
+
+ /// Handle the given expression from the given node.
+ ///
+ /// \param E The expression value which we are tracking
+ /// \param Original A node "downstream" where the tracking started.
+ /// \param ExprNode A node where the evaluation of \c E actually happens.
+ /// \param Opts Tracking options specifying how we are tracking the value.
+ virtual Tracker::Result handle(const Expr *E, const ExplodedNode *Original,
+ const ExplodedNode *ExprNode,
+ TrackingOptions Opts) = 0;
+
+ /// \Return the tracker that initiated the process.
+ Tracker &getParentTracker() { return ParentTracker; }
+};
+
+/// Handles stores during the tracking.
+class StoreHandler {
+private:
+ Tracker &ParentTracker;
+
+public:
+ StoreHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
+ virtual ~StoreHandler() {}
+
+ /// Handle the given store and produce the node.
+ ///
+ /// \param E The expression value which we are tracking
+ /// \param N A node where the evaluation of \c E actually happens.
+ /// \param Opts Tracking options specifying how we are tracking the value.
+ ///
+ /// \return the produced note, null if the handler doesn't support this kind
+ /// of stores.
+ virtual PathDiagnosticPieceRef handle(StoreInfo SI, TrackingOptions Opts) = 0;
+
+ Tracker &getParentTracker() { return ParentTracker; }
+};
+
/// Attempts to add visitors to track expression value back to its point of
/// origin.
///
using namespace clang;
using namespace ento;
+using namespace bugreporter;
//===----------------------------------------------------------------------===//
// Utility functions.
}
}
+//===----------------------------------------------------------------------===//
+// Tracker implementation
+//===----------------------------------------------------------------------===//
+
+Tracker::Tracker(PathSensitiveBugReport &Report) : Report(Report) {
+ // TODO: split trackExpressionValue and FindLastStoreBRVisitor into handlers
+ // and add them here.
+}
+
+Tracker::Result Tracker::track(const Expr *E, const ExplodedNode *N,
+ TrackingOptions Opts) {
+ if (!E || !N)
+ return {};
+
+ const Expr *Inner = peelOffOuterExpr(E, N);
+ const ExplodedNode *LVNode = findNodeForExpression(N, Inner);
+ if (!LVNode)
+ return {};
+
+ Result CombinedResult;
+ // Iterate through the handlers in the order according to their priorities.
+ for (ExpressionHandlerPtr &Handler : ExpressionHandlers) {
+ CombinedResult.combineWith(Handler->handle(Inner, N, LVNode, Opts));
+ if (CombinedResult.WasInterrupted)
+ break;
+ }
+
+ return CombinedResult;
+}
+
+Tracker::Result Tracker::track(SVal V, const MemRegion *R, TrackingOptions Opts,
+ const StackFrameContext *Origin) {
+ // TODO: support this operation after dismantling FindLastStoreBRVisitor
+ return {};
+}
+
+PathDiagnosticPieceRef Tracker::handle(StoreInfo SI, TrackingOptions Opts) {
+ // Iterate through the handlers in the order according to their priorities.
+ for (StoreHandlerPtr &Handler : StoreHandlers) {
+ if (PathDiagnosticPieceRef Result = Handler->handle(SI, Opts))
+ // If the handler produced a non-null piece, return it.
+ // There is no need in asking other handlers.
+ return Result;
+ }
+ return {};
+}
+
bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
const Expr *E,
PathSensitiveBugReport &report,