clang 22.0.0git
SVals.cpp
Go to the documentation of this file.
1//===-- SVals.cpp - Abstract RValues for Path-Sens. Value Tracking --------===//
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 SVal, Loc, and NonLoc, classes that represent
10// abstract r-values for use with path-sensitive value tracking.
11//
12//===----------------------------------------------------------------------===//
13
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/Type.h"
21#include "clang/Basic/LLVM.h"
28#include "llvm/Support/Compiler.h"
29#include "llvm/Support/ErrorHandling.h"
30#include "llvm/Support/raw_ostream.h"
31#include <cassert>
32#include <optional>
33
34using namespace clang;
35using namespace ento;
36
37//===----------------------------------------------------------------------===//
38// Symbol iteration within an SVal.
39//===----------------------------------------------------------------------===//
40
41//===----------------------------------------------------------------------===//
42// Utility methods.
43//===----------------------------------------------------------------------===//
44
46 if (std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
47 const MemRegion* R = X->getRegion();
48 if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>())
49 if (const auto *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
50 return FD;
51 }
52
53 if (auto X = getAs<nonloc::PointerToMember>()) {
54 if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(X->getDecl()))
55 return MD;
56 }
57 return nullptr;
58}
59
60/// If this SVal is a location (subclasses Loc) and wraps a symbol,
61/// return that SymbolRef. Otherwise return 0.
62///
63/// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
64/// region. If that is the case, gets the underlining region.
65/// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic,
66/// the first symbolic parent region is returned.
67SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const {
68 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
69 if (const MemRegion *R = getAsRegion())
70 if (const SymbolicRegion *SymR =
71 IncludeBaseRegions ? R->getSymbolicBase()
72 : dyn_cast<SymbolicRegion>(R->StripCasts()))
73 return SymR->getSymbol();
74
75 return nullptr;
76}
77
78/// Get the symbol in the SVal or its base region.
80 std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
81
82 if (!X)
83 return nullptr;
84
85 const MemRegion *R = X->getRegion();
86
87 while (const auto *SR = dyn_cast<SubRegion>(R)) {
88 if (const auto *SymR = dyn_cast<SymbolicRegion>(SR))
89 return SymR->getSymbol();
90 else
91 R = SR->getSuperRegion();
92 }
93
94 return nullptr;
95}
96
97/// If this SVal wraps a symbol return that SymbolRef.
98/// Otherwise, return 0.
99///
100/// Casts are ignored during lookup.
101/// \param IncludeBaseRegions The boolean that controls whether the search
102/// should continue to the base regions if the region is not symbolic.
103SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const {
104 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
105 if (std::optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
106 return X->getSymbol();
107
108 return getAsLocSymbol(IncludeBaseRegions);
109}
110
111const llvm::APSInt *SVal::getAsInteger() const {
112 if (auto CI = getAs<nonloc::ConcreteInt>())
113 return CI->getValue().get();
114 if (auto CI = getAs<loc::ConcreteInt>())
115 return CI->getValue().get();
116 return nullptr;
117}
118
120 if (std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
121 return X->getRegion();
122
123 if (std::optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
124 return X->getLoc().getAsRegion();
125
126 return nullptr;
127}
128
129namespace {
130class TypeRetrievingVisitor
131 : public FullSValVisitor<TypeRetrievingVisitor, QualType> {
132private:
133 const ASTContext &Context;
134
135public:
136 TypeRetrievingVisitor(const ASTContext &Context) : Context(Context) {}
137
138 QualType VisitMemRegionVal(loc::MemRegionVal MRV) {
139 return Visit(MRV.getRegion());
140 }
141 QualType VisitGotoLabel(loc::GotoLabel GL) {
142 return QualType{Context.VoidPtrTy};
143 }
144 template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) {
145 const llvm::APSInt &Value = CI.getValue();
146 if (1 == Value.getBitWidth())
147 return Context.BoolTy;
148 return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned());
149 }
150 QualType VisitLocAsInteger(nonloc::LocAsInteger LI) {
151 QualType NestedType = Visit(LI.getLoc());
152 if (NestedType.isNull())
153 return NestedType;
154
155 return Context.getIntTypeForBitwidth(LI.getNumBits(),
156 NestedType->isSignedIntegerType());
157 }
158 QualType VisitCompoundVal(nonloc::CompoundVal CV) {
159 return CV.getValue()->getType();
160 }
161 QualType VisitLazyCompoundVal(nonloc::LazyCompoundVal LCV) {
162 return LCV.getRegion()->getValueType();
163 }
164 QualType VisitSymbolVal(nonloc::SymbolVal SV) {
165 return Visit(SV.getSymbol());
166 }
167 QualType VisitSymbolicRegion(const SymbolicRegion *SR) {
168 return Visit(SR->getSymbol());
169 }
170 QualType VisitAllocaRegion(const AllocaRegion *) {
171 return QualType{Context.VoidPtrTy};
172 }
173 QualType VisitTypedRegion(const TypedRegion *TR) {
174 return TR->getLocationType();
175 }
176 QualType VisitSymExpr(const SymExpr *SE) { return SE->getType(); }
177};
178} // end anonymous namespace
179
180QualType SVal::getType(const ASTContext &Context) const {
181 TypeRetrievingVisitor TRV{Context};
182 return TRV.Visit(*this);
183}
184
185const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const {
186 return getRegion()->StripCasts(StripBaseCasts);
187}
188
190 return static_cast<const LazyCompoundValData*>(Data)->getStore();
191}
192
194 return static_cast<const LazyCompoundValData*>(Data)->getRegion();
195}
196
198 return getPTMData().isNull();
199}
200
202 const auto PTMD = this->getPTMData();
203 if (PTMD.isNull())
204 return nullptr;
205
206 const NamedDecl *ND = nullptr;
207 if (const auto *NDP = dyn_cast<const NamedDecl *>(PTMD))
208 ND = NDP;
209 else
210 ND = cast<const PointerToMemberData *>(PTMD)->getDeclaratorDecl();
211
212 return ND;
213}
214
215//===----------------------------------------------------------------------===//
216// Other Iterators.
217//===----------------------------------------------------------------------===//
218
220 return getValue()->begin();
221}
222
224 return getValue()->end();
225}
226
228 const PTMDataType PTMD = getPTMData();
229 if (isa<const NamedDecl *>(PTMD))
230 return {};
231 return cast<const PointerToMemberData *>(PTMD)->begin();
232}
233
235 const PTMDataType PTMD = getPTMData();
236 if (isa<const NamedDecl *>(PTMD))
237 return {};
238 return cast<const PointerToMemberData *>(PTMD)->end();
239}
240
241//===----------------------------------------------------------------------===//
242// Useful predicates.
243//===----------------------------------------------------------------------===//
244
245bool SVal::isConstant() const {
246 return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>();
247}
248
249bool SVal::isConstant(int I) const {
250 if (std::optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
251 return *LV->getValue() == I;
252 if (std::optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
253 return *NV->getValue() == I;
254 return false;
255}
256
258 return isConstant(0);
259}
260
261//===----------------------------------------------------------------------===//
262// Pretty-Printing.
263//===----------------------------------------------------------------------===//
264
265StringRef SVal::getKindStr() const {
266 switch (getKind()) {
267#define BASIC_SVAL(Id, Parent) \
268 case Id##Kind: \
269 return #Id;
270#define LOC_SVAL(Id, Parent) \
271 case Loc##Id##Kind: \
272 return #Id;
273#define NONLOC_SVAL(Id, Parent) \
274 case NonLoc##Id##Kind: \
275 return #Id;
276#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
277#undef REGION
278 }
279 llvm_unreachable("Unkown kind!");
280}
281
282LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); }
283
284void SVal::printJson(raw_ostream &Out, bool AddQuotes) const {
285 std::string Buf;
286 llvm::raw_string_ostream TempOut(Buf);
287
288 dumpToStream(TempOut);
289
290 Out << JsonFormat(Buf, AddQuotes);
291}
292
293void SVal::dumpToStream(raw_ostream &os) const {
294 if (isUndef()) {
295 os << "Undefined";
296 return;
297 }
298 if (isUnknown()) {
299 os << "Unknown";
300 return;
301 }
302 if (NonLoc::classof(*this)) {
303 castAs<NonLoc>().dumpToStream(os);
304 return;
305 }
306 if (Loc::classof(*this)) {
307 castAs<Loc>().dumpToStream(os);
308 return;
309 }
310 llvm_unreachable("Unhandled SVal kind!");
311}
312
313void NonLoc::dumpToStream(raw_ostream &os) const {
314 switch (getKind()) {
315 case nonloc::ConcreteIntKind: {
316 APSIntPtr Value = castAs<nonloc::ConcreteInt>().getValue();
317 os << Value << ' ' << (Value->isSigned() ? 'S' : 'U')
318 << Value->getBitWidth() << 'b';
319 break;
320 }
321 case nonloc::SymbolValKind:
322 os << castAs<nonloc::SymbolVal>().getSymbol();
323 break;
324
325 case nonloc::LocAsIntegerKind: {
326 const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>();
327 os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
328 break;
329 }
330 case nonloc::CompoundValKind: {
331 const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>();
332 os << "compoundVal{";
333 bool first = true;
334 for (const auto &I : C) {
335 if (first) {
336 os << ' '; first = false;
337 }
338 else
339 os << ", ";
340
341 I.dumpToStream(os);
342 }
343 os << "}";
344 break;
345 }
346 case nonloc::LazyCompoundValKind: {
347 const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>();
348 os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
349 << ',' << C.getRegion()
350 << '}';
351 break;
352 }
353 case nonloc::PointerToMemberKind: {
354 os << "pointerToMember{";
355 const nonloc::PointerToMember &CastRes =
356 castAs<nonloc::PointerToMember>();
357 if (CastRes.getDecl())
358 os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|";
359 bool first = true;
360 for (const auto &I : CastRes) {
361 if (first) {
362 os << ' '; first = false;
363 }
364 else
365 os << ", ";
366
367 os << I->getType();
368 }
369
370 os << '}';
371 break;
372 }
373 default:
374 assert(false && "Pretty-printed not implemented for this NonLoc.");
375 break;
376 }
377}
378
379void Loc::dumpToStream(raw_ostream &os) const {
380 switch (getKind()) {
381 case loc::ConcreteIntKind:
382 os << castAs<loc::ConcreteInt>().getValue()->getZExtValue() << " (Loc)";
383 break;
384 case loc::GotoLabelKind:
385 os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
386 break;
387 case loc::MemRegionValKind:
388 os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
389 break;
390 default:
391 llvm_unreachable("Pretty-printing not implemented for this Loc.");
392 }
393}
Defines the clang::ASTContext interface.
static const MemRegion * getRegion(const CallEvent &Call, const MutexDescriptor &Descriptor, bool IsLock)
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:1192
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
#define X(type, name)
Definition: Value.h:145
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
CanQualType VoidPtrTy
Definition: ASTContext.h:1249
CanQualType BoolTy
Definition: ASTContext.h:1223
QualType getIntTypeForBitwidth(unsigned DestWidth, unsigned Signed) const
getIntTypeForBitwidth - sets integer QualTy according to specified details: bitwidth,...
Represents a function declaration or definition.
Definition: Decl.h:1999
This represents a decl that may have a name.
Definition: Decl.h:273
std::string getQualifiedNameAsString() const
Definition: Decl.cpp:1680
A (possibly-)qualified type.
Definition: TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: TypeBase.h:1004
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition: Type.cpp:2209
A safe wrapper around APSInt objects allocated and owned by BasicValueFactory.
Definition: APSIntPtr.h:19
AllocaRegion - A region that represents an untyped blob of bytes created by a call to 'alloca'.
Definition: MemRegion.h:506
FullSValVisitor - a convenient mixed visitor for all three: SVal, SymExpr and MemRegion subclasses.
Definition: SValVisitor.h:130
FunctionCodeRegion - A region that represents code texts of function.
Definition: MemRegion.h:612
void dumpToStream(raw_ostream &Out) const
Definition: SVals.cpp:379
static bool classof(SVal V)
Definition: SVals.h:267
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:98
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
Definition: MemRegion.cpp:1457
const SymbolicRegion * getSymbolicBase() const
If this is a symbolic region, returns the region.
Definition: MemRegion.cpp:1480
const RegionTy * getAs() const
Definition: MemRegion.h:1416
static bool classof(SVal V)
Definition: SVals.h:250
void dumpToStream(raw_ostream &Out) const
Definition: SVals.cpp:313
bool isZeroConstant() const
Definition: SVals.cpp:257
void dumpToStream(raw_ostream &OS) const
Definition: SVals.cpp:293
void dump() const
Definition: SVals.cpp:282
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition: SVals.cpp:103
const FunctionDecl * getAsFunctionDecl() const
getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a CodeTextRegion wrapping a FunctionDecl...
Definition: SVals.cpp:45
void printJson(raw_ostream &Out, bool AddQuotes) const
printJson - Pretty-prints in JSON format.
Definition: SVals.cpp:284
bool isConstant() const
Definition: SVals.cpp:245
StringRef getKindStr() const
Definition: SVals.cpp:265
QualType getType(const ASTContext &) const
Try to get a reasonable type for the given value.
Definition: SVals.cpp:180
const llvm::APSInt * getAsInteger() const
If this SVal is loc::ConcreteInt or nonloc::ConcreteInt, return a pointer to APSInt which is held in ...
Definition: SVals.cpp:111
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
Definition: SVals.cpp:67
const MemRegion * getAsRegion() const
Definition: SVals.cpp:119
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
Definition: SVals.cpp:79
Symbolic value.
Definition: SymExpr.h:32
virtual QualType getType() const =0
SymbolicRegion - A special, "non-concrete" region.
Definition: MemRegion.h:808
SymbolRef getSymbol() const
It might return null.
Definition: MemRegion.h:827
TypedRegion - An abstract class representing regions that are typed.
Definition: MemRegion.h:539
virtual QualType getLocationType() const =0
TypedValueRegion - An abstract class representing regions having a typed value.
Definition: MemRegion.h:563
virtual QualType getValueType() const =0
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * stripCasts(bool StripBaseCasts=true) const
Get the underlining region and strip casts.
Definition: SVals.cpp:185
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getRegion() const
Get the underlining region.
Definition: SVals.h:493
The simplest example of a concrete compound value is nonloc::CompoundVal, which represents a concrete...
Definition: SVals.h:339
LLVM_ATTRIBUTE_RETURNS_NONNULL const CompoundValData * getValue() const
Definition: SVals.h:348
llvm::ImmutableList< SVal >::iterator iterator
Definition: SVals.h:352
While nonloc::CompoundVal covers a few simple use cases, nonloc::LazyCompoundVal is a more performant...
Definition: SVals.h:389
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
This function itself is immaterial.
Definition: SVals.cpp:193
const void * getStore() const
It might return null.
Definition: SVals.cpp:189
unsigned getNumBits() const
Definition: SVals.h:328
Value representing pointer-to-member.
Definition: SVals.h:434
llvm::PointerUnion< const NamedDecl *, const PointerToMemberData * > PTMDataType
Definition: SVals.h:439
llvm::ImmutableList< const CXXBaseSpecifier * >::iterator iterator
Definition: SVals.h:454
const NamedDecl * getDecl() const
Definition: SVals.cpp:201
Represents symbolic expression that isn't a location.
Definition: SVals.h:279
LLVM_ATTRIBUTE_RETURNS_NONNULL SymbolRef getSymbol() const
Definition: SVals.h:288
The JSON file list parser is used to communicate input to InstallAPI.
std::string JsonFormat(StringRef RawSR, bool AddQuotes)
Definition: JsonSupport.h:28