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 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.
76   bool isDifferent() { return Changed; }
77 
78   /// Returns the number of times the current block has been visited
79   /// along the analyzed path.
80   unsigned blockCount() const {
81     return NB.getContext().blockCount();
82   }
83 
84   ASTContext &getASTContext() {
85     return Eng.getContext();
86   }
87 
88   const ASTContext &getASTContext() const { return Eng.getContext(); }
89 
90   const LangOptions &getLangOpts() const {
91     return Eng.getContext().getLangOpts();
92   }
93 
94   const LocationContext *getLocationContext() const {
95     return Pred->getLocationContext();
96   }
97 
98   const StackFrameContext *getStackFrame() const {
99     return Pred->getStackFrame();
100   }
101 
102   /// Return true if the current LocationContext has no caller context.
103   bool inTopFrame() const { return getLocationContext()->inTopFrame();  }
104 
105   BugReporter &getBugReporter() {
106     return Eng.getBugReporter();
107   }
108 
109   const SourceManager &getSourceManager() {
110     return getBugReporter().getSourceManager();
111   }
112 
113   Preprocessor &getPreprocessor() { return getBugReporter().getPreprocessor(); }
114 
115   SValBuilder &getSValBuilder() {
116     return Eng.getSValBuilder();
117   }
118 
119   SymbolManager &getSymbolManager() {
120     return getSValBuilder().getSymbolManager();
121   }
122 
123   ProgramStateManager &getStateManager() {
124     return Eng.getStateManager();
125   }
126 
127   AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
128     return Pred->getLocationContext()->getAnalysisDeclContext();
129   }
130 
131   /// Get the blockID.
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.
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.
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.
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](BugReporterContext &,
320                PathSensitiveBugReport &) { return std::string(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).
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).
364   StringRef getCalleeName(const CallExpr *CE) const {
365     const FunctionDecl *FunDecl = getCalleeDecl(CE);
366     return getCalleeName(FunDecl);
367   }
368 
369   /// Returns true if the callee is an externally-visible function in the
370   /// 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 deliberately excludes C++ library functions in the \c std
376   /// namespace, but will include C library functions accessed through the
377   /// \c std namespace. This also does not check if the function is declared
378   /// as 'extern "C"', or if it uses C++ name mangling.
379   static bool isCLibraryFunction(const FunctionDecl *FD,
380                                  StringRef Name = StringRef());
381 
382   /// Depending on wither the location corresponds to a macro, return
383   /// either the macro name or the token spelling.
384   ///
385   /// This could be useful when checkers' logic depends on whether a function
386   /// is called with a given macro argument. For example:
387   ///   s = socket(AF_INET,..)
388   /// If AF_INET is a macro, the result should be treated as a source of taint.
389   ///
390   /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName().
391   StringRef getMacroNameOrSpelling(SourceLocation &Loc);
392 
393 private:
394   ExplodedNode *addTransitionImpl(ProgramStateRef State,
395                                  bool MarkAsSink,
396                                  ExplodedNode *P = nullptr,
397                                  const ProgramPointTag *Tag = nullptr) {
398     // The analyzer may stop exploring if it sees a state it has previously
399     // visited ("cache out"). The early return here is a defensive check to
400     // prevent accidental caching out by checker API clients. Unless there is a
401     // tag or the client checker has requested that the generated node be
402     // marked as a sink, we assume that a client requesting a transition to a
403     // state that is the same as the predecessor state has made a mistake. We
404     // return the predecessor rather than cache out.
405     //
406     // TODO: We could potentially change the return to an assertion to alert
407     // clients to their mistake, but several checkers (including
408     // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation)
409     // rely upon the defensive behavior and would need to be updated.
410     if (!State || (State == Pred->getState() && !Tag && !MarkAsSink))
411       return Pred;
412 
413     Changed = true;
414     const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
415     if (!P)
416       P = Pred;
417 
418     ExplodedNode *node;
419     if (MarkAsSink)
420       node = NB.generateSink(LocalLoc, State, P);
421     else
422       node = NB.generateNode(LocalLoc, State, P);
423     return node;
424   }
425 };
426 
427 } // end GR namespace
428 
429 } // end clang namespace
430 
431 #endif
432