xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
34 using namespace clang;
35 using namespace ento;
36 
37 //===----------------------------------------------------------------------===//
38 // Symbol iteration within an SVal.
39 //===----------------------------------------------------------------------===//
40 
41 //===----------------------------------------------------------------------===//
42 // Utility methods.
43 //===----------------------------------------------------------------------===//
44 
getAsFunctionDecl() const45 const 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>(CTR->getDecl()))
50         return FD;
51   }
52 
53   if (auto X = getAs<nonloc::PointerToMember>()) {
54     if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(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.
getAsLocSymbol(bool IncludeBaseRegions) const67 SymbolRef 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>(R->StripCasts()))
73       return SymR->getSymbol();
74 
75   return nullptr;
76 }
77 
78 /// Get the symbol in the SVal or its base region.
getLocSymbolInBase() const79 SymbolRef 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>(R)) {
88     if (const auto *SymR = dyn_cast<SymbolicRegion>(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.
getAsSymbol(bool IncludeBaseRegions) const103 SymbolRef 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 
getAsInteger() const111 const 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 
getAsRegion() const119 const 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 
129 namespace {
130 class TypeRetrievingVisitor
131     : public FullSValVisitor<TypeRetrievingVisitor, QualType> {
132 private:
133   const ASTContext &Context;
134 
135 public:
TypeRetrievingVisitor(const ASTContext & Context)136   TypeRetrievingVisitor(const ASTContext &Context) : Context(Context) {}
137 
VisitMemRegionVal(loc::MemRegionVal MRV)138   QualType VisitMemRegionVal(loc::MemRegionVal MRV) {
139     return Visit(MRV.getRegion());
140   }
VisitGotoLabel(loc::GotoLabel GL)141   QualType VisitGotoLabel(loc::GotoLabel GL) {
142     return QualType{Context.VoidPtrTy};
143   }
VisitConcreteInt(ConcreteInt CI)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(Value.getBitWidth(), Value.isSigned());
149   }
VisitLocAsInteger(nonloc::LocAsInteger LI)150   QualType VisitLocAsInteger(nonloc::LocAsInteger LI) {
151     QualType NestedType = Visit(LI.getLoc());
152     if (NestedType.isNull())
153       return NestedType;
154 
155     return Context.getIntTypeForBitwidth(LI.getNumBits(),
156                                          NestedType->isSignedIntegerType());
157   }
VisitCompoundVal(nonloc::CompoundVal CV)158   QualType VisitCompoundVal(nonloc::CompoundVal CV) {
159     return CV.getValue()->getType();
160   }
VisitLazyCompoundVal(nonloc::LazyCompoundVal LCV)161   QualType VisitLazyCompoundVal(nonloc::LazyCompoundVal LCV) {
162     return LCV.getRegion()->getValueType();
163   }
VisitSymbolVal(nonloc::SymbolVal SV)164   QualType VisitSymbolVal(nonloc::SymbolVal SV) {
165     return Visit(SV.getSymbol());
166   }
VisitSymbolicRegion(const SymbolicRegion * SR)167   QualType VisitSymbolicRegion(const SymbolicRegion *SR) {
168     return Visit(SR->getSymbol());
169   }
VisitAllocaRegion(const AllocaRegion *)170   QualType VisitAllocaRegion(const AllocaRegion *) {
171     return QualType{Context.VoidPtrTy};
172   }
VisitTypedRegion(const TypedRegion * TR)173   QualType VisitTypedRegion(const TypedRegion *TR) {
174     return TR->getLocationType();
175   }
VisitSymExpr(const SymExpr * SE)176   QualType VisitSymExpr(const SymExpr *SE) { return SE->getType(); }
177 };
178 } // end anonymous namespace
179 
getType(const ASTContext & Context) const180 QualType SVal::getType(const ASTContext &Context) const {
181   TypeRetrievingVisitor TRV{Context};
182   return TRV.Visit(*this);
183 }
184 
stripCasts(bool StripBaseCasts) const185 const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const {
186   return getRegion()->StripCasts(StripBaseCasts);
187 }
188 
getStore() const189 const void *nonloc::LazyCompoundVal::getStore() const {
190   return static_cast<const LazyCompoundValData*>(Data)->getStore();
191 }
192 
getRegion() const193 const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const {
194   return static_cast<const LazyCompoundValData*>(Data)->getRegion();
195 }
196 
isNullMemberPointer() const197 bool nonloc::PointerToMember::isNullMemberPointer() const {
198   return getPTMData().isNull();
199 }
200 
getDecl() const201 const 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 *>(PTMD))
208     ND = NDP;
209   else
210     ND = cast<const PointerToMemberData *>(PTMD)->getDeclaratorDecl();
211 
212   return ND;
213 }
214 
215 //===----------------------------------------------------------------------===//
216 // Other Iterators.
217 //===----------------------------------------------------------------------===//
218 
begin() const219 nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
220   return getValue()->begin();
221 }
222 
end() const223 nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
224   return getValue()->end();
225 }
226 
begin() const227 nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const {
228   const PTMDataType PTMD = getPTMData();
229   if (isa<const NamedDecl *>(PTMD))
230     return {};
231   return cast<const PointerToMemberData *>(PTMD)->begin();
232 }
233 
end() const234 nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const {
235   const PTMDataType PTMD = getPTMData();
236   if (isa<const NamedDecl *>(PTMD))
237     return {};
238   return cast<const PointerToMemberData *>(PTMD)->end();
239 }
240 
241 //===----------------------------------------------------------------------===//
242 // Useful predicates.
243 //===----------------------------------------------------------------------===//
244 
isConstant() const245 bool SVal::isConstant() const {
246   return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>();
247 }
248 
isConstant(int I) const249 bool 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 
isZeroConstant() const257 bool SVal::isZeroConstant() const {
258   return isConstant(0);
259 }
260 
261 //===----------------------------------------------------------------------===//
262 // Pretty-Printing.
263 //===----------------------------------------------------------------------===//
264 
getKindStr() const265 StringRef 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 
dump() const282 LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); }
283 
printJson(raw_ostream & Out,bool AddQuotes) const284 void SVal::printJson(raw_ostream &Out, bool AddQuotes) const {
285   std::string Buf;
286   llvm::raw_string_ostream TempOut(Buf);
287 
288   dumpToStream(TempOut);
289 
290   Out << JsonFormat(Buf, AddQuotes);
291 }
292 
dumpToStream(raw_ostream & os) const293 void 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(*this)) {
303     castAs<NonLoc>().dumpToStream(os);
304     return;
305   }
306   if (Loc::classof(*this)) {
307     castAs<Loc>().dumpToStream(os);
308     return;
309   }
310   llvm_unreachable("Unhandled SVal kind!");
311 }
312 
dumpToStream(raw_ostream & os) const313 void 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 
dumpToStream(raw_ostream & os) const379 void 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