/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp
Line | Count | Source (jump to first uncovered line) |
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/Casting.h" |
29 | | #include "llvm/Support/Compiler.h" |
30 | | #include "llvm/Support/ErrorHandling.h" |
31 | | #include "llvm/Support/raw_ostream.h" |
32 | | #include <cassert> |
33 | | #include <optional> |
34 | | |
35 | | using namespace clang; |
36 | | using namespace ento; |
37 | | |
38 | | //===----------------------------------------------------------------------===// |
39 | | // Symbol iteration within an SVal. |
40 | | //===----------------------------------------------------------------------===// |
41 | | |
42 | | //===----------------------------------------------------------------------===// |
43 | | // Utility methods. |
44 | | //===----------------------------------------------------------------------===// |
45 | | |
46 | 26.9k | const FunctionDecl *SVal::getAsFunctionDecl() const { |
47 | 26.9k | if (std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) { |
48 | 26.4k | const MemRegion* R = X->getRegion(); |
49 | 26.4k | if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>()) |
50 | 25.3k | if (const auto *FD = dyn_cast<FunctionDecl>(CTR->getDecl())) |
51 | 25.3k | return FD; |
52 | 26.4k | } |
53 | | |
54 | 1.56k | if (auto X = getAs<nonloc::PointerToMember>()) { |
55 | 410 | if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(X->getDecl())) |
56 | 410 | return MD; |
57 | 410 | } |
58 | 1.15k | return nullptr; |
59 | 1.56k | } |
60 | | |
61 | | /// If this SVal is a location (subclasses Loc) and wraps a symbol, |
62 | | /// return that SymbolRef. Otherwise return 0. |
63 | | /// |
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 | 2.27M | SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const { |
69 | | // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? |
70 | 2.27M | if (const MemRegion *R = getAsRegion()) |
71 | 918k | if (const SymbolicRegion *SymR = |
72 | 918k | IncludeBaseRegions ? R->getSymbolicBase() |
73 | 918k | : dyn_cast<SymbolicRegion>(R->StripCasts())) |
74 | 502k | return SymR->getSymbol(); |
75 | | |
76 | 1.76M | return nullptr; |
77 | 2.27M | } |
78 | | |
79 | | /// Get the symbol in the SVal or its base region. |
80 | 76.9k | SymbolRef SVal::getLocSymbolInBase() const { |
81 | 76.9k | std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>(); |
82 | | |
83 | 76.9k | if (!X) |
84 | 4 | return nullptr; |
85 | | |
86 | 76.9k | const MemRegion *R = X->getRegion(); |
87 | | |
88 | 180k | while (const auto *SR = dyn_cast<SubRegion>(R)) { |
89 | 116k | if (const auto *SymR = dyn_cast<SymbolicRegion>(SR)) |
90 | 13.7k | return SymR->getSymbol(); |
91 | 103k | else |
92 | 103k | R = SR->getSuperRegion(); |
93 | 116k | } |
94 | | |
95 | 63.2k | return nullptr; |
96 | 76.9k | } |
97 | | |
98 | | /// If this SVal wraps a symbol return that SymbolRef. |
99 | | /// Otherwise, return 0. |
100 | | /// |
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 | 9.38M | SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const { |
105 | | // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? |
106 | 9.38M | if (std::optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>()) |
107 | 7.15M | return X->getSymbol(); |
108 | | |
109 | 2.22M | return getAsLocSymbol(IncludeBaseRegions); |
110 | 9.38M | } |
111 | | |
112 | 536 | const llvm::APSInt *SVal::getAsInteger() const { |
113 | 536 | if (auto CI = getAs<nonloc::ConcreteInt>()) |
114 | 515 | return &CI->getValue(); |
115 | 21 | if (auto CI = getAs<loc::ConcreteInt>()) |
116 | 0 | return &CI->getValue(); |
117 | 21 | return nullptr; |
118 | 21 | } |
119 | | |
120 | 6.33M | const MemRegion *SVal::getAsRegion() const { |
121 | 6.33M | if (std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) |
122 | 3.34M | return X->getRegion(); |
123 | | |
124 | 2.98M | if (std::optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>()) |
125 | 1.53k | return X->getLoc().getAsRegion(); |
126 | | |
127 | 2.98M | return nullptr; |
128 | 2.98M | } |
129 | | |
130 | | namespace { |
131 | | class TypeRetrievingVisitor |
132 | | : public FullSValVisitor<TypeRetrievingVisitor, QualType> { |
133 | | private: |
134 | | const ASTContext &Context; |
135 | | |
136 | | public: |
137 | 237k | TypeRetrievingVisitor(const ASTContext &Context) : Context(Context) {} |
138 | | |
139 | 66.7k | QualType VisitLocMemRegionVal(loc::MemRegionVal MRV) { |
140 | 66.7k | return Visit(MRV.getRegion()); |
141 | 66.7k | } |
142 | 138 | QualType VisitLocGotoLabel(loc::GotoLabel GL) { |
143 | 138 | return QualType{Context.VoidPtrTy}; |
144 | 138 | } |
145 | 170k | template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) { |
146 | 170k | const llvm::APSInt &Value = CI.getValue(); |
147 | 170k | if (1 == Value.getBitWidth()) |
148 | 42 | return Context.BoolTy; |
149 | 169k | return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned()); |
150 | 170k | } SVals.cpp:clang::QualType (anonymous namespace)::TypeRetrievingVisitor::VisitConcreteInt<clang::ento::loc::ConcreteInt>(clang::ento::loc::ConcreteInt) Line | Count | Source | 145 | 43.2k | template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) { | 146 | 43.2k | const llvm::APSInt &Value = CI.getValue(); | 147 | 43.2k | if (1 == Value.getBitWidth()) | 148 | 0 | return Context.BoolTy; | 149 | 43.2k | return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned()); | 150 | 43.2k | } |
SVals.cpp:clang::QualType (anonymous namespace)::TypeRetrievingVisitor::VisitConcreteInt<clang::ento::nonloc::ConcreteInt>(clang::ento::nonloc::ConcreteInt) Line | Count | Source | 145 | 126k | template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) { | 146 | 126k | const llvm::APSInt &Value = CI.getValue(); | 147 | 126k | if (1 == Value.getBitWidth()) | 148 | 42 | return Context.BoolTy; | 149 | 126k | return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned()); | 150 | 126k | } |
|
151 | 43.2k | QualType VisitLocConcreteInt(loc::ConcreteInt CI) { |
152 | 43.2k | return VisitConcreteInt(CI); |
153 | 43.2k | } |
154 | 126k | QualType VisitNonLocConcreteInt(nonloc::ConcreteInt CI) { |
155 | 126k | return VisitConcreteInt(CI); |
156 | 126k | } |
157 | 84 | QualType VisitNonLocLocAsInteger(nonloc::LocAsInteger LI) { |
158 | 84 | QualType NestedType = Visit(LI.getLoc()); |
159 | 84 | if (NestedType.isNull()) |
160 | 0 | return NestedType; |
161 | | |
162 | 84 | return Context.getIntTypeForBitwidth(LI.getNumBits(), |
163 | 84 | NestedType->isSignedIntegerType()); |
164 | 84 | } |
165 | 126 | QualType VisitNonLocCompoundVal(nonloc::CompoundVal CV) { |
166 | 126 | return CV.getValue()->getType(); |
167 | 126 | } |
168 | 21 | QualType VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal LCV) { |
169 | 21 | return LCV.getRegion()->getValueType(); |
170 | 21 | } |
171 | 298 | QualType VisitNonLocSymbolVal(nonloc::SymbolVal SV) { |
172 | 298 | return Visit(SV.getSymbol()); |
173 | 298 | } |
174 | 41.5k | QualType VisitSymbolicRegion(const SymbolicRegion *SR) { |
175 | 41.5k | return Visit(SR->getSymbol()); |
176 | 41.5k | } |
177 | 70 | QualType VisitAllocaRegion(const AllocaRegion *) { |
178 | 70 | return QualType{Context.VoidPtrTy}; |
179 | 70 | } |
180 | 25.0k | QualType VisitTypedRegion(const TypedRegion *TR) { |
181 | 25.0k | return TR->getLocationType(); |
182 | 25.0k | } |
183 | 41.8k | QualType VisitSymExpr(const SymExpr *SE) { return SE->getType(); } |
184 | | }; |
185 | | } // end anonymous namespace |
186 | | |
187 | 237k | QualType SVal::getType(const ASTContext &Context) const { |
188 | 237k | TypeRetrievingVisitor TRV{Context}; |
189 | 237k | return TRV.Visit(*this); |
190 | 237k | } |
191 | | |
192 | 517 | const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const { |
193 | 517 | return getRegion()->StripCasts(StripBaseCasts); |
194 | 517 | } |
195 | | |
196 | 69.7k | const void *nonloc::LazyCompoundVal::getStore() const { |
197 | 69.7k | return static_cast<const LazyCompoundValData*>(Data)->getStore(); |
198 | 69.7k | } |
199 | | |
200 | 98.3k | const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const { |
201 | 98.3k | return static_cast<const LazyCompoundValData*>(Data)->getRegion(); |
202 | 98.3k | } |
203 | | |
204 | 95 | bool nonloc::PointerToMember::isNullMemberPointer() const { |
205 | 95 | return getPTMData().isNull(); |
206 | 95 | } |
207 | | |
208 | 469 | const NamedDecl *nonloc::PointerToMember::getDecl() const { |
209 | 469 | const auto PTMD = this->getPTMData(); |
210 | 469 | if (PTMD.isNull()) |
211 | 0 | return nullptr; |
212 | | |
213 | 469 | const NamedDecl *ND = nullptr; |
214 | 469 | if (PTMD.is<const NamedDecl *>()) |
215 | 421 | ND = PTMD.get<const NamedDecl *>(); |
216 | 48 | else |
217 | 48 | ND = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl(); |
218 | | |
219 | 469 | return ND; |
220 | 469 | } |
221 | | |
222 | | //===----------------------------------------------------------------------===// |
223 | | // Other Iterators. |
224 | | //===----------------------------------------------------------------------===// |
225 | | |
226 | 4.87k | nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const { |
227 | 4.87k | return getValue()->begin(); |
228 | 4.87k | } |
229 | | |
230 | 4.86k | nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const { |
231 | 4.86k | return getValue()->end(); |
232 | 4.86k | } |
233 | | |
234 | 17 | nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const { |
235 | 17 | const PTMDataType PTMD = getPTMData(); |
236 | 17 | if (PTMD.is<const NamedDecl *>()) |
237 | 7 | return {}; |
238 | 10 | return PTMD.get<const PointerToMemberData *>()->begin(); |
239 | 17 | } |
240 | | |
241 | 17 | nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const { |
242 | 17 | const PTMDataType PTMD = getPTMData(); |
243 | 17 | if (PTMD.is<const NamedDecl *>()) |
244 | 7 | return {}; |
245 | 10 | return PTMD.get<const PointerToMemberData *>()->end(); |
246 | 17 | } |
247 | | |
248 | | //===----------------------------------------------------------------------===// |
249 | | // Useful predicates. |
250 | | //===----------------------------------------------------------------------===// |
251 | | |
252 | 123k | bool SVal::isConstant() const { |
253 | 123k | return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>()84.9k ; |
254 | 123k | } |
255 | | |
256 | 260k | bool SVal::isConstant(int I) const { |
257 | 260k | if (std::optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>()) |
258 | 7.07k | return LV->getValue() == I; |
259 | 252k | if (std::optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>()) |
260 | 78.4k | return NV->getValue() == I; |
261 | 174k | return false; |
262 | 252k | } |
263 | | |
264 | 260k | bool SVal::isZeroConstant() const { |
265 | 260k | return isConstant(0); |
266 | 260k | } |
267 | | |
268 | | //===----------------------------------------------------------------------===// |
269 | | // Pretty-Printing. |
270 | | //===----------------------------------------------------------------------===// |
271 | | |
272 | 0 | LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); } |
273 | | |
274 | 352 | void SVal::printJson(raw_ostream &Out, bool AddQuotes) const { |
275 | 352 | std::string Buf; |
276 | 352 | llvm::raw_string_ostream TempOut(Buf); |
277 | | |
278 | 352 | dumpToStream(TempOut); |
279 | | |
280 | 352 | Out << JsonFormat(TempOut.str(), AddQuotes); |
281 | 352 | } |
282 | | |
283 | 4.13k | void SVal::dumpToStream(raw_ostream &os) const { |
284 | 4.13k | switch (getBaseKind()) { |
285 | 19 | case UnknownValKind: |
286 | 19 | os << "Unknown"; |
287 | 19 | break; |
288 | 3.62k | case NonLocKind: |
289 | 3.62k | castAs<NonLoc>().dumpToStream(os); |
290 | 3.62k | break; |
291 | 476 | case LocKind: |
292 | 476 | castAs<Loc>().dumpToStream(os); |
293 | 476 | break; |
294 | 16 | case UndefinedValKind: |
295 | 16 | os << "Undefined"; |
296 | 16 | break; |
297 | 4.13k | } |
298 | 4.13k | } |
299 | | |
300 | 3.62k | void NonLoc::dumpToStream(raw_ostream &os) const { |
301 | 3.62k | switch (getSubKind()) { |
302 | 521 | case nonloc::ConcreteIntKind: { |
303 | 521 | const auto &Value = castAs<nonloc::ConcreteInt>().getValue(); |
304 | 521 | os << Value << ' ' << (Value.isSigned() ? 'S'518 : 'U'3 ) |
305 | 521 | << Value.getBitWidth() << 'b'; |
306 | 521 | break; |
307 | 0 | } |
308 | 3.08k | case nonloc::SymbolValKind: |
309 | 3.08k | os << castAs<nonloc::SymbolVal>().getSymbol(); |
310 | 3.08k | break; |
311 | | |
312 | 9 | case nonloc::LocAsIntegerKind: { |
313 | 9 | const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>(); |
314 | 9 | os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]"; |
315 | 9 | break; |
316 | 0 | } |
317 | 0 | case nonloc::CompoundValKind: { |
318 | 0 | const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>(); |
319 | 0 | os << "compoundVal{"; |
320 | 0 | bool first = true; |
321 | 0 | for (const auto &I : C) { |
322 | 0 | if (first) { |
323 | 0 | os << ' '; first = false; |
324 | 0 | } |
325 | 0 | else |
326 | 0 | os << ", "; |
327 | |
|
328 | 0 | I.dumpToStream(os); |
329 | 0 | } |
330 | 0 | os << "}"; |
331 | 0 | break; |
332 | 0 | } |
333 | 11 | case nonloc::LazyCompoundValKind: { |
334 | 11 | const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>(); |
335 | 11 | os << "lazyCompoundVal{" << const_cast<void *>(C.getStore()) |
336 | 11 | << ',' << C.getRegion() |
337 | 11 | << '}'; |
338 | 11 | break; |
339 | 0 | } |
340 | 0 | case nonloc::PointerToMemberKind: { |
341 | 0 | os << "pointerToMember{"; |
342 | 0 | const nonloc::PointerToMember &CastRes = |
343 | 0 | castAs<nonloc::PointerToMember>(); |
344 | 0 | if (CastRes.getDecl()) |
345 | 0 | os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|"; |
346 | 0 | bool first = true; |
347 | 0 | for (const auto &I : CastRes) { |
348 | 0 | if (first) { |
349 | 0 | os << ' '; first = false; |
350 | 0 | } |
351 | 0 | else |
352 | 0 | os << ", "; |
353 | |
|
354 | 0 | os << I->getType(); |
355 | 0 | } |
356 | |
|
357 | 0 | os << '}'; |
358 | 0 | break; |
359 | 0 | } |
360 | 0 | default: |
361 | 0 | assert(false && "Pretty-printed not implemented for this NonLoc."); |
362 | 0 | break; |
363 | 3.62k | } |
364 | 3.62k | } |
365 | | |
366 | 476 | void Loc::dumpToStream(raw_ostream &os) const { |
367 | 476 | switch (getSubKind()) { |
368 | 70 | case loc::ConcreteIntKind: |
369 | 70 | os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)"; |
370 | 70 | break; |
371 | 0 | case loc::GotoLabelKind: |
372 | 0 | os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName(); |
373 | 0 | break; |
374 | 406 | case loc::MemRegionValKind: |
375 | 406 | os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString(); |
376 | 406 | break; |
377 | 0 | default: |
378 | 0 | llvm_unreachable("Pretty-printing not implemented for this Loc."); |
379 | 476 | } |
380 | 476 | } |