clang 20.0.0git
ProgramState.h
Go to the documentation of this file.
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"
23#include "llvm/ADT/FoldingSet.h"
24#include "llvm/ADT/ImmutableMap.h"
25#include "llvm/Support/Allocator.h"
26#include <optional>
27#include <utility>
28
29namespace llvm {
30class APSInt;
31}
32
33namespace clang {
34class ASTContext;
35
36namespace ento {
37
38class AnalysisManager;
39class CallEvent;
40class CallEventManager;
41
42typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)(
44typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)(
46
47//===----------------------------------------------------------------------===//
48// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState.
49//===----------------------------------------------------------------------===//
50
51template <typename T> struct ProgramStateTrait {
52 typedef typename T::data_type data_type;
53 static inline void *MakeVoidPtr(data_type D) { return (void*) D; }
54 static inline data_type MakeData(void *const* P) {
55 return P ? (data_type) *P : (data_type) 0;
56 }
57};
58
59/// \class ProgramState
60/// ProgramState - This class encapsulates:
61///
62/// 1. A mapping from expressions to values (Environment)
63/// 2. A mapping from locations to values (Store)
64/// 3. Constraints on symbolic values (GenericDataMap)
65///
66/// Together these represent the "abstract state" of a program.
67///
68/// ProgramState is intended to be used as a functional object; that is,
69/// once it is created and made "persistent" in a FoldingSet, its
70/// values will never change.
71class ProgramState : public llvm::FoldingSetNode {
72public:
73 typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
74
75private:
76 void operator=(const ProgramState& R) = delete;
77
78 friend class ProgramStateManager;
79 friend class ExplodedGraph;
80 friend class ExplodedNode;
81 friend class NodeBuilder;
82
83 ProgramStateManager *stateMgr;
84 Environment Env; // Maps a Stmt to its current SVal.
85 Store store; // Maps a location to its current value.
86 GenericDataMap GDM; // Custom data stored by a client of this class.
87
88 // A state is infeasible if there is a contradiction among the constraints.
89 // An infeasible state is represented by a `nullptr`.
90 // In the sense of `assumeDual`, a state can have two children by adding a
91 // new constraint and the negation of that new constraint. A parent state is
92 // over-constrained if both of its children are infeasible. In the
93 // mathematical sense, it means that the parent is infeasible and we should
94 // have realized that at the moment when we have created it. However, we
95 // could not recognize that because of the imperfection of the underlying
96 // constraint solver. We say it is posteriorly over-constrained because we
97 // recognize that a parent is infeasible only *after* a new and more specific
98 // constraint and its negation are evaluated.
99 //
100 // Example:
101 //
102 // x * x = 4 and x is in the range [0, 1]
103 // This is an already infeasible state, but the constraint solver is not
104 // capable of handling sqrt, thus we don't know it yet.
105 //
106 // Then a new constraint `x = 0` is added. At this moment the constraint
107 // solver re-evaluates the existing constraints and realizes the
108 // contradiction `0 * 0 = 4`.
109 // We also evaluate the negated constraint `x != 0`; the constraint solver
110 // deduces `x = 1` and then realizes the contradiction `1 * 1 = 4`.
111 // Both children are infeasible, thus the parent state is marked as
112 // posteriorly over-constrained. These parents are handled with special care:
113 // we do not allow transitions to exploded nodes with such states.
114 bool PosteriorlyOverconstrained = false;
115 // Make internal constraint solver entities friends so they can access the
116 // overconstrained-related functions. We want to keep this API inaccessible
117 // for Checkers.
118 friend class ConstraintManager;
119 bool isPosteriorlyOverconstrained() const {
120 return PosteriorlyOverconstrained;
121 }
122 ProgramStateRef cloneAsPosteriorlyOverconstrained() const;
123
124 unsigned refCount;
125
126 /// makeWithStore - Return a ProgramState with the same values as the current
127 /// state with the exception of using the specified Store.
128 ProgramStateRef makeWithStore(const StoreRef &store) const;
129
130 void setStore(const StoreRef &storeRef);
131
132public:
133 /// This ctor is used when creating the first ProgramState object.
135 StoreRef st, GenericDataMap gdm);
136
137 /// Copy ctor - We must explicitly define this or else the "Next" ptr
138 /// in FoldingSetNode will also get copied.
139 ProgramState(const ProgramState &RHS);
140
142
143 int64_t getID() const;
144
145 /// Return the ProgramStateManager associated with this state.
147 return *stateMgr;
148 }
149
151
152 /// Return the ConstraintManager.
154
155 /// getEnvironment - Return the environment associated with this state.
156 /// The environment is the mapping from expressions to values.
157 const Environment& getEnvironment() const { return Env; }
158
159 /// Return the store associated with this state. The store
160 /// is a mapping from locations to values.
161 Store getStore() const { return store; }
162
163
164 /// getGDM - Return the generic data map associated with this state.
165 GenericDataMap getGDM() const { return GDM; }
166
167 void setGDM(GenericDataMap gdm) { GDM = gdm; }
168
169 /// Profile - Profile the contents of a ProgramState object for use in a
170 /// FoldingSet. Two ProgramState objects are considered equal if they
171 /// have the same Environment, Store, and GenericDataMap.
172 static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) {
173 V->Env.Profile(ID);
174 ID.AddPointer(V->store);
175 V->GDM.Profile(ID);
176 ID.AddBoolean(V->PosteriorlyOverconstrained);
177 }
178
179 /// Profile - Used to profile the contents of this object for inclusion
180 /// in a FoldingSet.
181 void Profile(llvm::FoldingSetNodeID& ID) const {
182 Profile(ID, this);
183 }
184
187
188 //==---------------------------------------------------------------------==//
189 // Constraints on values.
190 //==---------------------------------------------------------------------==//
191 //
192 // Each ProgramState records constraints on symbolic values. These constraints
193 // are managed using the ConstraintManager associated with a ProgramStateManager.
194 // As constraints gradually accrue on symbolic values, added constraints
195 // may conflict and indicate that a state is infeasible (as no real values
196 // could satisfy all the constraints). This is the principal mechanism
197 // for modeling path-sensitivity in ExprEngine/ProgramState.
198 //
199 // Various "assume" methods form the interface for adding constraints to
200 // symbolic values. A call to 'assume' indicates an assumption being placed
201 // on one or symbolic values. 'assume' methods take the following inputs:
202 //
203 // (1) A ProgramState object representing the current state.
204 //
205 // (2) The assumed constraint (which is specific to a given "assume" method).
206 //
207 // (3) A binary value "Assumption" that indicates whether the constraint is
208 // assumed to be true or false.
209 //
210 // The output of "assume*" is a new ProgramState object with the added constraints.
211 // If no new state is feasible, NULL is returned.
212 //
213
214 /// Assumes that the value of \p cond is zero (if \p assumption is "false")
215 /// or non-zero (if \p assumption is "true").
216 ///
217 /// This returns a new state with the added constraint on \p cond.
218 /// If no new state is feasible, NULL is returned.
220 bool assumption) const;
221
222 /// Assumes both "true" and "false" for \p cond, and returns both
223 /// corresponding states (respectively).
224 ///
225 /// This is more efficient than calling assume() twice. Note that one (but not
226 /// both) of the returned states may be NULL.
227 [[nodiscard]] std::pair<ProgramStateRef, ProgramStateRef>
228 assume(DefinedOrUnknownSVal cond) const;
229
230 [[nodiscard]] std::pair<ProgramStateRef, ProgramStateRef>
232 QualType IndexType = QualType()) const;
233
234 [[nodiscard]] ProgramStateRef
236 bool assumption, QualType IndexType = QualType()) const;
237
238 /// Assumes that the value of \p Val is bounded with [\p From; \p To]
239 /// (if \p assumption is "true") or it is fully out of this range
240 /// (if \p assumption is "false").
241 ///
242 /// This returns a new state with the added constraint on \p cond.
243 /// If no new state is feasible, NULL is returned.
245 const llvm::APSInt &From,
246 const llvm::APSInt &To,
247 bool assumption) const;
248
249 /// Assumes given range both "true" and "false" for \p Val, and returns both
250 /// corresponding states (respectively).
251 ///
252 /// This is more efficient than calling assume() twice. Note that one (but not
253 /// both) of the returned states may be NULL.
254 [[nodiscard]] std::pair<ProgramStateRef, ProgramStateRef>
255 assumeInclusiveRange(DefinedOrUnknownSVal Val, const llvm::APSInt &From,
256 const llvm::APSInt &To) const;
257
258 /// Check if the given SVal is not constrained to zero and is not
259 /// a zero constant.
261
262 /// Check if the given SVal is constrained to zero or is a zero
263 /// constant.
265
266 /// \return Whether values \p Lhs and \p Rhs are equal.
267 ConditionTruthVal areEqual(SVal Lhs, SVal Rhs) const;
268
269 /// Utility method for getting regions.
270 LLVM_ATTRIBUTE_RETURNS_NONNULL
271 const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
272
273 //==---------------------------------------------------------------------==//
274 // Binding and retrieving values to/from the environment and symbolic store.
275 //==---------------------------------------------------------------------==//
276
277 /// Create a new state by binding the value 'V' to the statement 'S' in the
278 /// state's environment.
279 [[nodiscard]] ProgramStateRef BindExpr(const Stmt *S,
280 const LocationContext *LCtx, SVal V,
281 bool Invalidate = true) const;
282
283 [[nodiscard]] ProgramStateRef bindLoc(Loc location, SVal V,
284 const LocationContext *LCtx,
285 bool notifyChanges = true) const;
286
287 [[nodiscard]] ProgramStateRef bindLoc(SVal location, SVal V,
288 const LocationContext *LCtx) const;
289
290 /// Initializes the region of memory represented by \p loc with an initial
291 /// value. Once initialized, all values loaded from any sub-regions of that
292 /// region will be equal to \p V, unless overwritten later by the program.
293 /// This method should not be used on regions that are already initialized.
294 /// If you need to indicate that memory contents have suddenly become unknown
295 /// within a certain region of memory, consider invalidateRegions().
296 [[nodiscard]] ProgramStateRef
297 bindDefaultInitial(SVal loc, SVal V, const LocationContext *LCtx) const;
298
299 /// Performs C++ zero-initialization procedure on the region of memory
300 /// represented by \p loc.
301 [[nodiscard]] ProgramStateRef
302 bindDefaultZero(SVal loc, const LocationContext *LCtx) const;
303
304 [[nodiscard]] ProgramStateRef killBinding(Loc LV) const;
305
306 /// Returns the state with bindings for the given regions cleared from the
307 /// store. If \p Call is non-null, also invalidates global regions (but if
308 /// \p Call is from a system header, then this is limited to globals declared
309 /// in system headers).
310 ///
311 /// This calls the lower-level method \c StoreManager::invalidateRegions to
312 /// do the actual invalidation, then calls the checker callbacks which should
313 /// be triggered by this event.
314 ///
315 /// \param Regions the set of regions to be invalidated.
316 /// \param E the expression that caused the invalidation.
317 /// \param BlockCount The number of times the current basic block has been
318 /// visited.
319 /// \param CausesPointerEscape the flag is set to true when the invalidation
320 /// entails escape of a symbol (representing a pointer). For example,
321 /// due to it being passed as an argument in a call.
322 /// \param IS the set of invalidated symbols.
323 /// \param Call if non-null, the invalidated regions represent parameters to
324 /// the call and should be considered directly invalidated.
325 /// \param ITraits information about special handling for particular regions
326 /// or symbols.
327 [[nodiscard]] ProgramStateRef
329 unsigned BlockCount, const LocationContext *LCtx,
330 bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
331 const CallEvent *Call = nullptr,
332 RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
333
334 [[nodiscard]] ProgramStateRef
335 invalidateRegions(ArrayRef<SVal> Values, const Stmt *S, unsigned BlockCount,
336 const LocationContext *LCtx, bool CausesPointerEscape,
337 InvalidatedSymbols *IS = nullptr,
338 const CallEvent *Call = nullptr,
339 RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
340
341 /// enterStackFrame - Returns the state for entry to the given stack frame,
342 /// preserving the current state.
343 [[nodiscard]] ProgramStateRef
345 const StackFrameContext *CalleeCtx) const;
346
347 /// Return the value of 'self' if available in the given context.
348 SVal getSelfSVal(const LocationContext *LC) const;
349
350 /// Get the lvalue for a base class object reference.
351 Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const;
352
353 /// Get the lvalue for a base class object reference.
354 Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
355 bool IsVirtual) const;
356
357 /// Get the lvalue for a variable reference.
358 Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
359
360 Loc getLValue(const CompoundLiteralExpr *literal,
361 const LocationContext *LC) const;
362
363 /// Get the lvalue for an ivar reference.
364 SVal getLValue(const ObjCIvarDecl *decl, SVal base) const;
365
366 /// Get the lvalue for a field reference.
367 SVal getLValue(const FieldDecl *decl, SVal Base) const;
368
369 /// Get the lvalue for an indirect field reference.
371
372 /// Get the lvalue for an array index.
373 SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
374
375 /// Returns the SVal bound to the statement 'S' in the state's environment.
376 SVal getSVal(const Stmt *S, const LocationContext *LCtx) const;
377
378 SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const;
379
380 /// Return the value bound to the specified location.
381 /// Returns UnknownVal() if none found.
382 SVal getSVal(Loc LV, QualType T = QualType()) const;
383
384 /// Returns the "raw" SVal bound to LV before any value simplfication.
385 SVal getRawSVal(Loc LV, QualType T= QualType()) const;
386
387 /// Return the value bound to the specified location.
388 /// Returns UnknownVal() if none found.
389 SVal getSVal(const MemRegion* R, QualType T = QualType()) const;
390
391 /// Return the value bound to the specified location, assuming
392 /// that the value is a scalar integer or an enumeration or a pointer.
393 /// Returns UnknownVal() if none found or the region is not known to hold
394 /// a value of such type.
395 SVal getSValAsScalarOrLoc(const MemRegion *R) const;
396
397 using region_iterator = const MemRegion **;
398
399 /// Visits the symbols reachable from the given SVal using the provided