Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //== CheckerContext.h - Context info for path-sensitive checkers--*- 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 defines CheckerContext that provides contextual info for
  10. // path-sensitive checkers.
  11. //
  12. //===----------------------------------------------------------------------===//
  13.  
  14. #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
  15. #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
  16.  
  17. #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
  18. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
  19. #include <optional>
  20.  
  21. namespace clang {
  22. namespace ento {
  23.  
  24. class CheckerContext {
  25.   ExprEngine &Eng;
  26.   /// The current exploded(symbolic execution) graph node.
  27.   ExplodedNode *Pred;
  28.   /// The flag is true if the (state of the execution) has been modified
  29.   /// by the checker using this context. For example, a new transition has been
  30.   /// added or a bug report issued.
  31.   bool Changed;
  32.   /// The tagged location, which is used to generate all new nodes.
  33.   const ProgramPoint Location;
  34.   NodeBuilder &NB;
  35.  
  36. public:
  37.   /// If we are post visiting a call, this flag will be set if the
  38.   /// call was inlined.  In all other cases it will be false.
  39.   const bool wasInlined;
  40.  
  41.   CheckerContext(NodeBuilder &builder,
  42.                  ExprEngine &eng,
  43.                  ExplodedNode *pred,
  44.                  const ProgramPoint &loc,
  45.                  bool wasInlined = false)
  46.     : Eng(eng),
  47.       Pred(pred),
  48.       Changed(false),
  49.       Location(loc),
  50.       NB(builder),
  51.       wasInlined(wasInlined) {
  52.     assert(Pred->getState() &&
  53.            "We should not call the checkers on an empty state.");
  54.   }
  55.  
  56.   AnalysisManager &getAnalysisManager() {
  57.     return Eng.getAnalysisManager();
  58.   }
  59.  
  60.   ConstraintManager &getConstraintManager() {
  61.     return Eng.getConstraintManager();
  62.   }
  63.  
  64.   StoreManager &getStoreManager() {
  65.     return Eng.getStoreManager();
  66.   }
  67.  
  68.   /// Returns the previous node in the exploded graph, which includes
  69.   /// the state of the program before the checker ran. Note, checkers should
  70.   /// not retain the node in their state since the nodes might get invalidated.
  71.   ExplodedNode *getPredecessor() { return Pred; }
  72.   const ProgramStateRef &getState() const { return Pred->getState(); }
  73.  
  74.   /// Check if the checker changed the state of the execution; ex: added
  75.   /// a new transition or a bug report.
  76.   bool isDifferent() { return Changed; }
  77.  
  78.   /// Returns the number of times the current block has been visited
  79.   /// along the analyzed path.
  80.   unsigned blockCount() const {
  81.     return NB.getContext().blockCount();
  82.   }
  83.  
  84.   ASTContext &getASTContext() {
  85.     return Eng.getContext();
  86.   }
  87.  
  88.   const ASTContext &getASTContext() const { return Eng.getContext(); }
  89.  
  90.   const LangOptions &getLangOpts() const {
  91.     return Eng.getContext().getLangOpts();
  92.   }
  93.  
  94.   const LocationContext *getLocationContext() const {
  95.     return Pred->getLocationContext();
  96.   }
  97.  
  98.   const StackFrameContext *getStackFrame() const {
  99.     return Pred->getStackFrame();
  100.   }
  101.  
  102.   /// Return true if the current LocationContext has no caller context.
  103.   bool inTopFrame() const { return getLocationContext()->inTopFrame();  }
  104.  
  105.   BugReporter &getBugReporter() {
  106.     return Eng.getBugReporter();
  107.   }
  108.  
  109.   const SourceManager &getSourceManager() {
  110.     return getBugReporter().getSourceManager();
  111.   }
  112.  
  113.   Preprocessor &getPreprocessor() { return getBugReporter().getPreprocessor(); }
  114.  
  115.   SValBuilder &getSValBuilder() {
  116.     return Eng.getSValBuilder();
  117.   }
  118.  
  119.   SymbolManager &getSymbolManager() {
  120.     return getSValBuilder().getSymbolManager();
  121.   }
  122.  
  123.   ProgramStateManager &getStateManager() {
  124.     return Eng.getStateManager();
  125.   }
  126.  
  127.   AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
  128.     return Pred->getLocationContext()->getAnalysisDeclContext();
  129.   }
  130.  
  131.   /// Get the blockID.
  132.   unsigned getBlockID() const {
  133.     return NB.getContext().getBlock()->getBlockID();
  134.   }
  135.  
  136.   /// If the given node corresponds to a PostStore program point,
  137.   /// retrieve the location region as it was uttered in the code.
  138.   ///
  139.   /// This utility can be useful for generating extensive diagnostics, for
  140.   /// example, for finding variables that the given symbol was assigned to.
  141.   static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) {
  142.     ProgramPoint L = N->getLocation();
  143.     if (std::optional<PostStore> PSL = L.getAs<PostStore>())
  144.       return reinterpret_cast<const MemRegion*>(PSL->getLocationValue());
  145.     return nullptr;
  146.   }
  147.  
  148.   /// Get the value of arbitrary expressions at this point in the path.
  149.   SVal getSVal(const Stmt *S) const {
  150.     return Pred->getSVal(S);
  151.   }
  152.  
  153.   /// Returns true if the value of \p E is greater than or equal to \p
  154.   /// Val under unsigned comparison
  155.   bool isGreaterOrEqual(const Expr *E, unsigned long long Val);
  156.  
  157.   /// Returns true if the value of \p E is negative.
  158.   bool isNegative(const Expr *E);
  159.  
  160.   /// Generates a new transition in the program state graph
  161.   /// (ExplodedGraph). Uses the default CheckerContext predecessor node.
  162.   ///
  163.   /// @param State The state of the generated node. If not specified, the state
  164.   ///        will not be changed, but the new node will have the checker's tag.
  165.   /// @param Tag The tag is used to uniquely identify the creation site. If no
  166.   ///        tag is specified, a default tag, unique to the given checker,
  167.   ///        will be used. Tags are used to prevent states generated at
  168.   ///        different sites from caching out.
  169.   ExplodedNode *addTransition(ProgramStateRef State = nullptr,
  170.                               const ProgramPointTag *Tag = nullptr) {
  171.     return addTransitionImpl(State ? State : getState(), false, nullptr, Tag);
  172.   }
  173.  
  174.   /// Generates a new transition with the given predecessor.
  175.   /// Allows checkers to generate a chain of nodes.
  176.   ///
  177.   /// @param State The state of the generated node.
  178.   /// @param Pred The transition will be generated from the specified Pred node
  179.   ///             to the newly generated node.
  180.   /// @param Tag The tag to uniquely identify the creation site.
  181.   ExplodedNode *addTransition(ProgramStateRef State, ExplodedNode *Pred,
  182.                               const ProgramPointTag *Tag = nullptr) {
  183.     return addTransitionImpl(State, false, Pred, Tag);
  184.   }
  185.  
  186.   /// Generate a sink node. Generating a sink stops exploration of the
  187.   /// given path. To create a sink node for the purpose of reporting an error,
  188.   /// checkers should use generateErrorNode() instead.
  189.   ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
  190.                              const ProgramPointTag *Tag = nullptr) {
  191.     return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
  192.   }
  193.  
  194.   /// Add a sink node to the current path of execution, halting analysis.
  195.   void addSink(ProgramStateRef State = nullptr,
  196.                const ProgramPointTag *Tag = nullptr) {
  197.     if (!State)
  198.       State = getState();
  199.     addTransition(State, generateSink(State, getPredecessor()));
  200.   }
  201.  
  202.   /// Generate a transition to a node that will be used to report
  203.   /// an error. This node will be a sink. That is, it will stop exploration of
  204.   /// the given path.
  205.   ///
  206.   /// @param State The state of the generated node.
  207.   /// @param Tag The tag to uniquely identify the creation site. If null,
  208.   ///        the default tag for the checker will be used.
  209.   ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr,
  210.                                   const ProgramPointTag *Tag = nullptr) {
  211.     return generateSink(State, Pred,
  212.                        (Tag ? Tag : Location.getTag()));
  213.   }
  214.  
  215.   /// Generate a transition to a node that will be used to report
  216.   /// an error. This node will be a sink. That is, it will stop exploration of
  217.   /// the given path.
  218.   ///
  219.   /// @param State The state of the generated node.
  220.   /// @param Pred The transition will be generated from the specified Pred node
  221.   ///             to the newly generated node.
  222.   /// @param Tag The tag to uniquely identify the creation site. If null,
  223.   ///        the default tag for the checker will be used.
  224.   ExplodedNode *generateErrorNode(ProgramStateRef State,
  225.                                   ExplodedNode *Pred,
  226.                                   const ProgramPointTag *Tag = nullptr) {
  227.     return generateSink(State, Pred,
  228.                        (Tag ? Tag : Location.getTag()));
  229.   }
  230.  
  231.   /// Generate a transition to a node that will be used to report
  232.   /// an error. This node will not be a sink. That is, exploration will
  233.   /// continue along this path.
  234.   ///
  235.   /// @param State The state of the generated node.
  236.   /// @param Tag The tag to uniquely identify the creation site. If null,
  237.   ///        the default tag for the checker will be used.
  238.   ExplodedNode *
  239.   generateNonFatalErrorNode(ProgramStateRef State = nullptr,
  240.                             const ProgramPointTag *Tag = nullptr) {
  241.     return addTransition(State, (Tag ? Tag : Location.getTag()));
  242.   }
  243.  
  244.   /// Generate a transition to a node that will be used to report
  245.   /// an error. This node will not be a sink. That is, exploration will
  246.   /// continue along this path.
  247.   ///
  248.   /// @param State The state of the generated node.
  249.   /// @param Pred The transition will be generated from the specified Pred node
  250.   ///             to the newly generated node.
  251.   /// @param Tag The tag to uniquely identify the creation site. If null,
  252.   ///        the default tag for the checker will be used.
  253.   ExplodedNode *
  254.   generateNonFatalErrorNode(ProgramStateRef State,
  255.                             ExplodedNode *Pred,
  256.                             const ProgramPointTag *Tag = nullptr) {
  257.     return addTransition(State, Pred, (Tag ? Tag : Location.getTag()));
  258.   }
  259.  
  260.   /// Emit the diagnostics report.
  261.   void emitReport(std::unique_ptr<BugReport> R) {
  262.     Changed = true;
  263.     Eng.getBugReporter().emitReport(std::move(R));
  264.   }
  265.  
  266.   /// Produce a program point tag that displays an additional path note
  267.   /// to the user. This is a lightweight alternative to the
  268.   /// BugReporterVisitor mechanism: instead of visiting the bug report
  269.   /// node-by-node to restore the sequence of events that led to discovering
  270.   /// a bug, you can add notes as you add your transitions.
  271.   ///
  272.   /// @param Cb Callback with 'BugReporterContext &, BugReport &' parameters.
  273.   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
  274.   ///        to omit the note from the report if it would make the displayed
  275.   ///        bug path significantly shorter.
  276.   LLVM_ATTRIBUTE_RETURNS_NONNULL
  277.   const NoteTag *getNoteTag(NoteTag::Callback &&Cb, bool IsPrunable = false) {
  278.     return Eng.getDataTags().make<NoteTag>(std::move(Cb), IsPrunable);
  279.   }
  280.  
  281.   /// A shorthand version of getNoteTag that doesn't require you to accept
  282.   /// the 'BugReporterContext' argument when you don't need it.
  283.   ///
  284.   /// @param Cb Callback only with 'BugReport &' parameter.
  285.   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
  286.   ///        to omit the note from the report if it would make the displayed
  287.   ///        bug path significantly shorter.
  288.   const NoteTag
  289.   *getNoteTag(std::function<std::string(PathSensitiveBugReport &)> &&Cb,
  290.               bool IsPrunable = false) {
  291.     return getNoteTag(
  292.         [Cb](BugReporterContext &,
  293.              PathSensitiveBugReport &BR) { return Cb(BR); },
  294.         IsPrunable);
  295.   }
  296.  
  297.   /// A shorthand version of getNoteTag that doesn't require you to accept
  298.   /// the arguments when you don't need it.
  299.   ///
  300.   /// @param Cb Callback without parameters.
  301.   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
  302.   ///        to omit the note from the report if it would make the displayed
  303.   ///        bug path significantly shorter.
  304.   const NoteTag *getNoteTag(std::function<std::string()> &&Cb,
  305.                             bool IsPrunable = false) {
  306.     return getNoteTag([Cb](BugReporterContext &,
  307.                            PathSensitiveBugReport &) { return Cb(); },
  308.                       IsPrunable);
  309.   }
  310.  
  311.   /// A shorthand version of getNoteTag that accepts a plain note.
  312.   ///
  313.   /// @param Note The note.
  314.   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
  315.   ///        to omit the note from the report if it would make the displayed
  316.   ///        bug path significantly shorter.
  317.   const NoteTag *getNoteTag(StringRef Note, bool IsPrunable = false) {
  318.     return getNoteTag(
  319.         [Note](BugReporterContext &,
  320.                PathSensitiveBugReport &) { return std::string(Note); },
  321.         IsPrunable);
  322.   }
  323.  
  324.   /// A shorthand version of getNoteTag that accepts a lambda with stream for
  325.   /// note.
  326.   ///
  327.   /// @param Cb Callback with 'BugReport &' and 'llvm::raw_ostream &'.
  328.   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
  329.   ///        to omit the note from the report if it would make the displayed
  330.   ///        bug path significantly shorter.
  331.   const NoteTag *getNoteTag(
  332.       std::function<void(PathSensitiveBugReport &BR, llvm::raw_ostream &OS)> &&Cb,
  333.       bool IsPrunable = false) {
  334.     return getNoteTag(
  335.         [Cb](PathSensitiveBugReport &BR) -> std::string {
  336.           llvm::SmallString<128> Str;
  337.           llvm::raw_svector_ostream OS(Str);
  338.           Cb(BR, OS);
  339.           return std::string(OS.str());
  340.         },
  341.         IsPrunable);
  342.   }
  343.  
  344.   /// Returns the word that should be used to refer to the declaration
  345.   /// in the report.
  346.   StringRef getDeclDescription(const Decl *D);
  347.  
  348.   /// Get the declaration of the called function (path-sensitive).
  349.   const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
  350.  
  351.   /// Get the name of the called function (path-sensitive).
  352.   StringRef getCalleeName(const FunctionDecl *FunDecl) const;
  353.  
  354.   /// Get the identifier of the called function (path-sensitive).
  355.   const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const {
  356.     const FunctionDecl *FunDecl = getCalleeDecl(CE);
  357.     if (FunDecl)
  358.       return FunDecl->getIdentifier();
  359.     else
  360.       return nullptr;
  361.   }
  362.  
  363.   /// Get the name of the called function (path-sensitive).
  364.   StringRef getCalleeName(const CallExpr *CE) const {
  365.     const FunctionDecl *FunDecl = getCalleeDecl(CE);
  366.     return getCalleeName(FunDecl);
  367.   }
  368.  
  369.   /// Returns true if the callee is an externally-visible function in the
  370.   /// top-level namespace, such as \c malloc.
  371.   ///
  372.   /// If a name is provided, the function must additionally match the given
  373.   /// name.
  374.   ///
  375.   /// Note that this deliberately excludes C++ library functions in the \c std
  376.   /// namespace, but will include C library functions accessed through the
  377.   /// \c std namespace. This also does not check if the function is declared
  378.   /// as 'extern "C"', or if it uses C++ name mangling.
  379.   static bool isCLibraryFunction(const FunctionDecl *FD,
  380.                                  StringRef Name = StringRef());
  381.  
  382.   /// Depending on wither the location corresponds to a macro, return
  383.   /// either the macro name or the token spelling.
  384.   ///
  385.   /// This could be useful when checkers' logic depends on whether a function
  386.   /// is called with a given macro argument. For example:
  387.   ///   s = socket(AF_INET,..)
  388.   /// If AF_INET is a macro, the result should be treated as a source of taint.
  389.   ///
  390.   /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName().
  391.   StringRef getMacroNameOrSpelling(SourceLocation &Loc);
  392.  
  393. private:
  394.   ExplodedNode *addTransitionImpl(ProgramStateRef State,
  395.                                  bool MarkAsSink,
  396.                                  ExplodedNode *P = nullptr,
  397.                                  const ProgramPointTag *Tag = nullptr) {
  398.     // The analyzer may stop exploring if it sees a state it has previously
  399.     // visited ("cache out"). The early return here is a defensive check to
  400.     // prevent accidental caching out by checker API clients. Unless there is a
  401.     // tag or the client checker has requested that the generated node be
  402.     // marked as a sink, we assume that a client requesting a transition to a
  403.     // state that is the same as the predecessor state has made a mistake. We
  404.     // return the predecessor rather than cache out.
  405.     //
  406.     // TODO: We could potentially change the return to an assertion to alert
  407.     // clients to their mistake, but several checkers (including
  408.     // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation)
  409.     // rely upon the defensive behavior and would need to be updated.
  410.     if (!State || (State == Pred->getState() && !Tag && !MarkAsSink))
  411.       return Pred;
  412.  
  413.     Changed = true;
  414.     const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
  415.     if (!P)
  416.       P = Pred;
  417.  
  418.     ExplodedNode *node;
  419.     if (MarkAsSink)
  420.       node = NB.generateSink(LocalLoc, State, P);
  421.     else
  422.       node = NB.generateNode(LocalLoc, State, P);
  423.     return node;
  424.   }
  425. };
  426.  
  427. } // end GR namespace
  428.  
  429. } // end clang namespace
  430.  
  431. #endif
  432.