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