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
VisitAllocaRegion(const AllocaRegion
*) {
178 return QualType
{Context
.VoidPtrTy
};
180 QualType
VisitTypedRegion(const TypedRegion
*TR
) {
181 return TR
->getLocationType();
183 QualType
VisitSymExpr(const SymExpr
*SE
) { return SE
->getType(); }
185 } // end anonymous namespace
187 QualType
SVal::getType(const ASTContext
&Context
) const {
188 TypeRetrievingVisitor TRV
{Context
};
189 return TRV
.Visit(*this);
192 const MemRegion
*loc::MemRegionVal::stripCasts(bool StripBaseCasts
) const {
193 return getRegion()->StripCasts(StripBaseCasts
);
196 const void *nonloc::LazyCompoundVal::getStore() const {
197 return static_cast<const LazyCompoundValData
*>(Data
)->getStore();
200 const TypedValueRegion
*nonloc::LazyCompoundVal::getRegion() const {
201 return static_cast<const LazyCompoundValData
*>(Data
)->getRegion();
204 bool nonloc::PointerToMember::isNullMemberPointer() const {
205 return getPTMData().isNull();
208 const NamedDecl
*nonloc::PointerToMember::getDecl() const {
209 const auto PTMD
= this->getPTMData();
213 const NamedDecl
*ND
= nullptr;
214 if (PTMD
.is
<const NamedDecl
*>())
215 ND
= PTMD
.get
<const NamedDecl
*>();
217 ND
= PTMD
.get
<const PointerToMemberData
*>()->getDeclaratorDecl();
222 //===----------------------------------------------------------------------===//
224 //===----------------------------------------------------------------------===//
226 nonloc::CompoundVal::iterator
nonloc::CompoundVal::begin() const {
227 return getValue()->begin();
230 nonloc::CompoundVal::iterator
nonloc::CompoundVal::end() const {
231 return getValue()->end();
234 nonloc::PointerToMember::iterator
nonloc::PointerToMember::begin() const {
235 const PTMDataType PTMD
= getPTMData();
236 if (PTMD
.is
<const NamedDecl
*>())
238 return PTMD
.get
<const PointerToMemberData
*>()->begin();
241 nonloc::PointerToMember::iterator
nonloc::PointerToMember::end() const {
242 const PTMDataType PTMD
= getPTMData();
243 if (PTMD
.is
<const NamedDecl
*>())
245 return PTMD
.get
<const PointerToMemberData
*>()->end();
248 //===----------------------------------------------------------------------===//
249 // Useful predicates.
250 //===----------------------------------------------------------------------===//
252 bool SVal::isConstant() const {
253 return getAs
<nonloc::ConcreteInt
>() || getAs
<loc::ConcreteInt
>();
256 bool SVal::isConstant(int I
) const {
257 if (std::optional
<loc::ConcreteInt
> LV
= getAs
<loc::ConcreteInt
>())
258 return LV
->getValue() == I
;
259 if (std::optional
<nonloc::ConcreteInt
> NV
= getAs
<nonloc::ConcreteInt
>())
260 return NV
->getValue() == I
;
264 bool SVal::isZeroConstant() const {
265 return isConstant(0);
268 //===----------------------------------------------------------------------===//
270 //===----------------------------------------------------------------------===//
272 LLVM_DUMP_METHOD
void SVal::dump() const { dumpToStream(llvm::errs()); }
274 void SVal::printJson(raw_ostream
&Out
, bool AddQuotes
) const {
276 llvm::raw_string_ostream
TempOut(Buf
);
278 dumpToStream(TempOut
);
280 Out
<< JsonFormat(TempOut
.str(), AddQuotes
);
283 void SVal::dumpToStream(raw_ostream
&os
) const {
284 switch (getBaseKind()) {
289 castAs
<NonLoc
>().dumpToStream(os
);
292 castAs
<Loc
>().dumpToStream(os
);
294 case UndefinedValKind
:
300 void NonLoc::dumpToStream(raw_ostream
&os
) const {
301 switch (getSubKind()) {
302 case nonloc::ConcreteIntKind
: {
303 const auto &Value
= castAs
<nonloc::ConcreteInt
>().getValue();
304 os
<< Value
<< ' ' << (Value
.isSigned() ? 'S' : 'U')
305 << Value
.getBitWidth() << 'b';
308 case nonloc::SymbolValKind
:
309 os
<< castAs
<nonloc::SymbolVal
>().getSymbol();
312 case nonloc::LocAsIntegerKind
: {
313 const nonloc::LocAsInteger
& C
= castAs
<nonloc::LocAsInteger
>();
314 os
<< C
.getLoc() << " [as " << C
.getNumBits() << " bit integer]";
317 case nonloc::CompoundValKind
: {
318 const nonloc::CompoundVal
& C
= castAs
<nonloc::CompoundVal
>();
319 os
<< "compoundVal{";
321 for (const auto &I
: C
) {
323 os
<< ' '; first
= false;
333 case nonloc::LazyCompoundValKind
: {
334 const nonloc::LazyCompoundVal
&C
= castAs
<nonloc::LazyCompoundVal
>();
335 os
<< "lazyCompoundVal{" << const_cast<void *>(C
.getStore())
336 << ',' << C
.getRegion()
340 case nonloc::PointerToMemberKind
: {
341 os
<< "pointerToMember{";
342 const nonloc::PointerToMember
&CastRes
=
343 castAs
<nonloc::PointerToMember
>();
344 if (CastRes
.getDecl())
345 os
<< "|" << CastRes
.getDecl()->getQualifiedNameAsString() << "|";
347 for (const auto &I
: CastRes
) {
349 os
<< ' '; first
= false;
361 assert(false && "Pretty-printed not implemented for this NonLoc.");
366 void Loc::dumpToStream(raw_ostream
&os
) const {
367 switch (getSubKind()) {
368 case loc::ConcreteIntKind
:
369 os
<< castAs
<loc::ConcreteInt
>().getValue().getZExtValue() << " (Loc)";
371 case loc::GotoLabelKind
:
372 os
<< "&&" << castAs
<loc::GotoLabel
>().getLabel()->getName();
374 case loc::MemRegionValKind
:
375 os
<< '&' << castAs
<loc::MemRegionVal
>().getRegion()->getString();
378 llvm_unreachable("Pretty-printing not implemented for this Loc.");