]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp
zfs: merge openzfs/zfs@6a6bd4939 (zfs-2.1-release) into stable/13
[FreeBSD/FreeBSD.git] / contrib / llvm-project / clang / lib / StaticAnalyzer / Core / SVals.cpp
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/ADT/Optional.h"
29 #include "llvm/Support/Casting.h"
30 #include "llvm/Support/Compiler.h"
31 #include "llvm/Support/ErrorHandling.h"
32 #include "llvm/Support/raw_ostream.h"
33 #include <cassert>
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 bool SVal::hasConjuredSymbol() const {
47   if (Optional<nonloc::SymbolVal> SV = getAs<nonloc::SymbolVal>()) {
48     SymbolRef sym = SV->getSymbol();
49     if (isa<SymbolConjured>(sym))
50       return true;
51   }
52
53   if (Optional<loc::MemRegionVal> RV = getAs<loc::MemRegionVal>()) {
54     const MemRegion *R = RV->getRegion();
55     if (const auto *SR = dyn_cast<SymbolicRegion>(R)) {
56       SymbolRef sym = SR->getSymbol();
57       if (isa<SymbolConjured>(sym))
58         return true;
59     }
60   }
61
62   return false;
63 }
64
65 const FunctionDecl *SVal::getAsFunctionDecl() const {
66   if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
67     const MemRegion* R = X->getRegion();
68     if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>())
69       if (const auto *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
70         return FD;
71   }
72
73   if (auto X = getAs<nonloc::PointerToMember>()) {
74     if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(X->getDecl()))
75       return MD;
76   }
77   return nullptr;
78 }
79
80 /// If this SVal is a location (subclasses Loc) and wraps a symbol,
81 /// return that SymbolRef.  Otherwise return 0.
82 ///
83 /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
84 /// region. If that is the case, gets the underlining region.
85 /// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic,
86 /// the first symbolic parent region is returned.
87 SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const {
88   // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
89   if (const MemRegion *R = getAsRegion())
90     if (const SymbolicRegion *SymR =
91             IncludeBaseRegions ? R->getSymbolicBase()
92                                : dyn_cast<SymbolicRegion>(R->StripCasts()))
93       return SymR->getSymbol();
94
95   return nullptr;
96 }
97
98 /// Get the symbol in the SVal or its base region.
99 SymbolRef SVal::getLocSymbolInBase() const {
100   Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
101
102   if (!X)
103     return nullptr;
104
105   const MemRegion *R = X->getRegion();
106
107   while (const auto *SR = dyn_cast<SubRegion>(R)) {
108     if (const auto *SymR = dyn_cast<SymbolicRegion>(SR))
109       return SymR->getSymbol();
110     else
111       R = SR->getSuperRegion();
112   }
113
114   return nullptr;
115 }
116
117 /// If this SVal wraps a symbol return that SymbolRef.
118 /// Otherwise, return 0.
119 ///
120 /// Casts are ignored during lookup.
121 /// \param IncludeBaseRegions The boolean that controls whether the search
122 /// should continue to the base regions if the region is not symbolic.
123 SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const {
124   // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
125   if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
126     return X->getSymbol();
127
128   return getAsLocSymbol(IncludeBaseRegions);
129 }
130
131 const MemRegion *SVal::getAsRegion() const {
132   if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
133     return X->getRegion();
134
135   if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
136     return X->getLoc().getAsRegion();
137
138   return nullptr;
139 }
140
141 namespace {
142 class TypeRetrievingVisitor
143     : public FullSValVisitor<TypeRetrievingVisitor, QualType> {
144 private:
145   const ASTContext &Context;
146
147 public:
148   TypeRetrievingVisitor(const ASTContext &Context) : Context(Context) {}
149
150   QualType VisitLocMemRegionVal(loc::MemRegionVal MRV) {
151     return Visit(MRV.getRegion());
152   }
153   QualType VisitLocGotoLabel(loc::GotoLabel GL) {
154     return QualType{Context.VoidPtrTy};
155   }
156   template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) {
157     const llvm::APSInt &Value = CI.getValue();
158     return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned());
159   }
160   QualType VisitLocConcreteInt(loc::ConcreteInt CI) {
161     return VisitConcreteInt(CI);
162   }
163   QualType VisitNonLocConcreteInt(nonloc::ConcreteInt CI) {
164     return VisitConcreteInt(CI);
165   }
166   QualType VisitNonLocLocAsInteger(nonloc::LocAsInteger LI) {
167     QualType NestedType = Visit(LI.getLoc());
168     if (NestedType.isNull())
169       return NestedType;
170
171     return Context.getIntTypeForBitwidth(LI.getNumBits(),
172                                          NestedType->isSignedIntegerType());
173   }
174   QualType VisitNonLocCompoundVal(nonloc::CompoundVal CV) {
175     return CV.getValue()->getType();
176   }
177   QualType VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal LCV) {
178     return LCV.getRegion()->getValueType();
179   }
180   QualType VisitNonLocSymbolVal(nonloc::SymbolVal SV) {
181     return Visit(SV.getSymbol());
182   }
183   QualType VisitSymbolicRegion(const SymbolicRegion *SR) {
184     return Visit(SR->getSymbol());
185   }
186   QualType VisitTypedRegion(const TypedRegion *TR) {
187     return TR->getLocationType();
188   }
189   QualType VisitSymExpr(const SymExpr *SE) { return SE->getType(); }
190 };
191 } // end anonymous namespace
192
193 QualType SVal::getType(const ASTContext &Context) const {
194   TypeRetrievingVisitor TRV{Context};
195   return TRV.Visit(*this);
196 }
197
198 const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const {
199   const MemRegion *R = getRegion();
200   return R ?  R->StripCasts(StripBaseCasts) : nullptr;
201 }
202
203 const void *nonloc::LazyCompoundVal::getStore() const {
204   return static_cast<const LazyCompoundValData*>(Data)->getStore();
205 }
206
207 const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const {
208   return static_cast<const LazyCompoundValData*>(Data)->getRegion();
209 }
210
211 bool nonloc::PointerToMember::isNullMemberPointer() const {
212   return getPTMData().isNull();
213 }
214
215 const NamedDecl *nonloc::PointerToMember::getDecl() const {
216   const auto PTMD = this->getPTMData();
217   if (PTMD.isNull())
218     return nullptr;
219
220   const NamedDecl *ND = nullptr;
221   if (PTMD.is<const NamedDecl *>())
222     ND = PTMD.get<const NamedDecl *>();
223   else
224     ND = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl();
225
226   return ND;
227 }
228
229 //===----------------------------------------------------------------------===//
230 // Other Iterators.
231 //===----------------------------------------------------------------------===//
232
233 nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
234   return getValue()->begin();
235 }
236
237 nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
238   return getValue()->end();
239 }
240
241 nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const {
242   const PTMDataType PTMD = getPTMData();
243   if (PTMD.is<const NamedDecl *>())
244     return {};
245   return PTMD.get<const PointerToMemberData *>()->begin();
246 }
247
248 nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const {
249   const PTMDataType PTMD = getPTMData();
250   if (PTMD.is<const NamedDecl *>())
251     return {};
252   return PTMD.get<const PointerToMemberData *>()->end();
253 }
254
255 //===----------------------------------------------------------------------===//
256 // Useful predicates.
257 //===----------------------------------------------------------------------===//
258
259 bool SVal::isConstant() const {
260   return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>();
261 }
262
263 bool SVal::isConstant(int I) const {
264   if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
265     return LV->getValue() == I;
266   if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
267     return NV->getValue() == I;
268   return false;
269 }
270
271 bool SVal::isZeroConstant() const {
272   return isConstant(0);
273 }
274
275 //===----------------------------------------------------------------------===//
276 // Transfer function dispatch for Non-Locs.
277 //===----------------------------------------------------------------------===//
278
279 SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder,
280                                     BinaryOperator::Opcode Op,
281                                     const nonloc::ConcreteInt& R) const {
282   const llvm::APSInt* X =
283     svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue());
284
285   if (X)
286     return nonloc::ConcreteInt(*X);
287   else
288     return UndefinedVal();
289 }
290
291 nonloc::ConcreteInt
292 nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const {
293   return svalBuilder.makeIntVal(~getValue());
294 }
295
296 nonloc::ConcreteInt
297 nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const {
298   return svalBuilder.makeIntVal(-getValue());
299 }
300
301 //===----------------------------------------------------------------------===//
302 // Transfer function dispatch for Locs.
303 //===----------------------------------------------------------------------===//
304
305 SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
306                                  BinaryOperator::Opcode Op,
307                                  const loc::ConcreteInt& R) const {
308   assert(BinaryOperator::isComparisonOp(Op) || Op == BO_Sub);
309
310   const llvm::APSInt *X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
311
312   if (X)
313     return nonloc::ConcreteInt(*X);
314   else
315     return UndefinedVal();
316 }
317
318 //===----------------------------------------------------------------------===//
319 // Pretty-Printing.
320 //===----------------------------------------------------------------------===//
321
322 LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); }
323
324 void SVal::printJson(raw_ostream &Out, bool AddQuotes) const {
325   std::string Buf;
326   llvm::raw_string_ostream TempOut(Buf);
327
328   dumpToStream(TempOut);
329
330   Out << JsonFormat(TempOut.str(), AddQuotes);
331 }
332
333 void SVal::dumpToStream(raw_ostream &os) const {
334   switch (getBaseKind()) {
335     case UnknownValKind:
336       os << "Unknown";
337       break;
338     case NonLocKind:
339       castAs<NonLoc>().dumpToStream(os);
340       break;
341     case LocKind:
342       castAs<Loc>().dumpToStream(os);
343       break;
344     case UndefinedValKind:
345       os << "Undefined";
346       break;
347   }
348 }
349
350 void NonLoc::dumpToStream(raw_ostream &os) const {
351   switch (getSubKind()) {
352     case nonloc::ConcreteIntKind: {
353       const auto &Value = castAs<nonloc::ConcreteInt>().getValue();
354       os << Value << ' ' << (Value.isSigned() ? 'S' : 'U')
355          << Value.getBitWidth() << 'b';
356       break;
357     }
358     case nonloc::SymbolValKind:
359       os << castAs<nonloc::SymbolVal>().getSymbol();
360       break;
361
362     case nonloc::LocAsIntegerKind: {
363       const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>();
364       os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
365       break;
366     }
367     case nonloc::CompoundValKind: {
368       const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>();
369       os << "compoundVal{";
370       bool first = true;
371       for (const auto &I : C) {
372         if (first) {
373           os << ' '; first = false;
374         }
375         else
376           os << ", ";
377
378         I.dumpToStream(os);
379       }
380       os << "}";
381       break;
382     }
383     case nonloc::LazyCompoundValKind: {
384       const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>();
385       os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
386          << ',' << C.getRegion()
387          << '}';
388       break;
389     }
390     case nonloc::PointerToMemberKind: {
391       os << "pointerToMember{";
392       const nonloc::PointerToMember &CastRes =
393           castAs<nonloc::PointerToMember>();
394       if (CastRes.getDecl())
395         os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|";
396       bool first = true;
397       for (const auto &I : CastRes) {
398         if (first) {
399           os << ' '; first = false;
400         }
401         else
402           os << ", ";
403
404         os << (*I).getType().getAsString();
405       }
406
407       os << '}';
408       break;
409     }
410     default:
411       assert(false && "Pretty-printed not implemented for this NonLoc.");
412       break;
413   }
414 }
415
416 void Loc::dumpToStream(raw_ostream &os) const {
417   switch (getSubKind()) {
418     case loc::ConcreteIntKind:
419       os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)";
420       break;
421     case loc::GotoLabelKind:
422       os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
423       break;
424     case loc::MemRegionValKind:
425       os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
426       break;
427     default:
428       llvm_unreachable("Pretty-printing not implemented for this Loc.");
429   }
430 }