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