/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/Decl.h" |
16 | | #include "clang/AST/DeclCXX.h" |
17 | | #include "clang/AST/Expr.h" |
18 | | #include "clang/AST/Type.h" |
19 | | #include "clang/Basic/JsonSupport.h" |
20 | | #include "clang/Basic/LLVM.h" |
21 | | #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" |
22 | | #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" |
23 | | #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" |
24 | | #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" |
25 | | #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" |
26 | | #include "llvm/ADT/Optional.h" |
27 | | #include "llvm/Support/Casting.h" |
28 | | #include "llvm/Support/Compiler.h" |
29 | | #include "llvm/Support/ErrorHandling.h" |
30 | | #include "llvm/Support/raw_ostream.h" |
31 | | #include <cassert> |
32 | | |
33 | | using namespace clang; |
34 | | using namespace ento; |
35 | | |
36 | | //===----------------------------------------------------------------------===// |
37 | | // Symbol iteration within an SVal. |
38 | | //===----------------------------------------------------------------------===// |
39 | | |
40 | | //===----------------------------------------------------------------------===// |
41 | | // Utility methods. |
42 | | //===----------------------------------------------------------------------===// |
43 | | |
44 | 0 | bool SVal::hasConjuredSymbol() const { |
45 | 0 | if (Optional<nonloc::SymbolVal> SV = getAs<nonloc::SymbolVal>()) { |
46 | 0 | SymbolRef sym = SV->getSymbol(); |
47 | 0 | if (isa<SymbolConjured>(sym)) |
48 | 0 | return true; |
49 | 0 | } |
50 | | |
51 | 0 | if (Optional<loc::MemRegionVal> RV = getAs<loc::MemRegionVal>()) { |
52 | 0 | const MemRegion *R = RV->getRegion(); |
53 | 0 | if (const auto *SR = dyn_cast<SymbolicRegion>(R)) { |
54 | 0 | SymbolRef sym = SR->getSymbol(); |
55 | 0 | if (isa<SymbolConjured>(sym)) |
56 | 0 | return true; |
57 | 0 | } |
58 | 0 | } |
59 | | |
60 | 0 | return false; |
61 | 0 | } |
62 | | |
63 | 109k | const FunctionDecl *SVal::getAsFunctionDecl() const { |
64 | 109k | if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) { |
65 | 109k | const MemRegion* R = X->getRegion(); |
66 | 109k | if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>()) |
67 | 108k | if (const auto *FD = dyn_cast<FunctionDecl>(CTR->getDecl())) |
68 | 108k | return FD; |
69 | 1.24k | } |
70 | | |
71 | 1.24k | if (auto X = getAs<nonloc::PointerToMember>()) { |
72 | 405 | if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(X->getDecl())) |
73 | 405 | return MD; |
74 | 836 | } |
75 | 836 | return nullptr; |
76 | 836 | } |
77 | | |
78 | | /// If this SVal is a location (subclasses Loc) and wraps a symbol, |
79 | | /// return that SymbolRef. Otherwise return 0. |
80 | | /// |
81 | | /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element |
82 | | /// region. If that is the case, gets the underlining region. |
83 | | /// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic, |
84 | | /// the first symbolic parent region is returned. |
85 | 2.36M | SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const { |
86 | | // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? |
87 | 2.36M | if (const MemRegion *R = getAsRegion()) |
88 | 1.27M | if (const SymbolicRegion *SymR = |
89 | 357k | IncludeBaseRegions ? R->getSymbolicBase() |
90 | 357k | : dyn_cast<SymbolicRegion>(R->StripCasts())) |
91 | 357k | return SymR->getSymbol(); |
92 | | |
93 | 2.00M | return nullptr; |
94 | 2.00M | } |
95 | | |
96 | | /// Get the symbol in the SVal or its base region. |
97 | 75.7k | SymbolRef SVal::getLocSymbolInBase() const { |
98 | 75.7k | Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>(); |
99 | | |
100 | 75.7k | if (!X) |
101 | 4 | return nullptr; |
102 | | |
103 | 75.7k | const MemRegion *R = X->getRegion(); |
104 | | |
105 | 175k | while (const auto *SR = dyn_cast<SubRegion>(R)) { |
106 | 113k | if (const auto *SymR = dyn_cast<SymbolicRegion>(SR)) |
107 | 13.6k | return SymR->getSymbol(); |
108 | 99.7k | else |
109 | 99.7k | R = SR->getSuperRegion(); |
110 | 113k | } |
111 | | |
112 | 62.1k | return nullptr; |
113 | 75.7k | } |
114 | | |
115 | | /// If this SVal wraps a symbol return that SymbolRef. |
116 | | /// Otherwise, return 0. |
117 | | /// |
118 | | /// Casts are ignored during lookup. |
119 | | /// \param IncludeBaseRegions The boolean that controls whether the search |
120 | | /// should continue to the base regions if the region is not symbolic. |
121 | 3.81M | SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const { |
122 | | // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? |
123 | 3.81M | if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>()) |
124 | 1.49M | return X->getSymbol(); |
125 | | |
126 | 2.32M | return getAsLocSymbol(IncludeBaseRegions); |
127 | 2.32M | } |
128 | | |
129 | 5.71M | const MemRegion *SVal::getAsRegion() const { |
130 | 5.71M | if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) |
131 | 3.23M | return X->getRegion(); |
132 | | |
133 | 2.47M | if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>()) |
134 | 526 | return X->getLoc().getAsRegion(); |
135 | | |
136 | 2.47M | return nullptr; |
137 | 2.47M | } |
138 | | |
139 | 517 | const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const { |
140 | 517 | const MemRegion *R = getRegion(); |
141 | 517 | return R ? R->StripCasts(StripBaseCasts) : nullptr0 ; |
142 | 517 | } |
143 | | |
144 | 69.2k | const void *nonloc::LazyCompoundVal::getStore() const { |
145 | 69.2k | return static_cast<const LazyCompoundValData*>(Data)->getStore(); |
146 | 69.2k | } |
147 | | |
148 | 92.1k | const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const { |
149 | 92.1k | return static_cast<const LazyCompoundValData*>(Data)->getRegion(); |
150 | 92.1k | } |
151 | | |
152 | 90 | bool nonloc::PointerToMember::isNullMemberPointer() const { |
153 | 90 | return getPTMData().isNull(); |
154 | 90 | } |
155 | | |
156 | 461 | const NamedDecl *nonloc::PointerToMember::getDecl() const { |
157 | 461 | const auto PTMD = this->getPTMData(); |
158 | 461 | if (PTMD.isNull()) |
159 | 0 | return nullptr; |
160 | | |
161 | 461 | const NamedDecl *ND = nullptr; |
162 | 461 | if (PTMD.is<const NamedDecl *>()) |
163 | 418 | ND = PTMD.get<const NamedDecl *>(); |
164 | 43 | else |
165 | 43 | ND = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl(); |
166 | | |
167 | 461 | return ND; |
168 | 461 | } |
169 | | |
170 | | //===----------------------------------------------------------------------===// |
171 | | // Other Iterators. |
172 | | //===----------------------------------------------------------------------===// |
173 | | |
174 | 3.18k | nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const { |
175 | 3.18k | return getValue()->begin(); |
176 | 3.18k | } |
177 | | |
178 | 3.17k | nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const { |
179 | 3.17k | return getValue()->end(); |
180 | 3.17k | } |
181 | | |
182 | 14 | nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const { |
183 | 14 | const PTMDataType PTMD = getPTMData(); |
184 | 14 | if (PTMD.is<const NamedDecl *>()) |
185 | 7 | return {}; |
186 | 7 | return PTMD.get<const PointerToMemberData *>()->begin(); |
187 | 7 | } |
188 | | |
189 | 14 | nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const { |
190 | 14 | const PTMDataType PTMD = getPTMData(); |
191 | 14 | if (PTMD.is<const NamedDecl *>()) |
192 | 7 | return {}; |
193 | 7 | return PTMD.get<const PointerToMemberData *>()->end(); |
194 | 7 | } |
195 | | |
196 | | //===----------------------------------------------------------------------===// |
197 | | // Useful predicates. |
198 | | //===----------------------------------------------------------------------===// |
199 | | |
200 | 722k | bool SVal::isConstant() const { |
201 | 722k | return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>()695k ; |
202 | 722k | } |
203 | | |
204 | 223k | bool SVal::isConstant(int I) const { |
205 | 223k | if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>()) |
206 | 7.67k | return LV->getValue() == I; |
207 | 215k | if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>()) |
208 | 73.2k | return NV->getValue() == I; |
209 | 142k | return false; |
210 | 142k | } |
211 | | |
212 | 223k | bool SVal::isZeroConstant() const { |
213 | 223k | return isConstant(0); |
214 | 223k | } |
215 | | |
216 | | //===----------------------------------------------------------------------===// |
217 | | // Transfer function dispatch for Non-Locs. |
218 | | //===----------------------------------------------------------------------===// |
219 | | |
220 | | SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder, |
221 | | BinaryOperator::Opcode Op, |
222 | 0 | const nonloc::ConcreteInt& R) const { |
223 | 0 | const llvm::APSInt* X = |
224 | 0 | svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue()); |
225 | |
|
226 | 0 | if (X) |
227 | 0 | return nonloc::ConcreteInt(*X); |
228 | 0 | else |
229 | 0 | return UndefinedVal(); |
230 | 0 | } |
231 | | |
232 | | nonloc::ConcreteInt |
233 | 992 | nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const { |
234 | 992 | return svalBuilder.makeIntVal(~getValue()); |
235 | 992 | } |
236 | | |
237 | | nonloc::ConcreteInt |
238 | 1.52k | nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const { |
239 | 1.52k | return svalBuilder.makeIntVal(-getValue()); |
240 | 1.52k | } |
241 | | |
242 | | //===----------------------------------------------------------------------===// |
243 | | // Transfer function dispatch for Locs. |
244 | | //===----------------------------------------------------------------------===// |
245 | | |
246 | | SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals, |
247 | | BinaryOperator::Opcode Op, |
248 | 18 | const loc::ConcreteInt& R) const { |
249 | 18 | assert(BinaryOperator::isComparisonOp(Op) || Op == BO_Sub); |
250 | | |
251 | 18 | const llvm::APSInt *X = BasicVals.evalAPSInt(Op, getValue(), R.getValue()); |
252 | | |
253 | 18 | if (X) |
254 | 18 | return nonloc::ConcreteInt(*X); |
255 | 0 | else |
256 | 0 | return UndefinedVal(); |
257 | 18 | } |
258 | | |
259 | | //===----------------------------------------------------------------------===// |
260 | | // Pretty-Printing. |
261 | | //===----------------------------------------------------------------------===// |
262 | | |
263 | 0 | LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); } |
264 | | |
265 | 274 | void SVal::printJson(raw_ostream &Out, bool AddQuotes) const { |
266 | 274 | std::string Buf; |
267 | 274 | llvm::raw_string_ostream TempOut(Buf); |
268 | | |
269 | 274 | dumpToStream(TempOut); |
270 | | |
271 | 274 | Out << JsonFormat(TempOut.str(), AddQuotes); |
272 | 274 | } |
273 | | |
274 | 410 | void SVal::dumpToStream(raw_ostream &os) const { |
275 | 410 | switch (getBaseKind()) { |
276 | 2 | case UnknownValKind: |
277 | 2 | os << "Unknown"; |
278 | 2 | break; |
279 | 152 | case NonLocKind: |
280 | 152 | castAs<NonLoc>().dumpToStream(os); |
281 | 152 | break; |
282 | 256 | case LocKind: |
283 | 256 | castAs<Loc>().dumpToStream(os); |
284 | 256 | break; |
285 | 0 | case UndefinedValKind: |
286 | 0 | os << "Undefined"; |
287 | 0 | break; |
288 | 410 | } |
289 | 410 | } |
290 | | |
291 | 152 | void NonLoc::dumpToStream(raw_ostream &os) const { |
292 | 152 | switch (getSubKind()) { |
293 | 97 | case nonloc::ConcreteIntKind: { |
294 | 97 | const auto &Value = castAs<nonloc::ConcreteInt>().getValue(); |
295 | 96 | os << Value << ' ' << (Value.isSigned() ? 'S' : 'U'1 ) |
296 | 97 | << Value.getBitWidth() << 'b'; |
297 | 97 | break; |
298 | 0 | } |
299 | 45 | case nonloc::SymbolValKind: |
300 | 45 | os << castAs<nonloc::SymbolVal>().getSymbol(); |
301 | 45 | break; |
302 | | |
303 | 0 | case nonloc::LocAsIntegerKind: { |
304 | 0 | const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>(); |
305 | 0 | os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]"; |
306 | 0 | break; |
307 | 0 | } |
308 | 0 | case nonloc::CompoundValKind: { |
309 | 0 | const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>(); |
310 | 0 | os << "compoundVal{"; |
311 | 0 | bool first = true; |
312 | 0 | for (const auto &I : C) { |
313 | 0 | if (first) { |
314 | 0 | os << ' '; first = false; |
315 | 0 | } |
316 | 0 | else |
317 | 0 | os << ", "; |
318 | |
|
319 | 0 | I.dumpToStream(os); |
320 | 0 | } |
321 | 0 | os << "}"; |
322 | 0 | break; |
323 | 0 | } |
324 | 10 | case nonloc::LazyCompoundValKind: { |
325 | 10 | const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>(); |
326 | 10 | os << "lazyCompoundVal{" << const_cast<void *>(C.getStore()) |
327 | 10 | << ',' << C.getRegion() |
328 | 10 | << '}'; |
329 | 10 | break; |
330 | 0 | } |
331 | 0 | case nonloc::PointerToMemberKind: { |
332 | 0 | os << "pointerToMember{"; |
333 | 0 | const nonloc::PointerToMember &CastRes = |
334 | 0 | castAs<nonloc::PointerToMember>(); |
335 | 0 | if (CastRes.getDecl()) |
336 | 0 | os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|"; |
337 | 0 | bool first = true; |
338 | 0 | for (const auto &I : CastRes) { |
339 | 0 | if (first) { |
340 | 0 | os << ' '; first = false; |
341 | 0 | } |
342 | 0 | else |
343 | 0 | os << ", "; |
344 | |
|
345 | 0 | os << (*I).getType().getAsString(); |
346 | 0 | } |
347 | |
|
348 | 0 | os << '}'; |
349 | 0 | break; |
350 | 0 | } |
351 | 0 | default: |
352 | 0 | assert(false && "Pretty-printed not implemented for this NonLoc."); |
353 | 0 | break; |
354 | 152 | } |
355 | 152 | } |
356 | | |
357 | 256 | void Loc::dumpToStream(raw_ostream &os) const { |
358 | 256 | switch (getSubKind()) { |
359 | 66 | case loc::ConcreteIntKind: |
360 | 66 | os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)"; |
361 | 66 | break; |
362 | 0 | case loc::GotoLabelKind: |
363 | 0 | os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName(); |
364 | 0 | break; |
365 | 190 | case loc::MemRegionValKind: |
366 | 190 | os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString(); |
367 | 190 | break; |
368 | 0 | default: |
369 | 0 | llvm_unreachable("Pretty-printing not implemented for this Loc."); |
370 | 256 | } |
371 | 256 | } |