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