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
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/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
45const FunctionDecl *SVal::getAsFunctionDecl() const {
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>(Val: CTR->getDecl()))
50 return FD;
51 }
52
53 if (auto X = getAs<nonloc::PointerToMember>()) {
54 if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Val: 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>(Val: R->StripCasts()))
73 return SymR->getSymbol();
74
75 return nullptr;
76}
77
78/// Get the symbol in the SVal or its base region.
79SymbolRef SVal::getLocSymbolInBase() const {
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>(Val: R)) {
88 if (const auto *SymR = dyn_cast<SymbolicRegion>(Val: 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
119const MemRegion *SVal::getAsRegion() const {
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(R: 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(DestWidth: Value.getBitWidth(), Signed: Value.isSigned());
149 }
150 QualType VisitLocAsInteger(nonloc::LocAsInteger LI) {
151 QualType NestedType = Visit(V: LI.getLoc());
152 if (NestedType.isNull())
153 return NestedType;
154
155 return Context.getIntTypeForBitwidth(DestWidth: LI.getNumBits(),
156 Signed: 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(S: SV.getSymbol());
166 }
167 QualType VisitSymbolicRegion(const SymbolicRegion *SR) {
168 return Visit(S: 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(V: *this);
183}
184
185const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const {
186 return getRegion()->StripCasts(StripBaseAndDerivedCasts: StripBaseCasts);
187}
188
189const void *nonloc::LazyCompoundVal::getStore() const {
190 return static_cast<const LazyCompoundValData*>(Data)->getStore();
191}
192
193const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const {
194 return static_cast<const LazyCompoundValData*>(Data)->getRegion();
195}
196
197bool nonloc::PointerToMember::isNullMemberPointer() const {
198 return getPTMData().isNull();
199}
200
201const NamedDecl *nonloc::PointerToMember::getDecl() const {
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 *>(Val: PTMD))
208 ND = NDP;
209 else
210 ND = cast<const PointerToMemberData *>(Val: PTMD)->getDeclaratorDecl();
211
212 return ND;
213}
214
215//===----------------------------------------------------------------------===//
216// Other Iterators.
217//===----------------------------------------------------------------------===//
218
219nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
220 return getValue()->begin();
221}
222
223nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
224 return getValue()->end();
225}
226
227nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const {
228 const PTMDataType PTMD = getPTMData();
229 if (isa<const NamedDecl *>(Val: PTMD))
230 return {};
231 return cast<const PointerToMemberData *>(Val: PTMD)->begin();
232}
233
234nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const {
235 const PTMDataType PTMD = getPTMData();
236 if (isa<const NamedDecl *>(Val: PTMD))
237 return {};
238 return cast<const PointerToMemberData *>(Val: 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
257bool SVal::isZeroConstant() const {
258 return isConstant(I: 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(OS&: 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(OS&: TempOut);
289
290 Out << JsonFormat(RawSR: 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(V: *this)) {
303 castAs<NonLoc>().dumpToStream(Out&: os);
304 return;
305 }
306 if (Loc::classof(V: *this)) {
307 castAs<Loc>().dumpToStream(Out&: 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}
394

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/lib/StaticAnalyzer/Core/SVals.cpp