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 ? State : getState(), MarkAsSink: false, P: 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, MarkAsSink: false, P: 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 ? State : getState(), MarkAsSink: true, P: 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, Pred: generateSink(State, Pred: 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 ? 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 ? 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 ? 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 ? 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(R: 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>(ConstructorArgs: std::move(Cb), ConstructorArgs&: 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: [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: [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 | Cb: [Note = std::string(Note)](BugReporterContext &, |
320 | PathSensitiveBugReport &) { return 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: [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 given function is an externally-visible function in |
370 | /// the 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 also accepts functions from the \c std namespace (because |
376 | /// headers like <cstdlib> declare them there) and does not check if the |
377 | /// function is declared as 'extern "C"' or if it uses C++ name mangling. |
378 | static bool isCLibraryFunction(const FunctionDecl *FD, |
379 | StringRef Name = StringRef()); |
380 | |
381 | /// In builds that use source hardening (-D_FORTIFY_SOURCE), many standard |
382 | /// functions are implemented as macros that expand to calls of hardened |
383 | /// functions that take additional arguments compared to the "usual" |
384 | /// variant and perform additional input validation. For example, a `memcpy` |
385 | /// call may expand to `__memcpy_chk()` or `__builtin___memcpy_chk()`. |
386 | /// |
387 | /// This method returns true if `FD` declares a fortified variant of the |
388 | /// standard library function `Name`. |
389 | /// |
390 | /// NOTE: This method relies on heuristics; extend it if you need to handle a |
391 | /// hardened variant that's not yet covered by it. |
392 | static bool isHardenedVariantOf(const FunctionDecl *FD, StringRef Name); |
393 | |
394 | /// Depending on wither the location corresponds to a macro, return |
395 | /// either the macro name or the token spelling. |
396 | /// |
397 | /// This could be useful when checkers' logic depends on whether a function |
398 | /// is called with a given macro argument. For example: |
399 | /// s = socket(AF_INET,..) |
400 | /// If AF_INET is a macro, the result should be treated as a source of taint. |
401 | /// |
402 | /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName(). |
403 | StringRef getMacroNameOrSpelling(SourceLocation &Loc); |
404 | |
405 | private: |
406 | ExplodedNode *addTransitionImpl(ProgramStateRef State, |
407 | bool MarkAsSink, |
408 | ExplodedNode *P = nullptr, |
409 | const ProgramPointTag *Tag = nullptr) { |
410 | // The analyzer may stop exploring if it sees a state it has previously |
411 | // visited ("cache out"). The early return here is a defensive check to |
412 | // prevent accidental caching out by checker API clients. Unless there is a |
413 | // tag or the client checker has requested that the generated node be |
414 | // marked as a sink, we assume that a client requesting a transition to a |
415 | // state that is the same as the predecessor state has made a mistake. We |
416 | // return the predecessor rather than cache out. |
417 | // |
418 | // TODO: We could potentially change the return to an assertion to alert |
419 | // clients to their mistake, but several checkers (including |
420 | // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation) |
421 | // rely upon the defensive behavior and would need to be updated. |
422 | if (!State || (State == Pred->getState() && !Tag && !MarkAsSink)) |
423 | return Pred; |
424 | |
425 | Changed = true; |
426 | const ProgramPoint &LocalLoc = (Tag ? Location.withTag(tag: Tag) : Location); |
427 | if (!P) |
428 | P = Pred; |
429 | |
430 | ExplodedNode *node; |
431 | if (MarkAsSink) |
432 | node = NB.generateSink(PP: LocalLoc, State, Pred: P); |
433 | else |
434 | node = NB.generateNode(PP: LocalLoc, State, Pred: P); |
435 | return node; |
436 | } |
437 | }; |
438 | |
439 | } // end GR namespace |
440 | |
441 | } // end clang namespace |
442 | |
443 | #endif |
444 | |