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) 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 getASTContext()88 const ASTContext &getASTContext() const { return Eng.getContext(); } 89 getLangOpts()90 const LangOptions &getLangOpts() const { 91 return Eng.getContext().getLangOpts(); 92 } 93 getLocationContext()94 const LocationContext *getLocationContext() const { 95 return Pred->getLocationContext(); 96 } 97 getStackFrame()98 const StackFrameContext *getStackFrame() const { 99 return Pred->getStackFrame(); 100 } 101 102 /// Return true if the current LocationContext has no caller context. inTopFrame()103 bool inTopFrame() const { return getLocationContext()->inTopFrame(); } 104 getBugReporter()105 BugReporter &getBugReporter() { 106 return Eng.getBugReporter(); 107 } 108 getSourceManager()109 const SourceManager &getSourceManager() { 110 return getBugReporter().getSourceManager(); 111 } 112 getPreprocessor()113 Preprocessor &getPreprocessor() { return getBugReporter().getPreprocessor(); } 114 getSValBuilder()115 SValBuilder &getSValBuilder() { 116 return Eng.getSValBuilder(); 117 } 118 getSymbolManager()119 SymbolManager &getSymbolManager() { 120 return getSValBuilder().getSymbolManager(); 121 } 122 getStateManager()123 ProgramStateManager &getStateManager() { 124 return Eng.getStateManager(); 125 } 126 getCurrentAnalysisDeclContext()127 AnalysisDeclContext *getCurrentAnalysisDeclContext() const { 128 return Pred->getLocationContext()->getAnalysisDeclContext(); 129 } 130 131 /// Get the blockID. getBlockID()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. getLocationRegionIfPostStore(const ExplodedNode * N)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. getSVal(const Stmt * S)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. emitReport(std::unique_ptr<BugReport> R)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 = std::string(Note)](BugReporterContext &, 320 PathSensitiveBugReport &) { return 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). getCalleeIdentifier(const CallExpr * CE)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). getCalleeName(const CallExpr * CE)364 StringRef getCalleeName(const CallExpr *CE) const { 365 const FunctionDecl *FunDecl = getCalleeDecl(CE); 366 return getCalleeName(FunDecl); 367 } 368 369 /// Returns true if the given function is an externally-visible function in 370 /// the 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 also accepts functions from the \c std namespace (because 376 /// headers like <cstdlib> declare them there) and does not check if the 377 /// function is declared as 'extern "C"' or if it uses C++ name mangling. 378 static bool isCLibraryFunction(const FunctionDecl *FD, 379 StringRef Name = StringRef()); 380 381 /// In builds that use source hardening (-D_FORTIFY_SOURCE), many standard 382 /// functions are implemented as macros that expand to calls of hardened 383 /// functions that take additional arguments compared to the "usual" 384 /// variant and perform additional input validation. For example, a `memcpy` 385 /// call may expand to `__memcpy_chk()` or `__builtin___memcpy_chk()`. 386 /// 387 /// This method returns true if `FD` declares a fortified variant of the 388 /// standard library function `Name`. 389 /// 390 /// NOTE: This method relies on heuristics; extend it if you need to handle a 391 /// hardened variant that's not yet covered by it. 392 static bool isHardenedVariantOf(const FunctionDecl *FD, StringRef Name); 393 394 /// Depending on wither the location corresponds to a macro, return 395 /// either the macro name or the token spelling. 396 /// 397 /// This could be useful when checkers' logic depends on whether a function 398 /// is called with a given macro argument. For example: 399 /// s = socket(AF_INET,..) 400 /// If AF_INET is a macro, the result should be treated as a source of taint. 401 /// 402 /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName(). 403 StringRef getMacroNameOrSpelling(SourceLocation &Loc); 404 405 private: 406 ExplodedNode *addTransitionImpl(ProgramStateRef State, 407 bool MarkAsSink, 408 ExplodedNode *P = nullptr, 409 const ProgramPointTag *Tag = nullptr) { 410 // The analyzer may stop exploring if it sees a state it has previously 411 // visited ("cache out"). The early return here is a defensive check to 412 // prevent accidental caching out by checker API clients. Unless there is a 413 // tag or the client checker has requested that the generated node be 414 // marked as a sink, we assume that a client requesting a transition to a 415 // state that is the same as the predecessor state has made a mistake. We 416 // return the predecessor rather than cache out. 417 // 418 // TODO: We could potentially change the return to an assertion to alert 419 // clients to their mistake, but several checkers (including 420 // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation) 421 // rely upon the defensive behavior and would need to be updated. 422 if (!State || (State == Pred->getState() && !Tag && !MarkAsSink)) 423 return Pred; 424 425 Changed = true; 426 const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); 427 if (!P) 428 P = Pred; 429 430 ExplodedNode *node; 431 if (MarkAsSink) 432 node = NB.generateSink(LocalLoc, State, P); 433 else 434 node = NB.generateNode(LocalLoc, State, P); 435 return node; 436 } 437 }; 438 439 } // end GR namespace 440 441 } // end clang namespace 442 443 #endif 444