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_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H 16 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H 17 18 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 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) Eng(eng)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 getAnalysisManager()56 AnalysisManager &getAnalysisManager() { 57 return Eng.getAnalysisManager(); 58 } 59 getConstraintManager()60 ConstraintManager &getConstraintManager() { 61 return Eng.getConstraintManager(); 62 } 63 getStoreManager()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. getPredecessor()71 ExplodedNode *getPredecessor() { return Pred; } getState()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. isDifferent()76 bool isDifferent() { return Changed; } 77 78 /// Returns the number of times the current block has been visited 79 /// along the analyzed path. blockCount()80 unsigned blockCount() const { 81 return NB.getContext().blockCount(); 82 } 83 getASTContext()84 ASTContext &getASTContext() { 85 return Eng.getContext(); 86 } 87 getLangOpts()88 const LangOptions &getLangOpts() const { 89 return Eng.getContext().getLangOpts(); 90 } 91 getLocationContext()92 const LocationContext *getLocationContext() const { 93 return Pred->getLocationContext(); 94 } 95 getStackFrame()96 const StackFrameContext *getStackFrame() const { 97 return Pred->getStackFrame(); 98 } 99 100 /// Return true if the current LocationContext has no caller context. inTopFrame()101 bool inTopFrame() const { return getLocationContext()->inTopFrame(); } 102 getBugReporter()103 BugReporter &getBugReporter() { 104 return Eng.getBugReporter(); 105 } 106 getSourceManager()107 SourceManager &getSourceManager() { 108 return getBugReporter().getSourceManager(); 109 } 110 getSValBuilder()111 SValBuilder &getSValBuilder() { 112 return Eng.getSValBuilder(); 113 } 114 getSymbolManager()115 SymbolManager &getSymbolManager() { 116 return getSValBuilder().getSymbolManager(); 117 } 118 getStateManager()119 ProgramStateManager &getStateManager() { 120 return Eng.getStateManager(); 121 } 122 getCurrentAnalysisDeclContext()123 AnalysisDeclContext *getCurrentAnalysisDeclContext() const { 124 return Pred->getLocationContext()->getAnalysisDeclContext(); 125 } 126 127 /// Get the blockID. getBlockID()128 unsigned getBlockID() const { 129 return NB.getContext().getBlock()->getBlockID(); 130 } 131 132 /// If the given node corresponds to a PostStore program point, 133 /// retrieve the location region as it was uttered in the code. 134 /// 135 /// This utility can be useful for generating extensive diagnostics, for 136 /// example, for finding variables that the given symbol was assigned to. getLocationRegionIfPostStore(const ExplodedNode * N)137 static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) { 138 ProgramPoint L = N->getLocation(); 139 if (Optional<PostStore> PSL = L.getAs<PostStore>()) 140 return reinterpret_cast<const MemRegion*>(PSL->getLocationValue()); 141 return nullptr; 142 } 143 144 /// Get the value of arbitrary expressions at this point in the path. getSVal(const Stmt * S)145 SVal getSVal(const Stmt *S) const { 146 return Pred->getSVal(S); 147 } 148 149 /// Returns true if the value of \p E is greater than or equal to \p 150 /// Val under unsigned comparison 151 bool isGreaterOrEqual(const Expr *E, unsigned long long Val); 152 153 /// Returns true if the value of \p E is negative. 154 bool isNegative(const Expr *E); 155 156 /// Generates a new transition in the program state graph 157 /// (ExplodedGraph). Uses the default CheckerContext predecessor node. 158 /// 159 /// @param State The state of the generated node. If not specified, the state 160 /// will not be changed, but the new node will have the checker's tag. 161 /// @param Tag The tag is used to uniquely identify the creation site. If no 162 /// tag is specified, a default tag, unique to the given checker, 163 /// will be used. Tags are used to prevent states generated at 164 /// different sites from caching out. 165 ExplodedNode *addTransition(ProgramStateRef State = nullptr, 166 const ProgramPointTag *Tag = nullptr) { 167 return addTransitionImpl(State ? State : getState(), false, nullptr, Tag); 168 } 169 170 /// Generates a new transition with the given predecessor. 171 /// Allows checkers to generate a chain of nodes. 172 /// 173 /// @param State The state of the generated node. 174 /// @param Pred The transition will be generated from the specified Pred node 175 /// to the newly generated node. 176 /// @param Tag The tag to uniquely identify the creation site. 177 ExplodedNode *addTransition(ProgramStateRef State, 178 ExplodedNode *Pred, 179 const ProgramPointTag *Tag = nullptr) { 180 return addTransitionImpl(State, false, Pred, Tag); 181 } 182 183 /// Generate a sink node. Generating a sink stops exploration of the 184 /// given path. To create a sink node for the purpose of reporting an error, 185 /// checkers should use generateErrorNode() instead. 186 ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred, 187 const ProgramPointTag *Tag = nullptr) { 188 return addTransitionImpl(State ? State : getState(), true, Pred, Tag); 189 } 190 191 /// Generate a transition to a node that will be used to report 192 /// an error. This node will be a sink. That is, it will stop exploration of 193 /// the given path. 194 /// 195 /// @param State The state of the generated node. 196 /// @param Tag The tag to uniquely identify the creation site. If null, 197 /// the default tag for the checker will be used. 198 ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr, 199 const ProgramPointTag *Tag = nullptr) { 200 return generateSink(State, Pred, 201 (Tag ? Tag : Location.getTag())); 202 } 203 204 /// Generate a transition to a node that will be used to report 205 /// an error. This node will not be a sink. That is, exploration will 206 /// continue along this path. 207 /// 208 /// @param State The state of the generated node. 209 /// @param Tag The tag to uniquely identify the creation site. If null, 210 /// the default tag for the checker will be used. 211 ExplodedNode * 212 generateNonFatalErrorNode(ProgramStateRef State = nullptr, 213 const ProgramPointTag *Tag = nullptr) { 214 return addTransition(State, (Tag ? Tag : Location.getTag())); 215 } 216 217 /// Emit the diagnostics report. emitReport(std::unique_ptr<BugReport> R)218 void emitReport(std::unique_ptr<BugReport> R) { 219 Changed = true; 220 Eng.getBugReporter().emitReport(std::move(R)); 221 } 222 223 /// Returns the word that should be used to refer to the declaration 224 /// in the report. 225 StringRef getDeclDescription(const Decl *D); 226 227 /// Get the declaration of the called function (path-sensitive). 228 const FunctionDecl *getCalleeDecl(const CallExpr *CE) const; 229 230 /// Get the name of the called function (path-sensitive). 231 StringRef getCalleeName(const FunctionDecl *FunDecl) const; 232 233 /// Get the identifier of the called function (path-sensitive). getCalleeIdentifier(const CallExpr * CE)234 const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const { 235 const FunctionDecl *FunDecl = getCalleeDecl(CE); 236 if (FunDecl) 237 return FunDecl->getIdentifier(); 238 else 239 return nullptr; 240 } 241 242 /// Get the name of the called function (path-sensitive). getCalleeName(const CallExpr * CE)243 StringRef getCalleeName(const CallExpr *CE) const { 244 const FunctionDecl *FunDecl = getCalleeDecl(CE); 245 return getCalleeName(FunDecl); 246 } 247 248 /// Returns true if the callee is an externally-visible function in the 249 /// top-level namespace, such as \c malloc. 250 /// 251 /// If a name is provided, the function must additionally match the given 252 /// name. 253 /// 254 /// Note that this deliberately excludes C++ library functions in the \c std 255 /// namespace, but will include C library functions accessed through the 256 /// \c std namespace. This also does not check if the function is declared 257 /// as 'extern "C"', or if it uses C++ name mangling. 258 static bool isCLibraryFunction(const FunctionDecl *FD, 259 StringRef Name = StringRef()); 260 261 /// Depending on wither the location corresponds to a macro, return 262 /// either the macro name or the token spelling. 263 /// 264 /// This could be useful when checkers' logic depends on whether a function 265 /// is called with a given macro argument. For example: 266 /// s = socket(AF_INET,..) 267 /// If AF_INET is a macro, the result should be treated as a source of taint. 268 /// 269 /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName(). 270 StringRef getMacroNameOrSpelling(SourceLocation &Loc); 271 272 private: 273 ExplodedNode *addTransitionImpl(ProgramStateRef State, 274 bool MarkAsSink, 275 ExplodedNode *P = nullptr, 276 const ProgramPointTag *Tag = nullptr) { 277 // The analyzer may stop exploring if it sees a state it has previously 278 // visited ("cache out"). The early return here is a defensive check to 279 // prevent accidental caching out by checker API clients. Unless there is a 280 // tag or the client checker has requested that the generated node be 281 // marked as a sink, we assume that a client requesting a transition to a 282 // state that is the same as the predecessor state has made a mistake. We 283 // return the predecessor rather than cache out. 284 // 285 // TODO: We could potentially change the return to an assertion to alert 286 // clients to their mistake, but several checkers (including 287 // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation) 288 // rely upon the defensive behavior and would need to be updated. 289 if (!State || (State == Pred->getState() && !Tag && !MarkAsSink)) 290 return Pred; 291 292 Changed = true; 293 const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); 294 if (!P) 295 P = Pred; 296 297 ExplodedNode *node; 298 if (MarkAsSink) 299 node = NB.generateSink(LocalLoc, State, P); 300 else 301 node = NB.generateNode(LocalLoc, State, P); 302 return node; 303 } 304 }; 305 306 } // end GR namespace 307 308 } // end clang namespace 309 310 #endif 311