File: | tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp |
Warning: | line 100, column 29 Access to field 'CurrentState' results in a dereference of a null pointer (loaded from variable 'Req') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- MPIBugReporter.cpp - bug reporter -----------------------*- 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 | /// \file | |||
10 | /// This file defines prefabricated reports which are emitted in | |||
11 | /// case of MPI related bugs, detected by path-sensitive analysis. | |||
12 | /// | |||
13 | //===----------------------------------------------------------------------===// | |||
14 | ||||
15 | #include "MPIBugReporter.h" | |||
16 | #include "MPIChecker.h" | |||
17 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" | |||
18 | ||||
19 | namespace clang { | |||
20 | namespace ento { | |||
21 | namespace mpi { | |||
22 | ||||
23 | void MPIBugReporter::reportDoubleNonblocking( | |||
24 | const CallEvent &MPICallEvent, const ento::mpi::Request &Req, | |||
25 | const MemRegion *const RequestRegion, | |||
26 | const ExplodedNode *const ExplNode, | |||
27 | BugReporter &BReporter) const { | |||
28 | ||||
29 | std::string ErrorText; | |||
30 | ErrorText = "Double nonblocking on request " + | |||
31 | RequestRegion->getDescriptiveName() + ". "; | |||
32 | ||||
33 | auto Report = llvm::make_unique<BugReport>(*DoubleNonblockingBugType, | |||
34 | ErrorText, ExplNode); | |||
35 | ||||
36 | Report->addRange(MPICallEvent.getSourceRange()); | |||
37 | SourceRange Range = RequestRegion->sourceRange(); | |||
38 | ||||
39 | if (Range.isValid()) | |||
40 | Report->addRange(Range); | |||
41 | ||||
42 | Report->addVisitor(llvm::make_unique<RequestNodeVisitor>( | |||
43 | RequestRegion, "Request is previously used by nonblocking call here. ")); | |||
44 | Report->markInteresting(RequestRegion); | |||
45 | ||||
46 | BReporter.emitReport(std::move(Report)); | |||
47 | } | |||
48 | ||||
49 | void MPIBugReporter::reportMissingWait( | |||
50 | const ento::mpi::Request &Req, const MemRegion *const RequestRegion, | |||
51 | const ExplodedNode *const ExplNode, | |||
52 | BugReporter &BReporter) const { | |||
53 | std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() + | |||
54 | " has no matching wait. "}; | |||
55 | ||||
56 | auto Report = | |||
57 | llvm::make_unique<BugReport>(*MissingWaitBugType, ErrorText, ExplNode); | |||
58 | ||||
59 | SourceRange Range = RequestRegion->sourceRange(); | |||
60 | if (Range.isValid()) | |||
61 | Report->addRange(Range); | |||
62 | Report->addVisitor(llvm::make_unique<RequestNodeVisitor>( | |||
63 | RequestRegion, "Request is previously used by nonblocking call here. ")); | |||
64 | Report->markInteresting(RequestRegion); | |||
65 | ||||
66 | BReporter.emitReport(std::move(Report)); | |||
67 | } | |||
68 | ||||
69 | void MPIBugReporter::reportUnmatchedWait( | |||
70 | const CallEvent &CE, const clang::ento::MemRegion *const RequestRegion, | |||
71 | const ExplodedNode *const ExplNode, | |||
72 | BugReporter &BReporter) const { | |||
73 | std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() + | |||
74 | " has no matching nonblocking call. "}; | |||
75 | ||||
76 | auto Report = | |||
77 | llvm::make_unique<BugReport>(*UnmatchedWaitBugType, ErrorText, ExplNode); | |||
78 | ||||
79 | Report->addRange(CE.getSourceRange()); | |||
80 | SourceRange Range = RequestRegion->sourceRange(); | |||
81 | if (Range.isValid()) | |||
82 | Report->addRange(Range); | |||
83 | ||||
84 | BReporter.emitReport(std::move(Report)); | |||
85 | } | |||
86 | ||||
87 | std::shared_ptr<PathDiagnosticPiece> | |||
88 | MPIBugReporter::RequestNodeVisitor::VisitNode(const ExplodedNode *N, | |||
89 | BugReporterContext &BRC, | |||
90 | BugReport &BR) { | |||
91 | ||||
92 | if (IsNodeFound) | |||
| ||||
93 | return nullptr; | |||
94 | ||||
95 | const Request *const Req = N->getState()->get<RequestMap>(RequestRegion); | |||
96 | const Request *const PrevReq = | |||
97 | N->getFirstPred()->getState()->get<RequestMap>(RequestRegion); | |||
98 | ||||
99 | // Check if request was previously unused or in a different state. | |||
100 | if ((Req && !PrevReq) || (Req->CurrentState != PrevReq->CurrentState)) { | |||
| ||||
101 | IsNodeFound = true; | |||
102 | ||||
103 | ProgramPoint P = N->getFirstPred()->getLocation(); | |||
104 | PathDiagnosticLocation L = | |||
105 | PathDiagnosticLocation::create(P, BRC.getSourceManager()); | |||
106 | ||||
107 | return std::make_shared<PathDiagnosticEventPiece>(L, ErrorText); | |||
108 | } | |||
109 | ||||
110 | return nullptr; | |||
111 | } | |||
112 | ||||
113 | } // end of namespace: mpi | |||
114 | } // end of namespace: ento | |||
115 | } // end of namespace: clang |
1 | //== ProgramState.h - Path-sensitive "State" for tracking values -*- 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 the state of the program along the analysisa path. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H |
14 | #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H |
15 | |
16 | #include "clang/Basic/LLVM.h" |
17 | #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" |
18 | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h" |
19 | #include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h" |
20 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" |
21 | #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" |
22 | #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" |
23 | #include "llvm/ADT/FoldingSet.h" |
24 | #include "llvm/ADT/ImmutableMap.h" |
25 | #include "llvm/Support/Allocator.h" |
26 | #include <utility> |
27 | |
28 | namespace llvm { |
29 | class APSInt; |
30 | } |
31 | |
32 | namespace clang { |
33 | class ASTContext; |
34 | |
35 | namespace ento { |
36 | |
37 | class AnalysisManager; |
38 | class CallEvent; |
39 | class CallEventManager; |
40 | |
41 | typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)( |
42 | ProgramStateManager &, SubEngine *); |
43 | typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)( |
44 | ProgramStateManager &); |
45 | |
46 | //===----------------------------------------------------------------------===// |
47 | // ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState. |
48 | //===----------------------------------------------------------------------===// |
49 | |
50 | template <typename T> struct ProgramStatePartialTrait; |
51 | |
52 | template <typename T> struct ProgramStateTrait { |
53 | typedef typename T::data_type data_type; |
54 | static inline void *MakeVoidPtr(data_type D) { return (void*) D; } |
55 | static inline data_type MakeData(void *const* P) { |
56 | return P ? (data_type) *P : (data_type) 0; |
57 | } |
58 | }; |
59 | |
60 | /// \class ProgramState |
61 | /// ProgramState - This class encapsulates: |
62 | /// |
63 | /// 1. A mapping from expressions to values (Environment) |
64 | /// 2. A mapping from locations to values (Store) |
65 | /// 3. Constraints on symbolic values (GenericDataMap) |
66 | /// |
67 | /// Together these represent the "abstract state" of a program. |
68 | /// |
69 | /// ProgramState is intended to be used as a functional object; that is, |
70 | /// once it is created and made "persistent" in a FoldingSet, its |
71 | /// values will never change. |
72 | class ProgramState : public llvm::FoldingSetNode { |
73 | public: |
74 | typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; |
75 | typedef llvm::ImmutableMap<void*, void*> GenericDataMap; |
76 | |
77 | private: |
78 | void operator=(const ProgramState& R) = delete; |
79 | |
80 | friend class ProgramStateManager; |
81 | friend class ExplodedGraph; |
82 | friend class ExplodedNode; |
83 | |
84 | ProgramStateManager *stateMgr; |
85 | Environment Env; // Maps a Stmt to its current SVal. |
86 | Store store; // Maps a location to its current value. |
87 | GenericDataMap GDM; // Custom data stored by a client of this class. |
88 | unsigned refCount; |
89 | |
90 | /// makeWithStore - Return a ProgramState with the same values as the current |
91 | /// state with the exception of using the specified Store. |
92 | ProgramStateRef makeWithStore(const StoreRef &store) const; |
93 | |
94 | void setStore(const StoreRef &storeRef); |
95 | |
96 | public: |
97 | /// This ctor is used when creating the first ProgramState object. |
98 | ProgramState(ProgramStateManager *mgr, const Environment& env, |
99 | StoreRef st, GenericDataMap gdm); |
100 | |
101 | /// Copy ctor - We must explicitly define this or else the "Next" ptr |
102 | /// in FoldingSetNode will also get copied. |
103 | ProgramState(const ProgramState &RHS); |
104 | |
105 | ~ProgramState(); |
106 | |
107 | int64_t getID() const; |
108 | |
109 | /// Return the ProgramStateManager associated with this state. |
110 | ProgramStateManager &getStateManager() const { |
111 | return *stateMgr; |
112 | } |
113 | |
114 | AnalysisManager &getAnalysisManager() const; |
115 | |
116 | /// Return the ConstraintManager. |
117 | ConstraintManager &getConstraintManager() const; |
118 | |
119 | /// getEnvironment - Return the environment associated with this state. |
120 | /// The environment is the mapping from expressions to values. |
121 | const Environment& getEnvironment() const { return Env; } |
122 | |
123 | /// Return the store associated with this state. The store |
124 | /// is a mapping from locations to values. |
125 | Store getStore() const { return store; } |
126 | |
127 | |
128 | /// getGDM - Return the generic data map associated with this state. |
129 | GenericDataMap getGDM() const { return GDM; } |
130 | |
131 | void setGDM(GenericDataMap gdm) { GDM = gdm; } |
132 | |
133 | /// Profile - Profile the contents of a ProgramState object for use in a |
134 | /// FoldingSet. Two ProgramState objects are considered equal if they |
135 | /// have the same Environment, Store, and GenericDataMap. |
136 | static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) { |
137 | V->Env.Profile(ID); |
138 | ID.AddPointer(V->store); |
139 | V->GDM.Profile(ID); |
140 | } |
141 | |
142 | /// Profile - Used to profile the contents of this object for inclusion |
143 | /// in a FoldingSet. |
144 | void Profile(llvm::FoldingSetNodeID& ID) const { |
145 | Profile(ID, this); |
146 | } |
147 | |
148 | BasicValueFactory &getBasicVals() const; |
149 | SymbolManager &getSymbolManager() const; |
150 | |
151 | //==---------------------------------------------------------------------==// |
152 | // Constraints on values. |
153 | //==---------------------------------------------------------------------==// |
154 | // |
155 | // Each ProgramState records constraints on symbolic values. These constraints |
156 | // are managed using the ConstraintManager associated with a ProgramStateManager. |
157 | // As constraints gradually accrue on symbolic values, added constraints |
158 | // may conflict and indicate that a state is infeasible (as no real values |
159 | // could satisfy all the constraints). This is the principal mechanism |
160 | // for modeling path-sensitivity in ExprEngine/ProgramState. |
161 | // |
162 | // Various "assume" methods form the interface for adding constraints to |
163 | // symbolic values. A call to 'assume' indicates an assumption being placed |
164 | // on one or symbolic values. 'assume' methods take the following inputs: |
165 | // |
166 | // (1) A ProgramState object representing the current state. |
167 | // |
168 | // (2) The assumed constraint (which is specific to a given "assume" method). |
169 | // |
170 | // (3) A binary value "Assumption" that indicates whether the constraint is |
171 | // assumed to be true or false. |
172 | // |
173 | // The output of "assume*" is a new ProgramState object with the added constraints. |
174 | // If no new state is feasible, NULL is returned. |
175 | // |
176 | |
177 | /// Assumes that the value of \p cond is zero (if \p assumption is "false") |
178 | /// or non-zero (if \p assumption is "true"). |
179 | /// |
180 | /// This returns a new state with the added constraint on \p cond. |
181 | /// If no new state is feasible, NULL is returned. |
182 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef assume(DefinedOrUnknownSVal cond, |
183 | bool assumption) const; |
184 | |
185 | /// Assumes both "true" and "false" for \p cond, and returns both |
186 | /// corresponding states (respectively). |
187 | /// |
188 | /// This is more efficient than calling assume() twice. Note that one (but not |
189 | /// both) of the returned states may be NULL. |
190 | LLVM_NODISCARD[[clang::warn_unused_result]] std::pair<ProgramStateRef, ProgramStateRef> |
191 | assume(DefinedOrUnknownSVal cond) const; |
192 | |
193 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
194 | assumeInBound(DefinedOrUnknownSVal idx, DefinedOrUnknownSVal upperBound, |
195 | bool assumption, QualType IndexType = QualType()) const; |
196 | |
197 | /// Assumes that the value of \p Val is bounded with [\p From; \p To] |
198 | /// (if \p assumption is "true") or it is fully out of this range |
199 | /// (if \p assumption is "false"). |
200 | /// |
201 | /// This returns a new state with the added constraint on \p cond. |
202 | /// If no new state is feasible, NULL is returned. |
203 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef assumeInclusiveRange(DefinedOrUnknownSVal Val, |
204 | const llvm::APSInt &From, |
205 | const llvm::APSInt &To, |
206 | bool assumption) const; |
207 | |
208 | /// Assumes given range both "true" and "false" for \p Val, and returns both |
209 | /// corresponding states (respectively). |
210 | /// |
211 | /// This is more efficient than calling assume() twice. Note that one (but not |
212 | /// both) of the returned states may be NULL. |
213 | LLVM_NODISCARD[[clang::warn_unused_result]] std::pair<ProgramStateRef, ProgramStateRef> |
214 | assumeInclusiveRange(DefinedOrUnknownSVal Val, const llvm::APSInt &From, |
215 | const llvm::APSInt &To) const; |
216 | |
217 | /// Check if the given SVal is not constrained to zero and is not |
218 | /// a zero constant. |
219 | ConditionTruthVal isNonNull(SVal V) const; |
220 | |
221 | /// Check if the given SVal is constrained to zero or is a zero |
222 | /// constant. |
223 | ConditionTruthVal isNull(SVal V) const; |
224 | |
225 | /// \return Whether values \p Lhs and \p Rhs are equal. |
226 | ConditionTruthVal areEqual(SVal Lhs, SVal Rhs) const; |
227 | |
228 | /// Utility method for getting regions. |
229 | const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; |
230 | |
231 | //==---------------------------------------------------------------------==// |
232 | // Binding and retrieving values to/from the environment and symbolic store. |
233 | //==---------------------------------------------------------------------==// |
234 | |
235 | /// Create a new state by binding the value 'V' to the statement 'S' in the |
236 | /// state's environment. |
237 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef BindExpr(const Stmt *S, |
238 | const LocationContext *LCtx, SVal V, |
239 | bool Invalidate = true) const; |
240 | |
241 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef bindLoc(Loc location, SVal V, |
242 | const LocationContext *LCtx, |
243 | bool notifyChanges = true) const; |
244 | |
245 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef bindLoc(SVal location, SVal V, |
246 | const LocationContext *LCtx) const; |
247 | |
248 | /// Initializes the region of memory represented by \p loc with an initial |
249 | /// value. Once initialized, all values loaded from any sub-regions of that |
250 | /// region will be equal to \p V, unless overwritten later by the program. |
251 | /// This method should not be used on regions that are already initialized. |
252 | /// If you need to indicate that memory contents have suddenly become unknown |
253 | /// within a certain region of memory, consider invalidateRegions(). |
254 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
255 | bindDefaultInitial(SVal loc, SVal V, const LocationContext *LCtx) const; |
256 | |
257 | /// Performs C++ zero-initialization procedure on the region of memory |
258 | /// represented by \p loc. |
259 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
260 | bindDefaultZero(SVal loc, const LocationContext *LCtx) const; |
261 | |
262 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef killBinding(Loc LV) const; |
263 | |
264 | /// Returns the state with bindings for the given regions |
265 | /// cleared from the store. |
266 | /// |
267 | /// Optionally invalidates global regions as well. |
268 | /// |
269 | /// \param Regions the set of regions to be invalidated. |
270 | /// \param E the expression that caused the invalidation. |
271 | /// \param BlockCount The number of times the current basic block has been |
272 | // visited. |
273 | /// \param CausesPointerEscape the flag is set to true when |
274 | /// the invalidation entails escape of a symbol (representing a |
275 | /// pointer). For example, due to it being passed as an argument in a |
276 | /// call. |
277 | /// \param IS the set of invalidated symbols. |
278 | /// \param Call if non-null, the invalidated regions represent parameters to |
279 | /// the call and should be considered directly invalidated. |
280 | /// \param ITraits information about special handling for a particular |
281 | /// region/symbol. |
282 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
283 | invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E, |
284 | unsigned BlockCount, const LocationContext *LCtx, |
285 | bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, |
286 | const CallEvent *Call = nullptr, |
287 | RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; |
288 | |
289 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
290 | invalidateRegions(ArrayRef<SVal> Regions, const Expr *E, |
291 | unsigned BlockCount, const LocationContext *LCtx, |
292 | bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, |
293 | const CallEvent *Call = nullptr, |
294 | RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; |
295 | |
296 | /// enterStackFrame - Returns the state for entry to the given stack frame, |
297 | /// preserving the current state. |
298 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef enterStackFrame( |
299 | const CallEvent &Call, const StackFrameContext *CalleeCtx) const; |
300 | |
301 | /// Get the lvalue for a base class object reference. |
302 | Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const; |
303 | |
304 | /// Get the lvalue for a base class object reference. |
305 | Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super, |
306 | bool IsVirtual) const; |
307 | |
308 | /// Get the lvalue for a variable reference. |
309 | Loc getLValue(const VarDecl *D, const LocationContext *LC) const; |
310 | |
311 | Loc getLValue(const CompoundLiteralExpr *literal, |
312 | const LocationContext *LC) const; |
313 | |
314 | /// Get the lvalue for an ivar reference. |
315 | SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; |
316 | |
317 | /// Get the lvalue for a field reference. |
318 | SVal getLValue(const FieldDecl *decl, SVal Base) const; |
319 | |
320 | /// Get the lvalue for an indirect field reference. |
321 | SVal getLValue(const IndirectFieldDecl *decl, SVal Base) const; |
322 | |
323 | /// Get the lvalue for an array index. |
324 | SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const; |
325 | |
326 | /// Returns the SVal bound to the statement 'S' in the state's environment. |
327 | SVal getSVal(const Stmt *S, const LocationContext *LCtx) const; |
328 | |
329 | SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const; |
330 | |
331 | /// Return the value bound to the specified location. |
332 | /// Returns UnknownVal() if none found. |
333 | SVal getSVal(Loc LV, QualType T = QualType()) const; |
334 | |
335 | /// Returns the "raw" SVal bound to LV before any value simplfication. |
336 | SVal getRawSVal(Loc LV, QualType T= QualType()) const; |
337 | |
338 | /// Return the value bound to the specified location. |
339 | /// Returns UnknownVal() if none found. |
340 | SVal getSVal(const MemRegion* R, QualType T = QualType()) const; |
341 | |
342 | /// Return the value bound to the specified location, assuming |
343 | /// that the value is a scalar integer or an enumeration or a pointer. |
344 | /// Returns UnknownVal() if none found or the region is not known to hold |
345 | /// a value of such type. |
346 | SVal getSValAsScalarOrLoc(const MemRegion *R) const; |
347 | |
348 | using region_iterator = const MemRegion **; |
349 | |
350 | /// Visits the symbols reachable from the given SVal using the provided |
351 | /// SymbolVisitor. |
352 | /// |
353 | /// This is a convenience API. Consider using ScanReachableSymbols class |
354 | /// directly when making multiple scans on the same state with the same |
355 | /// visitor to avoid repeated initialization cost. |
356 | /// \sa ScanReachableSymbols |
357 | bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; |
358 | |
359 | /// Visits the symbols reachable from the regions in the given |
360 | /// MemRegions range using the provided SymbolVisitor. |
361 | bool scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable, |
362 | SymbolVisitor &visitor) const; |
363 | |
364 | template <typename CB> CB scanReachableSymbols(SVal val) const; |
365 | template <typename CB> CB |
366 | scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable) const; |
367 | |
368 | //==---------------------------------------------------------------------==// |
369 | // Accessing the Generic Data Map (GDM). |
370 | //==---------------------------------------------------------------------==// |
371 | |
372 | void *const* FindGDM(void *K) const; |
373 | |
374 | template <typename T> |
375 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
376 | add(typename ProgramStateTrait<T>::key_type K) const; |
377 | |
378 | template <typename T> |
379 | typename ProgramStateTrait<T>::data_type |
380 | get() const { |
381 | return ProgramStateTrait<T>::MakeData(FindGDM(ProgramStateTrait<T>::GDMIndex())); |
382 | } |
383 | |
384 | template<typename T> |
385 | typename ProgramStateTrait<T>::lookup_type |
386 | get(typename ProgramStateTrait<T>::key_type key) const { |
387 | void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex()); |
388 | return ProgramStateTrait<T>::Lookup(ProgramStateTrait<T>::MakeData(d), key); |
389 | } |
390 | |
391 | template <typename T> |
392 | typename ProgramStateTrait<T>::context_type get_context() const; |
393 | |
394 | template <typename T> |
395 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
396 | remove(typename ProgramStateTrait<T>::key_type K) const; |
397 | |
398 | template <typename T> |
399 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
400 | remove(typename ProgramStateTrait<T>::key_type K, |
401 | typename ProgramStateTrait<T>::context_type C) const; |
402 | |
403 | template <typename T> LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef remove() const; |
404 | |
405 | template <typename T> |
406 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
407 | set(typename ProgramStateTrait<T>::data_type D) const; |
408 | |
409 | template <typename T> |
410 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
411 | set(typename ProgramStateTrait<T>::key_type K, |
412 | typename ProgramStateTrait<T>::value_type E) const; |
413 | |
414 | template <typename T> |
415 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
416 | set(typename ProgramStateTrait<T>::key_type K, |
417 | typename ProgramStateTrait<T>::value_type E, |
418 | typename ProgramStateTrait<T>::context_type C) const; |
419 | |
420 | template<typename T> |
421 | bool contains(typename ProgramStateTrait<T>::key_type key) const { |
422 | void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex()); |
423 | return ProgramStateTrait<T>::Contains(ProgramStateTrait<T>::MakeData(d), key); |
424 | } |
425 | |
426 | // Pretty-printing. |
427 | void printJson(raw_ostream &Out, const LocationContext *LCtx = nullptr, |
428 | const char *NL = "\n", unsigned int Space = 0, |
429 | bool IsDot = false) const; |
430 | |
431 | void printDOT(raw_ostream &Out, const LocationContext *LCtx = nullptr, |
432 | unsigned int Space = 0) const; |
433 | |
434 | void dump() const; |
435 | |
436 | private: |
437 | friend void ProgramStateRetain(const ProgramState *state); |
438 | friend void ProgramStateRelease(const ProgramState *state); |
439 | |
440 | /// \sa invalidateValues() |
441 | /// \sa invalidateRegions() |
442 | ProgramStateRef |
443 | invalidateRegionsImpl(ArrayRef<SVal> Values, |
444 | const Expr *E, unsigned BlockCount, |
445 | const LocationContext *LCtx, |
446 | bool ResultsInSymbolEscape, |
447 | InvalidatedSymbols *IS, |
448 | RegionAndSymbolInvalidationTraits *HTraits, |
449 | const CallEvent *Call) const; |
450 | }; |
451 | |
452 | //===----------------------------------------------------------------------===// |
453 | // ProgramStateManager - Factory object for ProgramStates. |
454 | //===----------------------------------------------------------------------===// |
455 | |
456 | class ProgramStateManager { |
457 | friend class ProgramState; |
458 | friend void ProgramStateRelease(const ProgramState *state); |
459 | private: |
460 | /// Eng - The SubEngine that owns this state manager. |
461 | SubEngine *Eng; /* Can be null. */ |
462 | |
463 | EnvironmentManager EnvMgr; |
464 | std::unique_ptr<StoreManager> StoreMgr; |
465 | std::unique_ptr<ConstraintManager> ConstraintMgr; |
466 | |
467 | ProgramState::GenericDataMap::Factory GDMFactory; |
468 | |
469 | typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; |
470 | GDMContextsTy GDMContexts; |
471 | |
472 | /// StateSet - FoldingSet containing all the states created for analyzing |
473 | /// a particular function. This is used to unique states. |
474 | llvm::FoldingSet<ProgramState> StateSet; |
475 | |
476 | /// Object that manages the data for all created SVals. |
477 | std::unique_ptr<SValBuilder> svalBuilder; |
478 | |
479 | /// Manages memory for created CallEvents. |
480 | std::unique_ptr<CallEventManager> CallEventMgr; |
481 | |
482 | /// A BumpPtrAllocator to allocate states. |
483 | llvm::BumpPtrAllocator &Alloc; |
484 | |
485 | /// A vector of ProgramStates that we can reuse. |
486 | std::vector<ProgramState *> freeStates; |
487 | |
488 | public: |
489 | ProgramStateManager(ASTContext &Ctx, |
490 | StoreManagerCreator CreateStoreManager, |
491 | ConstraintManagerCreator CreateConstraintManager, |
492 | llvm::BumpPtrAllocator& alloc, |
493 | SubEngine *subeng); |
494 | |
495 | ~ProgramStateManager(); |
496 | |
497 | ProgramStateRef getInitialState(const LocationContext *InitLoc); |
498 | |
499 | ASTContext &getContext() { return svalBuilder->getContext(); } |
500 | const ASTContext &getContext() const { return svalBuilder->getContext(); } |
501 | |
502 | BasicValueFactory &getBasicVals() { |
503 | return svalBuilder->getBasicValueFactory(); |
504 | } |
505 | |
506 | SValBuilder &getSValBuilder() { |
507 | return *svalBuilder; |
508 | } |
509 | |
510 | SymbolManager &getSymbolManager() { |
511 | return svalBuilder->getSymbolManager(); |
512 | } |
513 | const SymbolManager &getSymbolManager() const { |
514 | return svalBuilder->getSymbolManager(); |
515 | } |
516 | |
517 | llvm::BumpPtrAllocator& getAllocator() { return Alloc; } |
518 | |
519 | MemRegionManager& getRegionManager() { |
520 | return svalBuilder->getRegionManager(); |
521 | } |
522 | const MemRegionManager &getRegionManager() const { |
523 | return svalBuilder->getRegionManager(); |
524 | } |
525 | |
526 | CallEventManager &getCallEventManager() { return *CallEventMgr; } |
527 | |
528 | StoreManager &getStoreManager() { return *StoreMgr; } |
529 | ConstraintManager &getConstraintManager() { return *ConstraintMgr; } |
530 | SubEngine &getOwningEngine() { return *Eng; } |
531 | |
532 | ProgramStateRef removeDeadBindings(ProgramStateRef St, |
533 | const StackFrameContext *LCtx, |
534 | SymbolReaper& SymReaper); |
535 | |
536 | public: |
537 | |
538 | SVal ArrayToPointer(Loc Array, QualType ElementTy) { |
539 | return StoreMgr->ArrayToPointer(Array, ElementTy); |
540 | } |
541 | |
542 | // Methods that manipulate the GDM. |
543 | ProgramStateRef addGDM(ProgramStateRef St, void *Key, void *Data); |
544 | ProgramStateRef removeGDM(ProgramStateRef state, void *Key); |
545 | |
546 | // Methods that query & manipulate the Store. |
547 | |
548 | void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler& F) { |
549 | StoreMgr->iterBindings(state->getStore(), F); |
550 | } |
551 | |
552 | ProgramStateRef getPersistentState(ProgramState &Impl); |
553 | ProgramStateRef getPersistentStateWithGDM(ProgramStateRef FromState, |
554 | ProgramStateRef GDMState); |
555 | |
556 | bool haveEqualConstraints(ProgramStateRef S1, ProgramStateRef S2) const { |
557 | return ConstraintMgr->haveEqualConstraints(S1, S2); |
558 | } |
559 | |
560 | bool haveEqualEnvironments(ProgramStateRef S1, ProgramStateRef S2) const { |
561 | return S1->Env == S2->Env; |
562 | } |
563 | |
564 | bool haveEqualStores(ProgramStateRef S1, ProgramStateRef S2) const { |
565 | return S1->store == S2->store; |
566 | } |
567 | |
568 | //==---------------------------------------------------------------------==// |
569 | // Generic Data Map methods. |
570 | //==---------------------------------------------------------------------==// |
571 | // |
572 | // ProgramStateManager and ProgramState support a "generic data map" that allows |
573 | // different clients of ProgramState objects to embed arbitrary data within a |
574 | // ProgramState object. The generic data map is essentially an immutable map |
575 | // from a "tag" (that acts as the "key" for a client) and opaque values. |
576 | // Tags/keys and values are simply void* values. The typical way that clients |
577 | // generate unique tags are by taking the address of a static variable. |
578 | // Clients are responsible for ensuring that data values referred to by a |
579 | // the data pointer are immutable (and thus are essentially purely functional |
580 | // data). |
581 | // |
582 | // The templated methods below use the ProgramStateTrait<T> class |
583 | // to resolve keys into the GDM and to return data values to clients. |
584 | // |
585 | |
586 | // Trait based GDM dispatch. |
587 | template <typename T> |
588 | ProgramStateRef set(ProgramStateRef st, typename ProgramStateTrait<T>::data_type D) { |
589 | return addGDM(st, ProgramStateTrait<T>::GDMIndex(), |
590 | ProgramStateTrait<T>::MakeVoidPtr(D)); |
591 | } |
592 | |
593 | template<typename T> |
594 | ProgramStateRef set(ProgramStateRef st, |
595 | typename ProgramStateTrait<T>::key_type K, |
596 | typename ProgramStateTrait<T>::value_type V, |
597 | typename ProgramStateTrait<T>::context_type C) { |
598 | |
599 | return addGDM(st, ProgramStateTrait<T>::GDMIndex(), |
600 | ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Set(st->get<T>(), K, V, C))); |
601 | } |
602 | |
603 | template <typename T> |
604 | ProgramStateRef add(ProgramStateRef st, |
605 | typename ProgramStateTrait<T>::key_type K, |
606 | typename ProgramStateTrait<T>::context_type C) { |
607 | return addGDM(st, ProgramStateTrait<T>::GDMIndex(), |
608 | ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Add(st->get<T>(), K, C))); |
609 | } |
610 | |
611 | template <typename T> |
612 | ProgramStateRef remove(ProgramStateRef st, |
613 | typename ProgramStateTrait<T>::key_type K, |
614 | typename ProgramStateTrait<T>::context_type C) { |
615 | |
616 | return addGDM(st, ProgramStateTrait<T>::GDMIndex(), |
617 | ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Remove(st->get<T>(), K, C))); |
618 | } |
619 | |
620 | template <typename T> |
621 | ProgramStateRef remove(ProgramStateRef st) { |
622 | return removeGDM(st, ProgramStateTrait<T>::GDMIndex()); |
623 | } |
624 | |
625 | void *FindGDMContext(void *index, |
626 | void *(*CreateContext)(llvm::BumpPtrAllocator&), |
627 | void (*DeleteContext)(void*)); |
628 | |
629 | template <typename T> |
630 | typename ProgramStateTrait<T>::context_type get_context() { |
631 | void *p = FindGDMContext(ProgramStateTrait<T>::GDMIndex(), |
632 | ProgramStateTrait<T>::CreateContext, |
633 | ProgramStateTrait<T>::DeleteContext); |
634 | |
635 | return ProgramStateTrait<T>::MakeContext(p); |
636 | } |
637 | }; |
638 | |
639 | |
640 | //===----------------------------------------------------------------------===// |
641 | // Out-of-line method definitions for ProgramState. |
642 | //===----------------------------------------------------------------------===// |
643 | |
644 | inline ConstraintManager &ProgramState::getConstraintManager() const { |
645 | return stateMgr->getConstraintManager(); |
646 | } |
647 | |
648 | inline const VarRegion* ProgramState::getRegion(const VarDecl *D, |
649 | const LocationContext *LC) const |
650 | { |
651 | return getStateManager().getRegionManager().getVarRegion(D, LC); |
652 | } |
653 | |
654 | inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond, |
655 | bool Assumption) const { |
656 | if (Cond.isUnknown()) |
657 | return this; |
658 | |
659 | return getStateManager().ConstraintMgr |
660 | ->assume(this, Cond.castAs<DefinedSVal>(), Assumption); |
661 | } |
662 | |
663 | inline std::pair<ProgramStateRef , ProgramStateRef > |
664 | ProgramState::assume(DefinedOrUnknownSVal Cond) const { |
665 | if (Cond.isUnknown()) |
666 | return std::make_pair(this, this); |
667 | |
668 | return getStateManager().ConstraintMgr |
669 | ->assumeDual(this, Cond.castAs<DefinedSVal>()); |
670 | } |
671 | |
672 | inline ProgramStateRef ProgramState::assumeInclusiveRange( |
673 | DefinedOrUnknownSVal Val, const llvm::APSInt &From, const llvm::APSInt &To, |
674 | bool Assumption) const { |
675 | if (Val.isUnknown()) |
676 | return this; |
677 | |
678 | assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!")((Val.getAs<NonLoc>() && "Only NonLocs are supported!" ) ? static_cast<void> (0) : __assert_fail ("Val.getAs<NonLoc>() && \"Only NonLocs are supported!\"" , "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" , 678, __PRETTY_FUNCTION__)); |
679 | |
680 | return getStateManager().ConstraintMgr->assumeInclusiveRange( |
681 | this, Val.castAs<NonLoc>(), From, To, Assumption); |
682 | } |
683 | |
684 | inline std::pair<ProgramStateRef, ProgramStateRef> |
685 | ProgramState::assumeInclusiveRange(DefinedOrUnknownSVal Val, |
686 | const llvm::APSInt &From, |
687 | const llvm::APSInt &To) const { |
688 | if (Val.isUnknown()) |
689 | return std::make_pair(this, this); |
690 | |
691 | assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!")((Val.getAs<NonLoc>() && "Only NonLocs are supported!" ) ? static_cast<void> (0) : __assert_fail ("Val.getAs<NonLoc>() && \"Only NonLocs are supported!\"" , "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" , 691, __PRETTY_FUNCTION__)); |
692 | |
693 | return getStateManager().ConstraintMgr->assumeInclusiveRangeDual( |
694 | this, Val.castAs<NonLoc>(), From, To); |
695 | } |
696 | |
697 | inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V, const LocationContext *LCtx) const { |
698 | if (Optional<Loc> L = LV.getAs<Loc>()) |
699 | return bindLoc(*L, V, LCtx); |
700 | return this; |
701 | } |
702 | |
703 | inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec, |
704 | const SubRegion *Super) const { |
705 | const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl(); |
706 | return loc::MemRegionVal( |
707 | getStateManager().getRegionManager().getCXXBaseObjectRegion( |
708 | Base, Super, BaseSpec.isVirtual())); |
709 | } |
710 | |
711 | inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass, |
712 | const SubRegion *Super, |
713 | bool IsVirtual) const { |
714 | return loc::MemRegionVal( |
715 | getStateManager().getRegionManager().getCXXBaseObjectRegion( |
716 | BaseClass, Super, IsVirtual)); |
717 | } |
718 | |
719 | inline Loc ProgramState::getLValue(const VarDecl *VD, |
720 | const LocationContext *LC) const { |
721 | return getStateManager().StoreMgr->getLValueVar(VD, LC); |
722 | } |
723 | |
724 | inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal, |
725 | const LocationContext *LC) const { |
726 | return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC); |
727 | } |
728 | |
729 | inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const { |
730 | return getStateManager().StoreMgr->getLValueIvar(D, Base); |
731 | } |
732 | |
733 | inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const { |
734 | return getStateManager().StoreMgr->getLValueField(D, Base); |
735 | } |
736 | |
737 | inline SVal ProgramState::getLValue(const IndirectFieldDecl *D, |
738 | SVal Base) const { |
739 | StoreManager &SM = *getStateManager().StoreMgr; |
740 | for (const auto *I : D->chain()) { |
741 | Base = SM.getLValueField(cast<FieldDecl>(I), Base); |
742 | } |
743 | |
744 | return Base; |
745 | } |
746 | |
747 | inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ |
748 | if (Optional<NonLoc> N = Idx.getAs<NonLoc>()) |
749 | return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base); |
750 | return UnknownVal(); |
751 | } |
752 | |
753 | inline SVal ProgramState::getSVal(const Stmt *Ex, |
754 | const LocationContext *LCtx) const{ |
755 | return Env.getSVal(EnvironmentEntry(Ex, LCtx), |
756 | *getStateManager().svalBuilder); |
757 | } |
758 | |
759 | inline SVal |
760 | ProgramState::getSValAsScalarOrLoc(const Stmt *S, |
761 | const LocationContext *LCtx) const { |
762 | if (const Expr *Ex = dyn_cast<Expr>(S)) { |
763 | QualType T = Ex->getType(); |
764 | if (Ex->isGLValue() || Loc::isLocType(T) || |
765 | T->isIntegralOrEnumerationType()) |
766 | return getSVal(S, LCtx); |
767 | } |
768 | |
769 | return UnknownVal(); |
770 | } |
771 | |
772 | inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const { |
773 | return getStateManager().StoreMgr->getBinding(getStore(), LV, T); |
774 | } |
775 | |
776 | inline SVal ProgramState::getSVal(const MemRegion* R, QualType T) const { |
777 | return getStateManager().StoreMgr->getBinding(getStore(), |
778 | loc::MemRegionVal(R), |
779 | T); |
780 | } |
781 | |
782 | inline BasicValueFactory &ProgramState::getBasicVals() const { |
783 | return getStateManager().getBasicVals(); |
784 | } |
785 | |
786 | inline SymbolManager &ProgramState::getSymbolManager() const { |
787 | return getStateManager().getSymbolManager(); |
788 | } |
789 | |
790 | template<typename T> |
791 | ProgramStateRef ProgramState::add(typename ProgramStateTrait<T>::key_type K) const { |
792 | return getStateManager().add<T>(this, K, get_context<T>()); |
793 | } |
794 | |
795 | template <typename T> |
796 | typename ProgramStateTrait<T>::context_type ProgramState::get_context() const { |
797 | return getStateManager().get_context<T>(); |
798 | } |
799 | |
800 | template<typename T> |
801 | ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const { |
802 | return getStateManager().remove<T>(this, K, get_context<T>()); |
803 | } |
804 | |
805 | template<typename T> |
806 | ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K, |
807 | typename ProgramStateTrait<T>::context_type C) const { |
808 | return getStateManager().remove<T>(this, K, C); |
809 | } |
810 | |
811 | template <typename T> |
812 | ProgramStateRef ProgramState::remove() const { |
813 | return getStateManager().remove<T>(this); |
814 | } |
815 | |
816 | template<typename T> |
817 | ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::data_type D) const { |
818 | return getStateManager().set<T>(this, D); |
819 | } |
820 | |
821 | template<typename T> |
822 | ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K, |
823 | typename ProgramStateTrait<T>::value_type E) const { |
824 | return getStateManager().set<T>(this, K, E, get_context<T>()); |
825 | } |
826 | |
827 | template<typename T> |
828 | ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K, |
829 | typename ProgramStateTrait<T>::value_type E, |
830 | typename ProgramStateTrait<T>::context_type C) const { |
831 | return getStateManager().set<T>(this, K, E, C); |
832 | } |
833 | |
834 | template <typename CB> |
835 | CB ProgramState::scanReachableSymbols(SVal val) const { |
836 | CB cb(this); |
837 | scanReachableSymbols(val, cb); |
838 | return cb; |
839 | } |
840 | |
841 | template <typename CB> |
842 | CB ProgramState::scanReachableSymbols( |
843 | llvm::iterator_range<region_iterator> Reachable) const { |
844 | CB cb(this); |
845 | scanReachableSymbols(Reachable, cb); |
846 | return cb; |
847 | } |
848 | |
849 | /// \class ScanReachableSymbols |
850 | /// A utility class that visits the reachable symbols using a custom |
851 | /// SymbolVisitor. Terminates recursive traversal when the visitor function |
852 | /// returns false. |
853 | class ScanReachableSymbols { |
854 | typedef llvm::DenseSet<const void*> VisitedItems; |
855 | |
856 | VisitedItems visited; |
857 | ProgramStateRef state; |
858 | SymbolVisitor &visitor; |
859 | public: |
860 | ScanReachableSymbols(ProgramStateRef st, SymbolVisitor &v) |
861 | : state(std::move(st)), visitor(v) {} |
862 | |
863 | bool scan(nonloc::LazyCompoundVal val); |
864 | bool scan(nonloc::CompoundVal val); |
865 | bool scan(SVal val); |
866 | bool scan(const MemRegion *R); |
867 | bool scan(const SymExpr *sym); |
868 | }; |
869 | |
870 | } // end ento namespace |
871 | |
872 | } // end clang namespace |
873 | |
874 | #endif |
1 | //ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- 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 partial implementations of template specializations of |
10 | // the class ProgramStateTrait<>. ProgramStateTrait<> is used by ProgramState |
11 | // to implement set/get methods for manipulating a ProgramState's |
12 | // generic data map. |
13 | // |
14 | //===----------------------------------------------------------------------===// |
15 | |
16 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H |
17 | #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H |
18 | |
19 | #include "llvm/ADT/ImmutableList.h" |
20 | #include "llvm/ADT/ImmutableMap.h" |
21 | #include "llvm/ADT/ImmutableSet.h" |
22 | #include "llvm/Support/Allocator.h" |
23 | #include <cstdint> |
24 | |
25 | namespace clang { |
26 | namespace ento { |
27 | |
28 | template <typename T> struct ProgramStatePartialTrait; |
29 | |
30 | /// Declares a program state trait for type \p Type called \p Name, and |
31 | /// introduce a type named \c NameTy. |
32 | /// The macro should not be used inside namespaces. |
33 | #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)namespace { class Name {}; using NameTy = Type; } namespace clang { namespace ento { template <> struct ProgramStateTrait <Name> : public ProgramStatePartialTrait<NameTy> { static void *GDMIndex() { static int Index; return &Index ; } }; } } \ |
34 | namespace { \ |
35 | class Name {}; \ |
36 | using Name ## Ty = Type; \ |
37 | } \ |
38 | namespace clang { \ |
39 | namespace ento { \ |
40 | template <> \ |
41 | struct ProgramStateTrait<Name> \ |
42 | : public ProgramStatePartialTrait<Name ## Ty> { \ |
43 | static void *GDMIndex() { static int Index; return &Index; } \ |
44 | }; \ |
45 | } \ |
46 | } |
47 | |
48 | /// Declares a factory for objects of type \p Type in the program state |
49 | /// manager. The type must provide a ::Factory sub-class. Commonly used for |
50 | /// ImmutableMap, ImmutableSet, ImmutableList. The macro should not be used |
51 | /// inside namespaces. |
52 | #define REGISTER_FACTORY_WITH_PROGRAMSTATE(Type)namespace clang { namespace ento { template <> struct ProgramStateTrait <Type> : public ProgramStatePartialTrait<Type> { static void *GDMIndex() { static int Index; return &Index; } }; } } \ |
53 | namespace clang { \ |
54 | namespace ento { \ |
55 | template <> \ |
56 | struct ProgramStateTrait<Type> \ |
57 | : public ProgramStatePartialTrait<Type> { \ |
58 | static void *GDMIndex() { static int Index; return &Index; } \ |
59 | }; \ |
60 | } \ |
61 | } |
62 | |
63 | /// Helper for registering a map trait. |
64 | /// |
65 | /// If the map type were written directly in the invocation of |
66 | /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments |
67 | /// would be treated as a macro argument separator, which is wrong. |
68 | /// This allows the user to specify a map type in a way that the preprocessor |
69 | /// can deal with. |
70 | #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value)llvm::ImmutableMap<Key, Value> llvm::ImmutableMap<Key, Value> |
71 | |
72 | /// Declares an immutable map of type \p NameTy, suitable for placement into |
73 | /// the ProgramState. This is implementing using llvm::ImmutableMap. |
74 | /// |
75 | /// \code |
76 | /// State = State->set<Name>(K, V); |
77 | /// const Value *V = State->get<Name>(K); // Returns NULL if not in the map. |
78 | /// State = State->remove<Name>(K); |
79 | /// NameTy Map = State->get<Name>(); |
80 | /// \endcode |
81 | /// |
82 | /// The macro should not be used inside namespaces, or for traits that must |
83 | /// be accessible from more than one translation unit. |
84 | #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)namespace { class Name {}; using NameTy = llvm::ImmutableMap< Key, Value>; } namespace clang { namespace ento { template <> struct ProgramStateTrait<Name> : public ProgramStatePartialTrait <NameTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } \ |
85 | REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \namespace { class Name {}; using NameTy = llvm::ImmutableMap< Key, Value>; } namespace clang { namespace ento { template <> struct ProgramStateTrait<Name> : public ProgramStatePartialTrait <NameTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } |
86 | CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value))namespace { class Name {}; using NameTy = llvm::ImmutableMap< Key, Value>; } namespace clang { namespace ento { template <> struct ProgramStateTrait<Name> : public ProgramStatePartialTrait <NameTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } |
87 | |
88 | /// Declares an immutable map type \p Name and registers the factory |
89 | /// for such maps in the program state, but does not add the map itself |
90 | /// to the program state. Useful for managing lifetime of maps that are used |
91 | /// as elements of other program state data structures. |
92 | #define REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(Name, Key, Value)using Name = llvm::ImmutableMap<Key, Value>; namespace clang { namespace ento { template <> struct ProgramStateTrait <Name> : public ProgramStatePartialTrait<Name> { static void *GDMIndex() { static int Index; return &Index; } }; } } \ |
93 | using Name = llvm::ImmutableMap<Key, Value>; \ |
94 | REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)namespace clang { namespace ento { template <> struct ProgramStateTrait <Name> : public ProgramStatePartialTrait<Name> { static void *GDMIndex() { static int Index; return &Index; } }; } } |
95 | |
96 | |
97 | /// Declares an immutable set of type \p NameTy, suitable for placement into |
98 | /// the ProgramState. This is implementing using llvm::ImmutableSet. |
99 | /// |
100 | /// \code |
101 | /// State = State->add<Name>(E); |
102 | /// State = State->remove<Name>(E); |
103 | /// bool Present = State->contains<Name>(E); |
104 | /// NameTy Set = State->get<Name>(); |
105 | /// \endcode |
106 | /// |
107 | /// The macro should not be used inside namespaces, or for traits that must |
108 | /// be accessible from more than one translation unit. |
109 | #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)namespace { class Name {}; using NameTy = llvm::ImmutableSet< Elem>; } namespace clang { namespace ento { template <> struct ProgramStateTrait<Name> : public ProgramStatePartialTrait <NameTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } \ |
110 | REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>)namespace { class Name {}; using NameTy = llvm::ImmutableSet< Elem>; } namespace clang { namespace ento { template <> struct ProgramStateTrait<Name> : public ProgramStatePartialTrait <NameTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } |
111 | |
112 | /// Declares an immutable set type \p Name and registers the factory |
113 | /// for such sets in the program state, but does not add the set itself |
114 | /// to the program state. Useful for managing lifetime of sets that are used |
115 | /// as elements of other program state data structures. |
116 | #define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem)using Name = llvm::ImmutableSet<Elem>; namespace clang { namespace ento { template <> struct ProgramStateTrait< Name> : public ProgramStatePartialTrait<Name> { static void *GDMIndex() { static int Index; return &Index; } }; } } \ |
117 | using Name = llvm::ImmutableSet<Elem>; \ |
118 | REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)namespace clang { namespace ento { template <> struct ProgramStateTrait <Name> : public ProgramStatePartialTrait<Name> { static void *GDMIndex() { static int Index; return &Index; } }; } } |
119 | |
120 | |
121 | /// Declares an immutable list type \p NameTy, suitable for placement into |
122 | /// the ProgramState. This is implementing using llvm::ImmutableList. |
123 | /// |
124 | /// \code |
125 | /// State = State->add<Name>(E); // Adds to the /end/ of the list. |
126 | /// bool Present = State->contains<Name>(E); |
127 | /// NameTy List = State->get<Name>(); |
128 | /// \endcode |
129 | /// |
130 | /// The macro should not be used inside namespaces, or for traits that must |
131 | /// be accessible from more than one translation unit. |
132 | #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem)namespace { class Name {}; using NameTy = llvm::ImmutableList <Elem>; } namespace clang { namespace ento { template < > struct ProgramStateTrait<Name> : public ProgramStatePartialTrait <NameTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } \ |
133 | REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)namespace { class Name {}; using NameTy = llvm::ImmutableList <Elem>; } namespace clang { namespace ento { template < > struct ProgramStateTrait<Name> : public ProgramStatePartialTrait <NameTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } |
134 | |
135 | /// Declares an immutable list of type \p Name and registers the factory |
136 | /// for such lists in the program state, but does not add the list itself |
137 | /// to the program state. Useful for managing lifetime of lists that are used |
138 | /// as elements of other program state data structures. |
139 | #define REGISTER_LIST_FACTORY_WITH_PROGRAMSTATE(Name, Elem)using Name = llvm::ImmutableList<Elem>; namespace clang { namespace ento { template <> struct ProgramStateTrait <Name> : public ProgramStatePartialTrait<Name> { static void *GDMIndex() { static int Index; return &Index; } }; } } \ |
140 | using Name = llvm::ImmutableList<Elem>; \ |
141 | REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)namespace clang { namespace ento { template <> struct ProgramStateTrait <Name> : public ProgramStatePartialTrait<Name> { static void *GDMIndex() { static int Index; return &Index; } }; } } |
142 | |
143 | |
144 | // Partial-specialization for ImmutableMap. |
145 | template <typename Key, typename Data, typename Info> |
146 | struct ProgramStatePartialTrait<llvm::ImmutableMap<Key, Data, Info>> { |
147 | using data_type = llvm::ImmutableMap<Key, Data, Info>; |
148 | using context_type = typename data_type::Factory &; |
149 | using key_type = Key; |
150 | using value_type = Data; |
151 | using lookup_type = const value_type *; |
152 | |
153 | static data_type MakeData(void *const *p) { |
154 | return p ? data_type((typename data_type::TreeTy *) *p) |
155 | : data_type(nullptr); |
156 | } |
157 | |
158 | static void *MakeVoidPtr(data_type B) { |
159 | return B.getRoot(); |
160 | } |
161 | |
162 | static lookup_type Lookup(data_type B, key_type K) { |
163 | return B.lookup(K); |
164 | } |
165 | |
166 | static data_type Set(data_type B, key_type K, value_type E, |
167 | context_type F) { |
168 | return F.add(B, K, E); |
169 | } |
170 | |
171 | static data_type Remove(data_type B, key_type K, context_type F) { |
172 | return F.remove(B, K); |
173 | } |
174 | |
175 | static bool Contains(data_type B, key_type K) { |
176 | return B.contains(K); |
177 | } |
178 | |
179 | static context_type MakeContext(void *p) { |
180 | return *((typename data_type::Factory *) p); |
181 | } |
182 | |
183 | static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { |
184 | return new typename data_type::Factory(Alloc); |
185 | } |
186 | |
187 | static void DeleteContext(void *Ctx) { |
188 | delete (typename data_type::Factory *) Ctx; |
189 | } |
190 | }; |
191 | |
192 | // Partial-specialization for ImmutableSet. |
193 | template <typename Key, typename Info> |
194 | struct ProgramStatePartialTrait<llvm::ImmutableSet<Key, Info>> { |
195 | using data_type = llvm::ImmutableSet<Key, Info>; |
196 | using context_type = typename data_type::Factory &; |
197 | using key_type = Key; |
198 | |
199 | static data_type MakeData(void *const *p) { |
200 | return p ? data_type((typename data_type::TreeTy *) *p) |
201 | : data_type(nullptr); |
202 | } |
203 | |
204 | static void *MakeVoidPtr(data_type B) { |
205 | return B.getRoot(); |
206 | } |
207 | |
208 | static data_type Add(data_type B, key_type K, context_type F) { |
209 | return F.add(B, K); |
210 | } |
211 | |
212 | static data_type Remove(data_type B, key_type K, context_type F) { |
213 | return F.remove(B, K); |
214 | } |
215 | |
216 | static bool Contains(data_type B, key_type K) { |
217 | return B.contains(K); |
218 | } |
219 | |
220 | static context_type MakeContext(void *p) { |
221 | return *((typename data_type::Factory *) p); |
222 | } |
223 | |
224 | static void *CreateContext(llvm::BumpPtrAllocator &Alloc) { |
225 | return new typename data_type::Factory(Alloc); |
226 | } |
227 | |
228 | static void DeleteContext(void *Ctx) { |
229 | delete (typename data_type::Factory *) Ctx; |
230 | } |
231 | }; |
232 | |
233 | // Partial-specialization for ImmutableList. |
234 | template <typename T> |
235 | struct ProgramStatePartialTrait<llvm::ImmutableList<T>> { |
236 | using data_type = llvm::ImmutableList<T>; |
237 | using key_type = T; |
238 | using context_type = typename data_type::Factory &; |
239 | |
240 | static data_type Add(data_type L, key_type K, context_type F) { |
241 | return F.add(K, L); |
242 | } |
243 | |
244 | static bool Contains(data_type L, key_type K) { |
245 | return L.contains(K); |
246 | } |
247 | |
248 | static data_type MakeData(void *const *p) { |
249 | return p ? data_type((const llvm::ImmutableListImpl<T> *) *p) |
250 | : data_type(nullptr); |
251 | } |
252 | |
253 | static void *MakeVoidPtr(data_type D) { |
254 | return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer()); |
255 | } |
256 | |
257 | static context_type MakeContext(void *p) { |
258 | return *((typename data_type::Factory *) p); |
259 | } |
260 | |
261 | static void *CreateContext(llvm::BumpPtrAllocator &Alloc) { |
262 | return new typename data_type::Factory(Alloc); |
263 | } |
264 | |
265 | static void DeleteContext(void *Ctx) { |
266 | delete (typename data_type::Factory *) Ctx; |
267 | } |
268 | }; |
269 | |
270 | // Partial specialization for bool. |
271 | template <> struct ProgramStatePartialTrait<bool> { |
272 | using data_type = bool; |
273 | |
274 | static data_type MakeData(void *const *p) { |
275 | return p ? (data_type) (uintptr_t) *p |
276 | : data_type(); |
277 | } |
278 | |
279 | static void *MakeVoidPtr(data_type d) { |
280 | return (void *) (uintptr_t) d; |
281 | } |
282 | }; |
283 | |
284 | // Partial specialization for unsigned. |
285 | template <> struct ProgramStatePartialTrait<unsigned> { |
286 | using data_type = unsigned; |
287 | |
288 | static data_type MakeData(void *const *p) { |
289 | return p ? (data_type) (uintptr_t) *p |
290 | : data_type(); |
291 | } |
292 | |
293 | static void *MakeVoidPtr(data_type d) { |
294 | return (void *) (uintptr_t) d; |
295 | } |
296 | }; |
297 | |
298 | // Partial specialization for void*. |
299 | template <> struct ProgramStatePartialTrait<void *> { |
300 | using data_type = void *; |
301 | |
302 | static data_type MakeData(void *const *p) { |
303 | return p ? *p |
304 | : data_type(); |
305 | } |
306 | |
307 | static void *MakeVoidPtr(data_type d) { |
308 | return d; |
309 | } |
310 | }; |
311 | |
312 | // Partial specialization for const void *. |
313 | template <> struct ProgramStatePartialTrait<const void *> { |
314 | using data_type = const void *; |
315 | |
316 | static data_type MakeData(void *const *p) { |
317 | return p ? *p : data_type(); |
318 | } |
319 | |
320 | static void *MakeVoidPtr(data_type d) { |
321 | return const_cast<void *>(d); |
322 | } |
323 | }; |
324 | |
325 | } // namespace ento |
326 | } // namespace clang |
327 | |
328 | #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H |