xref: /llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h (revision 752e10379c2ffb4f6eebf490f1fab7eb769dfbf6)
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