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