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