1 //===-- SVals.cpp - Abstract RValues for Path-Sens. Value Tracking --------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines SVal, Loc, and NonLoc, classes that represent
10 // abstract r-values for use with path-sensitive value tracking.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Expr.h"
19 #include "clang/AST/Type.h"
20 #include "clang/Basic/JsonSupport.h"
21 #include "clang/Basic/LLVM.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
24 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
25 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
26 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
28 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/Compiler.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/raw_ostream.h"
35 using namespace clang
;
38 //===----------------------------------------------------------------------===//
39 // Symbol iteration within an SVal.
40 //===----------------------------------------------------------------------===//
42 //===----------------------------------------------------------------------===//
44 //===----------------------------------------------------------------------===//
46 const FunctionDecl
*SVal::getAsFunctionDecl() const {
47 if (std::optional
<loc::MemRegionVal
> X
= getAs
<loc::MemRegionVal
>()) {
48 const MemRegion
* R
= X
->getRegion();
49 if (const FunctionCodeRegion
*CTR
= R
->getAs
<FunctionCodeRegion
>())
50 if (const auto *FD
= dyn_cast
<FunctionDecl
>(CTR
->getDecl()))
54 if (auto X
= getAs
<nonloc::PointerToMember
>()) {
55 if (const auto *MD
= dyn_cast_or_null
<CXXMethodDecl
>(X
->getDecl()))
61 /// If this SVal is a location (subclasses Loc) and wraps a symbol,
62 /// return that SymbolRef. Otherwise return 0.
64 /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
65 /// region. If that is the case, gets the underlining region.
66 /// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic,
67 /// the first symbolic parent region is returned.
68 SymbolRef
SVal::getAsLocSymbol(bool IncludeBaseRegions
) const {
69 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
70 if (const MemRegion
*R
= getAsRegion())
71 if (const SymbolicRegion
*SymR
=
72 IncludeBaseRegions
? R
->getSymbolicBase()
73 : dyn_cast
<SymbolicRegion
>(R
->StripCasts()))
74 return SymR
->getSymbol();
79 /// Get the symbol in the SVal or its base region.
80 SymbolRef
SVal::getLocSymbolInBase() const {
81 std::optional
<loc::MemRegionVal
> X
= getAs
<loc::MemRegionVal
>();
86 const MemRegion
*R
= X
->getRegion();
88 while (const auto *SR
= dyn_cast
<SubRegion
>(R
)) {
89 if (const auto *SymR
= dyn_cast
<SymbolicRegion
>(SR
))
90 return SymR
->getSymbol();
92 R
= SR
->getSuperRegion();
98 /// If this SVal wraps a symbol return that SymbolRef.
99 /// Otherwise, return 0.
101 /// Casts are ignored during lookup.
102 /// \param IncludeBaseRegions The boolean that controls whether the search
103 /// should continue to the base regions if the region is not symbolic.
104 SymbolRef
SVal::getAsSymbol(bool IncludeBaseRegions
) const {
105 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
106 if (std::optional
<nonloc::SymbolVal
> X
= getAs
<nonloc::SymbolVal
>())
107 return X
->getSymbol();
109 return getAsLocSymbol(IncludeBaseRegions
);
112 const llvm::APSInt
*SVal::getAsInteger() const {
113 if (auto CI
= getAs
<nonloc::ConcreteInt
>())
114 return &CI
->getValue();
115 if (auto CI
= getAs
<loc::ConcreteInt
>())
116 return &CI
->getValue();
120 const MemRegion
*SVal::getAsRegion() const {
121 if (std::optional
<loc::MemRegionVal
> X
= getAs
<loc::MemRegionVal
>())
122 return X
->getRegion();
124 if (std::optional
<nonloc::LocAsInteger
> X
= getAs
<nonloc::LocAsInteger
>())
125 return X
->getLoc().getAsRegion();
131 class TypeRetrievingVisitor
132 : public FullSValVisitor
<TypeRetrievingVisitor
, QualType
> {
134 const ASTContext
&Context
;
137 TypeRetrievingVisitor(const ASTContext
&Context
) : Context(Context
) {}
139 QualType
VisitLocMemRegionVal(loc::MemRegionVal MRV
) {
140 return Visit(MRV
.getRegion());
142 QualType
VisitLocGotoLabel(loc::GotoLabel GL
) {
143 return QualType
{Context
.VoidPtrTy
};
145 template <class ConcreteInt
> QualType
VisitConcreteInt(ConcreteInt CI
) {
146 const llvm::APSInt
&Value
= CI
.getValue();
147 if (1 == Value
.getBitWidth())
148 return Context
.BoolTy
;
149 return Context
.getIntTypeForBitwidth(Value
.getBitWidth(), Value
.isSigned());
151 QualType
VisitLocConcreteInt(loc::ConcreteInt CI
) {
152 return VisitConcreteInt(CI
);
154 QualType
VisitNonLocConcreteInt(nonloc::ConcreteInt CI
) {
155 return VisitConcreteInt(CI
);
157 QualType
VisitNonLocLocAsInteger(nonloc::LocAsInteger LI
) {
158 QualType NestedType
= Visit(LI
.getLoc());
159 if (NestedType
.isNull())
162 return Context
.getIntTypeForBitwidth(LI
.getNumBits(),
163 NestedType
->isSignedIntegerType());
165 QualType
VisitNonLocCompoundVal(nonloc::CompoundVal CV
) {
166 return CV
.getValue()->getType();
168 QualType
VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal LCV
) {
169 return LCV
.getRegion()->getValueType();
171 QualType
VisitNonLocSymbolVal(nonloc::SymbolVal SV
) {
172 return Visit(SV
.getSymbol());
174 QualType
VisitSymbolicRegion(const SymbolicRegion
*SR
) {
175 return Visit(SR
->getSymbol());
177 QualType
VisitTypedRegion(const TypedRegion
*TR
) {
178 return TR
->getLocationType();
180 QualType
VisitSymExpr(const SymExpr
*SE
) { return SE
->getType(); }
182 } // end anonymous namespace
184 QualType
SVal::getType(const ASTContext
&Context
) const {
185 TypeRetrievingVisitor TRV
{Context
};
186 return TRV
.Visit(*this);
189 const MemRegion
*loc::MemRegionVal::stripCasts(bool StripBaseCasts
) const {
190 return getRegion()->StripCasts(StripBaseCasts
);
193 const void *nonloc::LazyCompoundVal::getStore() const {
194 return static_cast<const LazyCompoundValData
*>(Data
)->getStore();
197 const TypedValueRegion
*nonloc::LazyCompoundVal::getRegion() const {
198 return static_cast<const LazyCompoundValData
*>(Data
)->getRegion();
201 bool nonloc::PointerToMember::isNullMemberPointer() const {
202 return getPTMData().isNull();
205 const NamedDecl
*nonloc::PointerToMember::getDecl() const {
206 const auto PTMD
= this->getPTMData();
210 const NamedDecl
*ND
= nullptr;
211 if (PTMD
.is
<const NamedDecl
*>())
212 ND
= PTMD
.get
<const NamedDecl
*>();
214 ND
= PTMD
.get
<const PointerToMemberData
*>()->getDeclaratorDecl();
219 //===----------------------------------------------------------------------===//
221 //===----------------------------------------------------------------------===//
223 nonloc::CompoundVal::iterator
nonloc::CompoundVal::begin() const {
224 return getValue()->begin();
227 nonloc::CompoundVal::iterator
nonloc::CompoundVal::end() const {
228 return getValue()->end();
231 nonloc::PointerToMember::iterator
nonloc::PointerToMember::begin() const {
232 const PTMDataType PTMD
= getPTMData();
233 if (PTMD
.is
<const NamedDecl
*>())
235 return PTMD
.get
<const PointerToMemberData
*>()->begin();
238 nonloc::PointerToMember::iterator
nonloc::PointerToMember::end() const {
239 const PTMDataType PTMD
= getPTMData();
240 if (PTMD
.is
<const NamedDecl
*>())
242 return PTMD
.get
<const PointerToMemberData
*>()->end();
245 //===----------------------------------------------------------------------===//
246 // Useful predicates.
247 //===----------------------------------------------------------------------===//
249 bool SVal::isConstant() const {
250 return getAs
<nonloc::ConcreteInt
>() || getAs
<loc::ConcreteInt
>();
253 bool SVal::isConstant(int I
) const {
254 if (std::optional
<loc::ConcreteInt
> LV
= getAs
<loc::ConcreteInt
>())
255 return LV
->getValue() == I
;
256 if (std::optional
<nonloc::ConcreteInt
> NV
= getAs
<nonloc::ConcreteInt
>())
257 return NV
->getValue() == I
;
261 bool SVal::isZeroConstant() const {
262 return isConstant(0);
265 //===----------------------------------------------------------------------===//
267 //===----------------------------------------------------------------------===//
269 LLVM_DUMP_METHOD
void SVal::dump() const { dumpToStream(llvm::errs()); }
271 void SVal::printJson(raw_ostream
&Out
, bool AddQuotes
) const {
273 llvm::raw_string_ostream
TempOut(Buf
);
275 dumpToStream(TempOut
);
277 Out
<< JsonFormat(TempOut
.str(), AddQuotes
);
280 void SVal::dumpToStream(raw_ostream
&os
) const {
281 switch (getBaseKind()) {
286 castAs
<NonLoc
>().dumpToStream(os
);
289 castAs
<Loc
>().dumpToStream(os
);
291 case UndefinedValKind
:
297 void NonLoc::dumpToStream(raw_ostream
&os
) const {
298 switch (getSubKind()) {
299 case nonloc::ConcreteIntKind
: {
300 const auto &Value
= castAs
<nonloc::ConcreteInt
>().getValue();
301 os
<< Value
<< ' ' << (Value
.isSigned() ? 'S' : 'U')
302 << Value
.getBitWidth() << 'b';
305 case nonloc::SymbolValKind
:
306 os
<< castAs
<nonloc::SymbolVal
>().getSymbol();
309 case nonloc::LocAsIntegerKind
: {
310 const nonloc::LocAsInteger
& C
= castAs
<nonloc::LocAsInteger
>();
311 os
<< C
.getLoc() << " [as " << C
.getNumBits() << " bit integer]";
314 case nonloc::CompoundValKind
: {
315 const nonloc::CompoundVal
& C
= castAs
<nonloc::CompoundVal
>();
316 os
<< "compoundVal{";
318 for (const auto &I
: C
) {
320 os
<< ' '; first
= false;
330 case nonloc::LazyCompoundValKind
: {
331 const nonloc::LazyCompoundVal
&C
= castAs
<nonloc::LazyCompoundVal
>();
332 os
<< "lazyCompoundVal{" << const_cast<void *>(C
.getStore())
333 << ',' << C
.getRegion()
337 case nonloc::PointerToMemberKind
: {
338 os
<< "pointerToMember{";
339 const nonloc::PointerToMember
&CastRes
=
340 castAs
<nonloc::PointerToMember
>();
341 if (CastRes
.getDecl())
342 os
<< "|" << CastRes
.getDecl()->getQualifiedNameAsString() << "|";
344 for (const auto &I
: CastRes
) {
346 os
<< ' '; first
= false;
358 assert(false && "Pretty-printed not implemented for this NonLoc.");
363 void Loc::dumpToStream(raw_ostream
&os
) const {
364 switch (getSubKind()) {
365 case loc::ConcreteIntKind
:
366 os
<< castAs
<loc::ConcreteInt
>().getValue().getZExtValue() << " (Loc)";
368 case loc::GotoLabelKind
:
369 os
<< "&&" << castAs
<loc::GotoLabel
>().getLabel()->getName();
371 case loc::MemRegionValKind
:
372 os
<< '&' << castAs
<loc::MemRegionVal
>().getRegion()->getString();
375 llvm_unreachable("Pretty-printing not implemented for this Loc.");