xref: /freebsd/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===- SVals.h - Abstract Values for Static Analysis ------------*- C++ -*-===//
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 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
15 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
16 
17 #include "clang/AST/Expr.h"
18 #include "clang/AST/Type.h"
19 #include "clang/Basic/LLVM.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
21 #include "llvm/ADT/APSInt.h"
22 #include "llvm/ADT/FoldingSet.h"
23 #include "llvm/ADT/ImmutableList.h"
24 #include "llvm/ADT/PointerUnion.h"
25 #include "llvm/ADT/STLForwardCompat.h"
26 #include "llvm/ADT/iterator_range.h"
27 #include "llvm/Support/Casting.h"
28 #include <cassert>
29 #include <cstdint>
30 #include <optional>
31 #include <utility>
32 
33 //==------------------------------------------------------------------------==//
34 //  Base SVal types.
35 //==------------------------------------------------------------------------==//
36 
37 namespace clang {
38 
39 class CXXBaseSpecifier;
40 class FunctionDecl;
41 class LabelDecl;
42 
43 namespace ento {
44 
45 class CompoundValData;
46 class LazyCompoundValData;
47 class MemRegion;
48 class PointerToMemberData;
49 class SValBuilder;
50 class TypedValueRegion;
51 
52 /// SVal - This represents a symbolic expression, which can be either
53 ///  an L-value or an R-value.
54 ///
55 class SVal {
56 public:
57   enum SValKind : unsigned char {
58 #define BASIC_SVAL(Id, Parent) Id##Kind,
59 #define LOC_SVAL(Id, Parent) Loc##Id##Kind,
60 #define NONLOC_SVAL(Id, Parent) NonLoc##Id##Kind,
61 #define SVAL_RANGE(Id, First, Last)                                            \
62   BEGIN_##Id = Id##First##Kind, END_##Id = Id##Last##Kind,
63 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
64   };
65 
66 protected:
67   const void *Data = nullptr;
68   SValKind Kind = UndefinedValKind;
69 
70   explicit SVal(SValKind Kind, const void *Data = nullptr)
Data(Data)71       : Data(Data), Kind(Kind) {}
72 
castDataAs()73   template <typename T> const T *castDataAs() const {
74     return static_cast<const T *>(Data);
75   }
76 
77 public:
78   explicit SVal() = default;
79 
80   /// Convert to the specified SVal type, asserting that this SVal is of
81   /// the desired type.
castAs()82   template <typename T> T castAs() const { return llvm::cast<T>(*this); }
83 
84   /// Convert to the specified SVal type, returning std::nullopt if this SVal is
85   /// not of the desired type.
getAs()86   template <typename T> std::optional<T> getAs() const {
87     return llvm::dyn_cast<T>(*this);
88   }
89 
getKind()90   SValKind getKind() const { return Kind; }
91 
92   // This method is required for using SVal in a FoldingSetNode.  It
93   // extracts a unique signature for this SVal object.
Profile(llvm::FoldingSetNodeID & ID)94   void Profile(llvm::FoldingSetNodeID &ID) const {
95     ID.AddPointer(Data);
96     ID.AddInteger(llvm::to_underlying(getKind()));
97   }
98 
99   bool operator==(SVal R) const { return Kind == R.Kind && Data == R.Data; }
100   bool operator!=(SVal R) const { return !(*this == R); }
101 
isUnknown()102   bool isUnknown() const { return getKind() == UnknownValKind; }
103 
isUndef()104   bool isUndef() const { return getKind() == UndefinedValKind; }
105 
isUnknownOrUndef()106   bool isUnknownOrUndef() const { return isUnknown() || isUndef(); }
107 
isValid()108   bool isValid() const { return !isUnknownOrUndef(); }
109 
110   bool isConstant() const;
111 
112   bool isConstant(int I) const;
113 
114   bool isZeroConstant() const;
115 
116   /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
117   /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
118   /// Otherwise return 0.
119   const FunctionDecl *getAsFunctionDecl() const;
120 
121   /// If this SVal is a location and wraps a symbol, return that
122   ///  SymbolRef. Otherwise return 0.
123   ///
124   /// Casts are ignored during lookup.
125   /// \param IncludeBaseRegions The boolean that controls whether the search
126   /// should continue to the base regions if the region is not symbolic.
127   SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const;
128 
129   /// Get the symbol in the SVal or its base region.
130   SymbolRef getLocSymbolInBase() const;
131 
132   /// If this SVal wraps a symbol return that SymbolRef.
133   /// Otherwise, return 0.
134   ///
135   /// Casts are ignored during lookup.
136   /// \param IncludeBaseRegions The boolean that controls whether the search
137   /// should continue to the base regions if the region is not symbolic.
138   SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const;
139 
140   /// If this SVal is loc::ConcreteInt or nonloc::ConcreteInt,
141   /// return a pointer to APSInt which is held in it.
142   /// Otherwise, return nullptr.
143   const llvm::APSInt *getAsInteger() const;
144 
145   const MemRegion *getAsRegion() const;
146 
147   /// printJson - Pretty-prints in JSON format.
148   void printJson(raw_ostream &Out, bool AddQuotes) const;
149 
150   void dumpToStream(raw_ostream &OS) const;
151   void dump() const;
152 
symbols()153   llvm::iterator_range<SymExpr::symbol_iterator> symbols() const {
154     if (const SymExpr *SE = getAsSymbol(/*IncludeBaseRegions=*/true))
155       return SE->symbols();
156     SymExpr::symbol_iterator end{};
157     return llvm::make_range(end, end);
158   }
159 
160   /// Try to get a reasonable type for the given value.
161   ///
162   /// \returns The best approximation of the value type or Null.
163   /// In theory, all symbolic values should be typed, but this function
164   /// is still a WIP and might have a few blind spots.
165   ///
166   /// \note This function should not be used when the user has access to the
167   /// bound expression AST node as well, since AST always has exact types.
168   ///
169   /// \note Loc values are interpreted as pointer rvalues for the purposes of
170   /// this method.
171   QualType getType(const ASTContext &) const;
172 };
173 
174 inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) {
175   V.dumpToStream(os);
176   return os;
177 }
178 
179 namespace nonloc {
180 /// Sub-kinds for NonLoc values.
181 #define NONLOC_SVAL(Id, Parent)                                                \
182   inline constexpr auto Id##Kind = SVal::SValKind::NonLoc##Id##Kind;
183 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
184 } // namespace nonloc
185 
186 namespace loc {
187 /// Sub-kinds for Loc values.
188 #define LOC_SVAL(Id, Parent)                                                   \
189   inline constexpr auto Id##Kind = SVal::SValKind::Loc##Id##Kind;
190 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
191 } // namespace loc
192 
193 class UndefinedVal : public SVal {
194 public:
UndefinedVal()195   UndefinedVal() : SVal(UndefinedValKind) {}
classof(SVal V)196   static bool classof(SVal V) { return V.getKind() == UndefinedValKind; }
197 };
198 
199 class DefinedOrUnknownSVal : public SVal {
200 public:
201   // We want calling these methods to be a compiler error since they are
202   // tautologically false.
203   bool isUndef() const = delete;
204   bool isValid() const = delete;
205 
classof(SVal V)206   static bool classof(SVal V) { return !V.isUndef(); }
207 
208 protected:
209   explicit DefinedOrUnknownSVal(SValKind Kind, const void *Data = nullptr)
SVal(Kind,Data)210       : SVal(Kind, Data) {}
211 };
212 
213 class UnknownVal : public DefinedOrUnknownSVal {
214 public:
UnknownVal()215   explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {}
216 
classof(SVal V)217   static bool classof(SVal V) { return V.getKind() == UnknownValKind; }
218 };
219 
220 class DefinedSVal : public DefinedOrUnknownSVal {
221 public:
222   // We want calling these methods to be a compiler error since they are
223   // tautologically true/false.
224   bool isUnknown() const = delete;
225   bool isUnknownOrUndef() const = delete;
226   bool isValid() const = delete;
227 
classof(SVal V)228   static bool classof(SVal V) { return !V.isUnknownOrUndef(); }
229 
230 protected:
DefinedSVal(SValKind Kind,const void * Data)231   explicit DefinedSVal(SValKind Kind, const void *Data)
232       : DefinedOrUnknownSVal(Kind, Data) {}
233 };
234 
235 class NonLoc : public DefinedSVal {
236 protected:
NonLoc(SValKind Kind,const void * Data)237   NonLoc(SValKind Kind, const void *Data) : DefinedSVal(Kind, Data) {}
238 
239 public:
240   void dumpToStream(raw_ostream &Out) const;
241 
isCompoundType(QualType T)242   static bool isCompoundType(QualType T) {
243     return T->isArrayType() || T->isRecordType() ||
244            T->isAnyComplexType() || T->isVectorType();
245   }
246 
classof(SVal V)247   static bool classof(SVal V) {
248     return BEGIN_NonLoc <= V.getKind() && V.getKind() <= END_NonLoc;
249   }
250 };
251 
252 class Loc : public DefinedSVal {
253 protected:
Loc(SValKind Kind,const void * Data)254   Loc(SValKind Kind, const void *Data) : DefinedSVal(Kind, Data) {}
255 
256 public:
257   void dumpToStream(raw_ostream &Out) const;
258 
isLocType(QualType T)259   static bool isLocType(QualType T) {
260     return T->isAnyPointerType() || T->isBlockPointerType() ||
261            T->isReferenceType() || T->isNullPtrType();
262   }
263 
classof(SVal V)264   static bool classof(SVal V) {
265     return BEGIN_Loc <= V.getKind() && V.getKind() <= END_Loc;
266   }
267 };
268 
269 //==------------------------------------------------------------------------==//
270 //  Subclasses of NonLoc.
271 //==------------------------------------------------------------------------==//
272 
273 namespace nonloc {
274 
275 /// Represents symbolic expression that isn't a location.
276 class SymbolVal : public NonLoc {
277 public:
278   SymbolVal() = delete;
SymbolVal(SymbolRef Sym)279   explicit SymbolVal(SymbolRef Sym) : NonLoc(SymbolValKind, Sym) {
280     assert(Sym);
281     assert(!Loc::isLocType(Sym->getType()));
282   }
283 
284   LLVM_ATTRIBUTE_RETURNS_NONNULL
getSymbol()285   SymbolRef getSymbol() const {
286     return (const SymExpr *) Data;
287   }
288 
isExpression()289   bool isExpression() const {
290     return !isa<SymbolData>(getSymbol());
291   }
292 
classof(SVal V)293   static bool classof(SVal V) { return V.getKind() == SymbolValKind; }
294 };
295 
296 /// Value representing integer constant.
297 class ConcreteInt : public NonLoc {
298 public:
ConcreteInt(const llvm::APSInt & V)299   explicit ConcreteInt(const llvm::APSInt &V) : NonLoc(ConcreteIntKind, &V) {}
300 
getValue()301   const llvm::APSInt &getValue() const { return *castDataAs<llvm::APSInt>(); }
302 
classof(SVal V)303   static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; }
304 };
305 
306 class LocAsInteger : public NonLoc {
307   friend class ento::SValBuilder;
308 
LocAsInteger(const std::pair<SVal,uintptr_t> & data)309   explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
310       : NonLoc(LocAsIntegerKind, &data) {
311     // We do not need to represent loc::ConcreteInt as LocAsInteger,
312     // as it'd collapse into a nonloc::ConcreteInt instead.
313     [[maybe_unused]] SValKind K = data.first.getKind();
314     assert(K == loc::MemRegionValKind || K == loc::GotoLabelKind);
315   }
316 
317 public:
getLoc()318   Loc getLoc() const {
319     return castDataAs<std::pair<SVal, uintptr_t>>()->first.castAs<Loc>();
320   }
321 
getNumBits()322   unsigned getNumBits() const {
323     return castDataAs<std::pair<SVal, uintptr_t>>()->second;
324   }
325 
classof(SVal V)326   static bool classof(SVal V) { return V.getKind() == LocAsIntegerKind; }
327 };
328 
329 class CompoundVal : public NonLoc {
330   friend class ento::SValBuilder;
331 
CompoundVal(const CompoundValData * D)332   explicit CompoundVal(const CompoundValData *D) : NonLoc(CompoundValKind, D) {
333     assert(D);
334   }
335 
336 public:
337   LLVM_ATTRIBUTE_RETURNS_NONNULL
getValue()338   const CompoundValData* getValue() const {
339     return castDataAs<CompoundValData>();
340   }
341 
342   using iterator = llvm::ImmutableList<SVal>::iterator;
343   iterator begin() const;
344   iterator end() const;
345 
classof(SVal V)346   static bool classof(SVal V) { return V.getKind() == CompoundValKind; }
347 };
348 
349 class LazyCompoundVal : public NonLoc {
350   friend class ento::SValBuilder;
351 
LazyCompoundVal(const LazyCompoundValData * D)352   explicit LazyCompoundVal(const LazyCompoundValData *D)
353       : NonLoc(LazyCompoundValKind, D) {
354     assert(D);
355   }
356 
357 public:
358   LLVM_ATTRIBUTE_RETURNS_NONNULL
getCVData()359   const LazyCompoundValData *getCVData() const {
360     return castDataAs<LazyCompoundValData>();
361   }
362 
363   /// It might return null.
364   const void *getStore() const;
365 
366   LLVM_ATTRIBUTE_RETURNS_NONNULL
367   const TypedValueRegion *getRegion() const;
368 
classof(SVal V)369   static bool classof(SVal V) { return V.getKind() == LazyCompoundValKind; }
370 };
371 
372 /// Value representing pointer-to-member.
373 ///
374 /// This value is qualified as NonLoc because neither loading nor storing
375 /// operations are applied to it. Instead, the analyzer uses the L-value coming
376 /// from pointer-to-member applied to an object.
377 /// This SVal is represented by a NamedDecl which can be a member function
378 /// pointer or a member data pointer and an optional list of CXXBaseSpecifiers.
379 /// This list is required to accumulate the pointer-to-member cast history to
380 /// figure out the correct subobject field. In particular, implicit casts grow
381 /// this list and explicit casts like static_cast shrink this list.
382 class PointerToMember : public NonLoc {
383   friend class ento::SValBuilder;
384 
385 public:
386   using PTMDataType =
387       llvm::PointerUnion<const NamedDecl *, const PointerToMemberData *>;
388 
getPTMData()389   const PTMDataType getPTMData() const {
390     return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
391   }
392 
393   bool isNullMemberPointer() const;
394 
395   const NamedDecl *getDecl() const;
396 
397   template<typename AdjustedDecl>
getDeclAs()398   const AdjustedDecl *getDeclAs() const {
399     return dyn_cast_or_null<AdjustedDecl>(getDecl());
400   }
401 
402   using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
403 
404   iterator begin() const;
405   iterator end() const;
406 
classof(SVal V)407   static bool classof(SVal V) { return V.getKind() == PointerToMemberKind; }
408 
409 private:
PointerToMember(const PTMDataType D)410   explicit PointerToMember(const PTMDataType D)
411       : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
412 };
413 
414 } // namespace nonloc
415 
416 //==------------------------------------------------------------------------==//
417 //  Subclasses of Loc.
418 //==------------------------------------------------------------------------==//
419 
420 namespace loc {
421 
422 class GotoLabel : public Loc {
423 public:
GotoLabel(const LabelDecl * Label)424   explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) {
425     assert(Label);
426   }
427 
getLabel()428   const LabelDecl *getLabel() const { return castDataAs<LabelDecl>(); }
429 
classof(SVal V)430   static bool classof(SVal V) { return V.getKind() == GotoLabelKind; }
431 };
432 
433 class MemRegionVal : public Loc {
434 public:
MemRegionVal(const MemRegion * r)435   explicit MemRegionVal(const MemRegion *r) : Loc(MemRegionValKind, r) {
436     assert(r);
437   }
438 
439   /// Get the underlining region.
440   LLVM_ATTRIBUTE_RETURNS_NONNULL
getRegion()441   const MemRegion *getRegion() const { return castDataAs<MemRegion>(); }
442 
443   /// Get the underlining region and strip casts.
444   LLVM_ATTRIBUTE_RETURNS_NONNULL
445   const MemRegion* stripCasts(bool StripBaseCasts = true) const;
446 
447   template <typename REGION>
getRegionAs()448   const REGION* getRegionAs() const {
449     return dyn_cast<REGION>(getRegion());
450   }
451 
452   bool operator==(const MemRegionVal &R) const {
453     return getRegion() == R.getRegion();
454   }
455 
456   bool operator!=(const MemRegionVal &R) const {
457     return getRegion() != R.getRegion();
458   }
459 
classof(SVal V)460   static bool classof(SVal V) { return V.getKind() == MemRegionValKind; }
461 };
462 
463 class ConcreteInt : public Loc {
464 public:
ConcreteInt(const llvm::APSInt & V)465   explicit ConcreteInt(const llvm::APSInt &V) : Loc(ConcreteIntKind, &V) {}
466 
getValue()467   const llvm::APSInt &getValue() const { return *castDataAs<llvm::APSInt>(); }
468 
classof(SVal V)469   static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; }
470 };
471 
472 } // namespace loc
473 } // namespace ento
474 } // namespace clang
475 
476 namespace llvm {
477 template <typename To, typename From>
478 struct CastInfo<
479     To, From,
480     std::enable_if_t<std::is_base_of<::clang::ento::SVal, From>::value>>
481     : public CastIsPossible<To, ::clang::ento::SVal> {
482   using Self = CastInfo<
483       To, From,
484       std::enable_if_t<std::is_base_of<::clang::ento::SVal, From>::value>>;
485   static bool isPossible(const From &V) {
486     return To::classof(*static_cast<const ::clang::ento::SVal *>(&V));
487   }
488   static std::optional<To> castFailed() { return std::optional<To>{}; }
489   static To doCast(const From &f) {
490     return *static_cast<const To *>(cast<::clang::ento::SVal>(&f));
491   }
492   static std::optional<To> doCastIfPossible(const From &f) {
493     if (!Self::isPossible(f))
494       return Self::castFailed();
495     return doCast(f);
496   }
497 };
498 } // namespace llvm
499 
500 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
501