• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //== CheckerContext.h - Context info for path-sensitive checkers--*- C++ -*--=//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines CheckerContext that provides contextual info for
11 // path-sensitive checkers.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
16 #define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
17 
18 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
19 
20 namespace clang {
21 namespace ento {
22 
23 class CheckerContext {
24   ExprEngine &Eng;
25   /// The current exploded(symbolic execution) graph node.
26   ExplodedNode *Pred;
27   /// The flag is true if the (state of the execution) has been modified
28   /// by the checker using this context. For example, a new transition has been
29   /// added or a bug report issued.
30   bool Changed;
31   /// The tagged location, which is used to generate all new nodes.
32   const ProgramPoint Location;
33   NodeBuilder &NB;
34 
35 public:
36   /// If we are post visiting a call, this flag will be set if the
37   /// call was inlined.  In all other cases it will be false.
38   const bool wasInlined;
39 
40   CheckerContext(NodeBuilder &builder,
41                  ExprEngine &eng,
42                  ExplodedNode *pred,
43                  const ProgramPoint &loc,
44                  bool wasInlined = false)
Eng(eng)45     : Eng(eng),
46       Pred(pred),
47       Changed(false),
48       Location(loc),
49       NB(builder),
50       wasInlined(wasInlined) {
51     assert(Pred->getState() &&
52            "We should not call the checkers on an empty state.");
53   }
54 
getAnalysisManager()55   AnalysisManager &getAnalysisManager() {
56     return Eng.getAnalysisManager();
57   }
58 
getConstraintManager()59   ConstraintManager &getConstraintManager() {
60     return Eng.getConstraintManager();
61   }
62 
getStoreManager()63   StoreManager &getStoreManager() {
64     return Eng.getStoreManager();
65   }
66 
getConfig()67   const AnalyzerOptions::ConfigTable &getConfig() const {
68     return Eng.getAnalysisManager().options.Config;
69   }
70 
71   /// \brief Returns the previous node in the exploded graph, which includes
72   /// the state of the program before the checker ran. Note, checkers should
73   /// not retain the node in their state since the nodes might get invalidated.
getPredecessor()74   ExplodedNode *getPredecessor() { return Pred; }
getState()75   ProgramStateRef getState() const { return Pred->getState(); }
76 
77   /// \brief Check if the checker changed the state of the execution; ex: added
78   /// a new transition or a bug report.
isDifferent()79   bool isDifferent() { return Changed; }
80 
81   /// \brief Returns the number of times the current block has been visited
82   /// along the analyzed path.
blockCount()83   unsigned blockCount() const {
84     return NB.getContext().blockCount();
85   }
86 
getASTContext()87   ASTContext &getASTContext() {
88     return Eng.getContext();
89   }
90 
getLangOpts()91   const LangOptions &getLangOpts() const {
92     return Eng.getContext().getLangOpts();
93   }
94 
getLocationContext()95   const LocationContext *getLocationContext() const {
96     return Pred->getLocationContext();
97   }
98 
getStackFrame()99   const StackFrameContext *getStackFrame() const {
100     return Pred->getStackFrame();
101   }
102 
103   /// Returns true if the predecessor is within an inlined function/method.
isWithinInlined()104   bool isWithinInlined() {
105     return (getStackFrame()->getParent() != 0);
106   }
107 
getBugReporter()108   BugReporter &getBugReporter() {
109     return Eng.getBugReporter();
110   }
111 
getSourceManager()112   SourceManager &getSourceManager() {
113     return getBugReporter().getSourceManager();
114   }
115 
getSValBuilder()116   SValBuilder &getSValBuilder() {
117     return Eng.getSValBuilder();
118   }
119 
getSymbolManager()120   SymbolManager &getSymbolManager() {
121     return getSValBuilder().getSymbolManager();
122   }
123 
isObjCGCEnabled()124   bool isObjCGCEnabled() const {
125     return Eng.isObjCGCEnabled();
126   }
127 
getStateManager()128   ProgramStateManager &getStateManager() {
129     return Eng.getStateManager();
130   }
131 
getCurrentAnalysisDeclContext()132   AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
133     return Pred->getLocationContext()->getAnalysisDeclContext();
134   }
135 
136   /// \brief If the given node corresponds to a PostStore program point, retrieve
137   /// 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.
getLocationRegionIfPostStore(const ExplodedNode * N)141   static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) {
142     ProgramPoint L = N->getLocation();
143     if (const PostStore *PSL = dyn_cast<PostStore>(&L))
144       return reinterpret_cast<const MemRegion*>(PSL->getLocationValue());
145     return 0;
146   }
147 
148   /// \brief Get the value of arbitrary expressions at this point in the path.
getSVal(const Stmt * S)149   SVal getSVal(const Stmt *S) const {
150     return getState()->getSVal(S, getLocationContext());
151   }
152 
153   /// \brief Generates a new transition in the program state graph
154   /// (ExplodedGraph). Uses the default CheckerContext predecessor node.
155   ///
156   /// @param State The state of the generated node. If not specified, the state
157   ///        will not be changed, but the new node will have the checker's tag.
158   /// @param Tag The tag is used to uniquely identify the creation site. If no
159   ///        tag is specified, a default tag, unique to the given checker,
160   ///        will be used. Tags are used to prevent states generated at
161   ///        different sites from caching out.
162   ExplodedNode *addTransition(ProgramStateRef State = 0,
163                               const ProgramPointTag *Tag = 0) {
164     return addTransitionImpl(State ? State : getState(), false, 0, Tag);
165   }
166 
167   /// \brief Generates a new transition with the given predecessor.
168   /// Allows checkers to generate a chain of nodes.
169   ///
170   /// @param State The state of the generated node.
171   /// @param Pred The transition will be generated from the specified Pred node
172   ///             to the newly generated node.
173   /// @param Tag The tag to uniquely identify the creation site.
174   ExplodedNode *addTransition(ProgramStateRef State,
175                               ExplodedNode *Pred,
176                               const ProgramPointTag *Tag = 0) {
177     return addTransitionImpl(State, false, Pred, Tag);
178   }
179 
180   /// \brief Generate a sink node. Generating a sink stops exploration of the
181   /// given path.
182   ExplodedNode *generateSink(ProgramStateRef State = 0,
183                              ExplodedNode *Pred = 0,
184                              const ProgramPointTag *Tag = 0) {
185     return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
186   }
187 
188   /// \brief Emit the diagnostics report.
EmitReport(BugReport * R)189   void EmitReport(BugReport *R) {
190     Changed = true;
191     Eng.getBugReporter().EmitReport(R);
192   }
193 
194   /// \brief Get the declaration of the called function (path-sensitive).
195   const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
196 
197   /// \brief Get the name of the called function (path-sensitive).
198   StringRef getCalleeName(const FunctionDecl *FunDecl) const;
199 
200   /// \brief Get the name of the called function (path-sensitive).
getCalleeName(const CallExpr * CE)201   StringRef getCalleeName(const CallExpr *CE) const {
202     const FunctionDecl *FunDecl = getCalleeDecl(CE);
203     return getCalleeName(FunDecl);
204   }
205 
206   /// Given a function declaration and a name checks if this is a C lib
207   /// function with the given name.
208   bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name);
209   static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name,
210                                  ASTContext &Context);
211 
212   /// \brief Depending on wither the location corresponds to a macro, return
213   /// either the macro name or the token spelling.
214   ///
215   /// This could be useful when checkers' logic depends on whether a function
216   /// is called with a given macro argument. For example:
217   ///   s = socket(AF_INET,..)
218   /// If AF_INET is a macro, the result should be treated as a source of taint.
219   ///
220   /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName().
221   StringRef getMacroNameOrSpelling(SourceLocation &Loc);
222 
223 private:
224   ExplodedNode *addTransitionImpl(ProgramStateRef State,
225                                  bool MarkAsSink,
226                                  ExplodedNode *P = 0,
227                                  const ProgramPointTag *Tag = 0) {
228     if (!State || (State == Pred->getState() && !Tag && !MarkAsSink))
229       return Pred;
230 
231     Changed = true;
232     const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
233     if (!P)
234       P = Pred;
235 
236     ExplodedNode *node;
237     if (MarkAsSink)
238       node = NB.generateSink(LocalLoc, State, P);
239     else
240       node = NB.generateNode(LocalLoc, State, P);
241     return node;
242   }
243 };
244 
245 /// \brief A helper class which wraps a boolean value set to false by default.
246 struct DefaultBool {
247   bool Val;
DefaultBoolDefaultBool248   DefaultBool() : Val(false) {}
249   operator bool() const { return Val; }
250   DefaultBool &operator=(bool b) { Val = b; return *this; }
251 };
252 
253 } // end GR namespace
254 
255 } // end clang namespace
256 
257 #endif
258