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