|
|
|||
File indexing completed on 2026-05-10 08:37:07
0001 //== CheckerContext.h - Context info for path-sensitive checkers--*- C++ -*--=// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 // 0009 // This file defines CheckerContext that provides contextual info for 0010 // path-sensitive checkers. 0011 // 0012 //===----------------------------------------------------------------------===// 0013 0014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H 0015 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H 0016 0017 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 0018 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 0019 #include <optional> 0020 0021 namespace clang { 0022 namespace ento { 0023 0024 class CheckerContext { 0025 ExprEngine &Eng; 0026 /// The current exploded(symbolic execution) graph node. 0027 ExplodedNode *Pred; 0028 /// The flag is true if the (state of the execution) has been modified 0029 /// by the checker using this context. For example, a new transition has been 0030 /// added or a bug report issued. 0031 bool Changed; 0032 /// The tagged location, which is used to generate all new nodes. 0033 const ProgramPoint Location; 0034 NodeBuilder &NB; 0035 0036 public: 0037 /// If we are post visiting a call, this flag will be set if the 0038 /// call was inlined. In all other cases it will be false. 0039 const bool wasInlined; 0040 0041 CheckerContext(NodeBuilder &builder, 0042 ExprEngine &eng, 0043 ExplodedNode *pred, 0044 const ProgramPoint &loc, 0045 bool wasInlined = false) 0046 : Eng(eng), 0047 Pred(pred), 0048 Changed(false), 0049 Location(loc), 0050 NB(builder), 0051 wasInlined(wasInlined) { 0052 assert(Pred->getState() && 0053 "We should not call the checkers on an empty state."); 0054 } 0055 0056 AnalysisManager &getAnalysisManager() { 0057 return Eng.getAnalysisManager(); 0058 } 0059 0060 ConstraintManager &getConstraintManager() { 0061 return Eng.getConstraintManager(); 0062 } 0063 0064 StoreManager &getStoreManager() { 0065 return Eng.getStoreManager(); 0066 } 0067 0068 /// Returns the previous node in the exploded graph, which includes 0069 /// the state of the program before the checker ran. Note, checkers should 0070 /// not retain the node in their state since the nodes might get invalidated. 0071 ExplodedNode *getPredecessor() { return Pred; } 0072 const ProgramPoint getLocation() const { return Location; } 0073 const ProgramStateRef &getState() const { return Pred->getState(); } 0074 0075 /// Check if the checker changed the state of the execution; ex: added 0076 /// a new transition or a bug report. 0077 bool isDifferent() { return Changed; } 0078 0079 /// Returns the number of times the current block has been visited 0080 /// along the analyzed path. 0081 unsigned blockCount() const { 0082 return NB.getContext().blockCount(); 0083 } 0084 0085 ASTContext &getASTContext() { 0086 return Eng.getContext(); 0087 } 0088 0089 const ASTContext &getASTContext() const { return Eng.getContext(); } 0090 0091 const LangOptions &getLangOpts() const { 0092 return Eng.getContext().getLangOpts(); 0093 } 0094 0095 const LocationContext *getLocationContext() const { 0096 return Pred->getLocationContext(); 0097 } 0098 0099 const StackFrameContext *getStackFrame() const { 0100 return Pred->getStackFrame(); 0101 } 0102 0103 /// Return true if the current LocationContext has no caller context. 0104 bool inTopFrame() const { return getLocationContext()->inTopFrame(); } 0105 0106 BugReporter &getBugReporter() { 0107 return Eng.getBugReporter(); 0108 } 0109 0110 const SourceManager &getSourceManager() { 0111 return getBugReporter().getSourceManager(); 0112 } 0113 0114 Preprocessor &getPreprocessor() { return getBugReporter().getPreprocessor(); } 0115 0116 SValBuilder &getSValBuilder() { 0117 return Eng.getSValBuilder(); 0118 } 0119 0120 SymbolManager &getSymbolManager() { 0121 return getSValBuilder().getSymbolManager(); 0122 } 0123 0124 ProgramStateManager &getStateManager() { 0125 return Eng.getStateManager(); 0126 } 0127 0128 AnalysisDeclContext *getCurrentAnalysisDeclContext() const { 0129 return Pred->getLocationContext()->getAnalysisDeclContext(); 0130 } 0131 0132 /// Get the blockID. 0133 unsigned getBlockID() const { 0134 return NB.getContext().getBlock()->getBlockID(); 0135 } 0136 0137 /// If the given node corresponds to a PostStore program point, 0138 /// retrieve the location region as it was uttered in the code. 0139 /// 0140 /// This utility can be useful for generating extensive diagnostics, for 0141 /// example, for finding variables that the given symbol was assigned to. 0142 static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) { 0143 ProgramPoint L = N->getLocation(); 0144 if (std::optional<PostStore> PSL = L.getAs<PostStore>()) 0145 return reinterpret_cast<const MemRegion*>(PSL->getLocationValue()); 0146 return nullptr; 0147 } 0148 0149 /// Get the value of arbitrary expressions at this point in the path. 0150 SVal getSVal(const Stmt *S) const { 0151 return Pred->getSVal(S); 0152 } 0153 0154 /// Returns true if the value of \p E is greater than or equal to \p 0155 /// Val under unsigned comparison 0156 bool isGreaterOrEqual(const Expr *E, unsigned long long Val); 0157 0158 /// Returns true if the value of \p E is negative. 0159 bool isNegative(const Expr *E); 0160 0161 /// Generates a new transition in the program state graph 0162 /// (ExplodedGraph). Uses the default CheckerContext predecessor node. 0163 /// 0164 /// @param State The state of the generated node. If not specified, the state 0165 /// will not be changed, but the new node will have the checker's tag. 0166 /// @param Tag The tag is used to uniquely identify the creation site. If no 0167 /// tag is specified, a default tag, unique to the given checker, 0168 /// will be used. Tags are used to prevent states generated at 0169 /// different sites from caching out. 0170 ExplodedNode *addTransition(ProgramStateRef State = nullptr, 0171 const ProgramPointTag *Tag = nullptr) { 0172 return addTransitionImpl(State ? State : getState(), false, nullptr, Tag); 0173 } 0174 0175 /// Generates a new transition with the given predecessor. 0176 /// Allows checkers to generate a chain of nodes. 0177 /// 0178 /// @param State The state of the generated node. 0179 /// @param Pred The transition will be generated from the specified Pred node 0180 /// to the newly generated node. 0181 /// @param Tag The tag to uniquely identify the creation site. 0182 ExplodedNode *addTransition(ProgramStateRef State, ExplodedNode *Pred, 0183 const ProgramPointTag *Tag = nullptr) { 0184 return addTransitionImpl(State, false, Pred, Tag); 0185 } 0186 0187 /// Generate a sink node. Generating a sink stops exploration of the 0188 /// given path. To create a sink node for the purpose of reporting an error, 0189 /// checkers should use generateErrorNode() instead. 0190 ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred, 0191 const ProgramPointTag *Tag = nullptr) { 0192 return addTransitionImpl(State ? State : getState(), true, Pred, Tag); 0193 } 0194 0195 /// Add a sink node to the current path of execution, halting analysis. 0196 void addSink(ProgramStateRef State = nullptr, 0197 const ProgramPointTag *Tag = nullptr) { 0198 if (!State) 0199 State = getState(); 0200 addTransition(State, generateSink(State, getPredecessor())); 0201 } 0202 0203 /// Generate a transition to a node that will be used to report 0204 /// an error. This node will be a sink. That is, it will stop exploration of 0205 /// the given path. 0206 /// 0207 /// @param State The state of the generated node. 0208 /// @param Tag The tag to uniquely identify the creation site. If null, 0209 /// the default tag for the checker will be used. 0210 ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr, 0211 const ProgramPointTag *Tag = nullptr) { 0212 return generateSink(State, Pred, 0213 (Tag ? Tag : Location.getTag())); 0214 } 0215 0216 /// Generate a transition to a node that will be used to report 0217 /// an error. This node will be a sink. That is, it will stop exploration of 0218 /// the given path. 0219 /// 0220 /// @param State The state of the generated node. 0221 /// @param Pred The transition will be generated from the specified Pred node 0222 /// to the newly generated node. 0223 /// @param Tag The tag to uniquely identify the creation site. If null, 0224 /// the default tag for the checker will be used. 0225 ExplodedNode *generateErrorNode(ProgramStateRef State, 0226 ExplodedNode *Pred, 0227 const ProgramPointTag *Tag = nullptr) { 0228 return generateSink(State, Pred, 0229 (Tag ? Tag : Location.getTag())); 0230 } 0231 0232 /// Generate a transition to a node that will be used to report 0233 /// an error. This node will not be a sink. That is, exploration will 0234 /// continue along this path. 0235 /// 0236 /// @param State The state of the generated node. 0237 /// @param Tag The tag to uniquely identify the creation site. If null, 0238 /// the default tag for the checker will be used. 0239 ExplodedNode * 0240 generateNonFatalErrorNode(ProgramStateRef State = nullptr, 0241 const ProgramPointTag *Tag = nullptr) { 0242 return addTransition(State, (Tag ? Tag : Location.getTag())); 0243 } 0244 0245 /// Generate a transition to a node that will be used to report 0246 /// an error. This node will not be a sink. That is, exploration will 0247 /// continue along this path. 0248 /// 0249 /// @param State The state of the generated node. 0250 /// @param Pred The transition will be generated from the specified Pred node 0251 /// to the newly generated node. 0252 /// @param Tag The tag to uniquely identify the creation site. If null, 0253 /// the default tag for the checker will be used. 0254 ExplodedNode * 0255 generateNonFatalErrorNode(ProgramStateRef State, 0256 ExplodedNode *Pred, 0257 const ProgramPointTag *Tag = nullptr) { 0258 return addTransition(State, Pred, (Tag ? Tag : Location.getTag())); 0259 } 0260 0261 /// Emit the diagnostics report. 0262 void emitReport(std::unique_ptr<BugReport> R) { 0263 Changed = true; 0264 Eng.getBugReporter().emitReport(std::move(R)); 0265 } 0266 0267 /// Produce a program point tag that displays an additional path note 0268 /// to the user. This is a lightweight alternative to the 0269 /// BugReporterVisitor mechanism: instead of visiting the bug report 0270 /// node-by-node to restore the sequence of events that led to discovering 0271 /// a bug, you can add notes as you add your transitions. 0272 /// 0273 /// @param Cb Callback with 'BugReporterContext &, BugReport &' parameters. 0274 /// @param IsPrunable Whether the note is prunable. It allows BugReporter 0275 /// to omit the note from the report if it would make the displayed 0276 /// bug path significantly shorter. 0277 LLVM_ATTRIBUTE_RETURNS_NONNULL 0278 const NoteTag *getNoteTag(NoteTag::Callback &&Cb, bool IsPrunable = false) { 0279 return Eng.getDataTags().make<NoteTag>(std::move(Cb), IsPrunable); 0280 } 0281 0282 /// A shorthand version of getNoteTag that doesn't require you to accept 0283 /// the 'BugReporterContext' argument when you don't need it. 0284 /// 0285 /// @param Cb Callback only with 'BugReport &' parameter. 0286 /// @param IsPrunable Whether the note is prunable. It allows BugReporter 0287 /// to omit the note from the report if it would make the displayed 0288 /// bug path significantly shorter. 0289 const NoteTag 0290 *getNoteTag(std::function<std::string(PathSensitiveBugReport &)> &&Cb, 0291 bool IsPrunable = false) { 0292 return getNoteTag( 0293 [Cb](BugReporterContext &, 0294 PathSensitiveBugReport &BR) { return Cb(BR); }, 0295 IsPrunable); 0296 } 0297 0298 /// A shorthand version of getNoteTag that doesn't require you to accept 0299 /// the arguments when you don't need it. 0300 /// 0301 /// @param Cb Callback without parameters. 0302 /// @param IsPrunable Whether the note is prunable. It allows BugReporter 0303 /// to omit the note from the report if it would make the displayed 0304 /// bug path significantly shorter. 0305 const NoteTag *getNoteTag(std::function<std::string()> &&Cb, 0306 bool IsPrunable = false) { 0307 return getNoteTag([Cb](BugReporterContext &, 0308 PathSensitiveBugReport &) { return Cb(); }, 0309 IsPrunable); 0310 } 0311 0312 /// A shorthand version of getNoteTag that accepts a plain note. 0313 /// 0314 /// @param Note The note. 0315 /// @param IsPrunable Whether the note is prunable. It allows BugReporter 0316 /// to omit the note from the report if it would make the displayed 0317 /// bug path significantly shorter. 0318 const NoteTag *getNoteTag(StringRef Note, bool IsPrunable = false) { 0319 return getNoteTag( 0320 [Note = std::string(Note)](BugReporterContext &, 0321 PathSensitiveBugReport &) { return Note; }, 0322 IsPrunable); 0323 } 0324 0325 /// A shorthand version of getNoteTag that accepts a lambda with stream for 0326 /// note. 0327 /// 0328 /// @param Cb Callback with 'BugReport &' and 'llvm::raw_ostream &'. 0329 /// @param IsPrunable Whether the note is prunable. It allows BugReporter 0330 /// to omit the note from the report if it would make the displayed 0331 /// bug path significantly shorter. 0332 const NoteTag *getNoteTag( 0333 std::function<void(PathSensitiveBugReport &BR, llvm::raw_ostream &OS)> &&Cb, 0334 bool IsPrunable = false) { 0335 return getNoteTag( 0336 [Cb](PathSensitiveBugReport &BR) -> std::string { 0337 llvm::SmallString<128> Str; 0338 llvm::raw_svector_ostream OS(Str); 0339 Cb(BR, OS); 0340 return std::string(OS.str()); 0341 }, 0342 IsPrunable); 0343 } 0344 0345 /// Returns the word that should be used to refer to the declaration 0346 /// in the report. 0347 StringRef getDeclDescription(const Decl *D); 0348 0349 /// Get the declaration of the called function (path-sensitive). 0350 const FunctionDecl *getCalleeDecl(const CallExpr *CE) const; 0351 0352 /// Get the name of the called function (path-sensitive). 0353 StringRef getCalleeName(const FunctionDecl *FunDecl) const; 0354 0355 /// Get the identifier of the called function (path-sensitive). 0356 const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const { 0357 const FunctionDecl *FunDecl = getCalleeDecl(CE); 0358 if (FunDecl) 0359 return FunDecl->getIdentifier(); 0360 else 0361 return nullptr; 0362 } 0363 0364 /// Get the name of the called function (path-sensitive). 0365 StringRef getCalleeName(const CallExpr *CE) const { 0366 const FunctionDecl *FunDecl = getCalleeDecl(CE); 0367 return getCalleeName(FunDecl); 0368 } 0369 0370 /// Returns true if the given function is an externally-visible function in 0371 /// the top-level namespace, such as \c malloc. 0372 /// 0373 /// If a name is provided, the function must additionally match the given 0374 /// name. 0375 /// 0376 /// Note that this also accepts functions from the \c std namespace (because 0377 /// headers like <cstdlib> declare them there) and does not check if the 0378 /// function is declared as 'extern "C"' or if it uses C++ name mangling. 0379 static bool isCLibraryFunction(const FunctionDecl *FD, 0380 StringRef Name = StringRef()); 0381 0382 /// In builds that use source hardening (-D_FORTIFY_SOURCE), many standard 0383 /// functions are implemented as macros that expand to calls of hardened 0384 /// functions that take additional arguments compared to the "usual" 0385 /// variant and perform additional input validation. For example, a `memcpy` 0386 /// call may expand to `__memcpy_chk()` or `__builtin___memcpy_chk()`. 0387 /// 0388 /// This method returns true if `FD` declares a fortified variant of the 0389 /// standard library function `Name`. 0390 /// 0391 /// NOTE: This method relies on heuristics; extend it if you need to handle a 0392 /// hardened variant that's not yet covered by it. 0393 static bool isHardenedVariantOf(const FunctionDecl *FD, StringRef Name); 0394 0395 /// Depending on wither the location corresponds to a macro, return 0396 /// either the macro name or the token spelling. 0397 /// 0398 /// This could be useful when checkers' logic depends on whether a function 0399 /// is called with a given macro argument. For example: 0400 /// s = socket(AF_INET,..) 0401 /// If AF_INET is a macro, the result should be treated as a source of taint. 0402 /// 0403 /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName(). 0404 StringRef getMacroNameOrSpelling(SourceLocation &Loc); 0405 0406 private: 0407 ExplodedNode *addTransitionImpl(ProgramStateRef State, 0408 bool MarkAsSink, 0409 ExplodedNode *P = nullptr, 0410 const ProgramPointTag *Tag = nullptr) { 0411 // The analyzer may stop exploring if it sees a state it has previously 0412 // visited ("cache out"). The early return here is a defensive check to 0413 // prevent accidental caching out by checker API clients. Unless there is a 0414 // tag or the client checker has requested that the generated node be 0415 // marked as a sink, we assume that a client requesting a transition to a 0416 // state that is the same as the predecessor state has made a mistake. We 0417 // return the predecessor rather than cache out. 0418 // 0419 // TODO: We could potentially change the return to an assertion to alert 0420 // clients to their mistake, but several checkers (including 0421 // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation) 0422 // rely upon the defensive behavior and would need to be updated. 0423 if (!State || (State == Pred->getState() && !Tag && !MarkAsSink)) 0424 return Pred; 0425 0426 Changed = true; 0427 const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location); 0428 if (!P) 0429 P = Pred; 0430 0431 ExplodedNode *node; 0432 if (MarkAsSink) 0433 node = NB.generateSink(LocalLoc, State, P); 0434 else 0435 node = NB.generateNode(LocalLoc, State, P); 0436 return node; 0437 } 0438 }; 0439 0440 } // end GR namespace 0441 0442 } // end clang namespace 0443 0444 #endif
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|