Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:37:09

0001 // SValBuilder.h - Construction of SVals from evaluating expressions -*- C++ -*-
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines SValBuilder, a class that defines the interface for
0010 //  "symbolical evaluators" which construct an SVal from an expression.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
0015 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
0016 
0017 #include "clang/AST/ASTContext.h"
0018 #include "clang/AST/DeclarationName.h"
0019 #include "clang/AST/Expr.h"
0020 #include "clang/AST/ExprObjC.h"
0021 #include "clang/AST/Type.h"
0022 #include "clang/Basic/LLVM.h"
0023 #include "clang/Basic/LangOptions.h"
0024 #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
0025 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
0026 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
0027 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
0028 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
0029 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
0030 #include "llvm/ADT/ImmutableList.h"
0031 #include <cstdint>
0032 #include <optional>
0033 
0034 namespace clang {
0035 
0036 class AnalyzerOptions;
0037 class BlockDecl;
0038 class CXXBoolLiteralExpr;
0039 class CXXMethodDecl;
0040 class CXXRecordDecl;
0041 class DeclaratorDecl;
0042 class FunctionDecl;
0043 class LocationContext;
0044 class StackFrameContext;
0045 class Stmt;
0046 
0047 namespace ento {
0048 
0049 class ConditionTruthVal;
0050 class ProgramStateManager;
0051 class StoreRef;
0052 
0053 class SValBuilder {
0054   virtual void anchor();
0055 
0056 protected:
0057   ASTContext &Context;
0058 
0059   /// Manager of APSInt values.
0060   BasicValueFactory BasicVals;
0061 
0062   /// Manages the creation of symbols.
0063   SymbolManager SymMgr;
0064 
0065   /// Manages the creation of memory regions.
0066   MemRegionManager MemMgr;
0067 
0068   ProgramStateManager &StateMgr;
0069 
0070   const AnalyzerOptions &AnOpts;
0071 
0072   /// The scalar type to use for array indices.
0073   const QualType ArrayIndexTy;
0074 
0075   /// The width of the scalar type used for array indices.
0076   const unsigned ArrayIndexWidth;
0077 
0078 public:
0079   SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
0080               ProgramStateManager &stateMgr);
0081 
0082   virtual ~SValBuilder() = default;
0083 
0084   SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy);
0085 
0086   // Handles casts of type CK_IntegralCast.
0087   SVal evalIntegralCast(ProgramStateRef state, SVal val, QualType castTy,
0088                         QualType originalType);
0089 
0090   SVal evalMinus(NonLoc val);
0091   SVal evalComplement(NonLoc val);
0092 
0093   /// Create a new value which represents a binary expression with two non-
0094   /// location operands.
0095   virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op,
0096                            NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
0097 
0098   /// Create a new value which represents a binary expression with two memory
0099   /// location operands.
0100   virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op,
0101                            Loc lhs, Loc rhs, QualType resultTy) = 0;
0102 
0103   /// Create a new value which represents a binary expression with a memory
0104   /// location and non-location operands. For example, this would be used to
0105   /// evaluate a pointer arithmetic operation.
0106   virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op,
0107                            Loc lhs, NonLoc rhs, QualType resultTy) = 0;
0108 
0109   /// Evaluates a given SVal. If the SVal has only one possible (integer) value,
0110   /// that value is returned. Otherwise, returns NULL.
0111   virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0;
0112 
0113   /// Tries to get the minimal possible (integer) value of a given SVal. This
0114   /// always returns the value of a ConcreteInt, but may return NULL if the
0115   /// value is symbolic and the constraint manager cannot provide a useful
0116   /// answer.
0117   virtual const llvm::APSInt *getMinValue(ProgramStateRef state, SVal val) = 0;
0118 
0119   /// Tries to get the maximal possible (integer) value of a given SVal. This
0120   /// always returns the value of a ConcreteInt, but may return NULL if the
0121   /// value is symbolic and the constraint manager cannot provide a useful
0122   /// answer.
0123   virtual const llvm::APSInt *getMaxValue(ProgramStateRef state, SVal val) = 0;
0124 
0125   /// Simplify symbolic expressions within a given SVal. Return an SVal
0126   /// that represents the same value, but is hopefully easier to work with
0127   /// than the original SVal.
0128   virtual SVal simplifySVal(ProgramStateRef State, SVal Val) = 0;
0129 
0130   /// Constructs a symbolic expression for two non-location values.
0131   SVal makeSymExprValNN(BinaryOperator::Opcode op,
0132                         NonLoc lhs, NonLoc rhs, QualType resultTy);
0133 
0134   SVal evalUnaryOp(ProgramStateRef state, UnaryOperator::Opcode opc,
0135                  SVal operand, QualType type);
0136 
0137   SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
0138                  SVal lhs, SVal rhs, QualType type);
0139 
0140   /// \return Whether values in \p lhs and \p rhs are equal at \p state.
0141   ConditionTruthVal areEqual(ProgramStateRef state, SVal lhs, SVal rhs);
0142 
0143   SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs);
0144 
0145   DefinedOrUnknownSVal evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs,
0146                               DefinedOrUnknownSVal rhs);
0147 
0148   ASTContext &getContext() { return Context; }
0149   const ASTContext &getContext() const { return Context; }
0150 
0151   ProgramStateManager &getStateManager() { return StateMgr; }
0152 
0153   QualType getConditionType() const {
0154     return Context.getLangOpts().CPlusPlus ? Context.BoolTy : Context.IntTy;
0155   }
0156 
0157   QualType getArrayIndexType() const {
0158     return ArrayIndexTy;
0159   }
0160 
0161   BasicValueFactory &getBasicValueFactory() { return BasicVals; }
0162   const BasicValueFactory &getBasicValueFactory() const { return BasicVals; }
0163 
0164   SymbolManager &getSymbolManager() { return SymMgr; }
0165   const SymbolManager &getSymbolManager() const { return SymMgr; }
0166 
0167   MemRegionManager &getRegionManager() { return MemMgr; }
0168   const MemRegionManager &getRegionManager() const { return MemMgr; }
0169 
0170   const AnalyzerOptions &getAnalyzerOptions() const { return AnOpts; }
0171 
0172   // Forwarding methods to SymbolManager.
0173 
0174   const SymbolConjured* conjureSymbol(const Stmt *stmt,
0175                                       const LocationContext *LCtx,
0176                                       QualType type,
0177                                       unsigned visitCount,
0178                                       const void *symbolTag = nullptr) {
0179     return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag);
0180   }
0181 
0182   const SymbolConjured* conjureSymbol(const Expr *expr,
0183                                       const LocationContext *LCtx,
0184                                       unsigned visitCount,
0185                                       const void *symbolTag = nullptr) {
0186     return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag);
0187   }
0188 
0189   /// Construct an SVal representing '0' for the specified type.
0190   DefinedOrUnknownSVal makeZeroVal(QualType type);
0191 
0192   /// Make a unique symbol for value of region.
0193   DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedValueRegion *region);
0194 
0195   /// Create a new symbol with a unique 'name'.
0196   ///
0197   /// We resort to conjured symbols when we cannot construct a derived symbol.
0198   /// The advantage of symbols derived/built from other symbols is that we
0199   /// preserve the relation between related(or even equivalent) expressions, so
0200   /// conjured symbols should be used sparingly.
0201   DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
0202                                         const Expr *expr,
0203                                         const LocationContext *LCtx,
0204                                         unsigned count);
0205   DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Stmt *S,
0206                                         const LocationContext *LCtx,
0207                                         QualType type, unsigned count);
0208   DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt,
0209                                         const LocationContext *LCtx,
0210                                         QualType type,
0211                                         unsigned visitCount);
0212 
0213   /// Conjure a symbol representing heap allocated memory region.
0214   ///
0215   /// Note, the expression should represent a location.
0216   DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
0217                                        const LocationContext *LCtx,
0218                                        unsigned Count);
0219 
0220   /// Conjure a symbol representing heap allocated memory region.
0221   ///
0222   /// Note, now, the expression *doesn't* need to represent a location.
0223   /// But the type need to!
0224   DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
0225                                        const LocationContext *LCtx,
0226                                        QualType type, unsigned Count);
0227 
0228   /// Create an SVal representing the result of an alloca()-like call, that is,
0229   /// an AllocaRegion on the stack.
0230   ///
0231   /// After calling this function, it's a good idea to set the extent of the
0232   /// returned AllocaRegion.
0233   loc::MemRegionVal getAllocaRegionVal(const Expr *E,
0234                                        const LocationContext *LCtx,
0235                                        unsigned Count);
0236 
0237   DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
0238       SymbolRef parentSymbol, const TypedValueRegion *region);
0239 
0240   DefinedSVal getMetadataSymbolVal(const void *symbolTag,
0241                                    const MemRegion *region,
0242                                    const Expr *expr, QualType type,
0243                                    const LocationContext *LCtx,
0244                                    unsigned count);
0245 
0246   DefinedSVal getMemberPointer(const NamedDecl *ND);
0247 
0248   DefinedSVal getFunctionPointer(const FunctionDecl *func);
0249 
0250   DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy,
0251                               const LocationContext *locContext,
0252                               unsigned blockCount);
0253 
0254   /// Returns the value of \p E, if it can be determined in a non-path-sensitive
0255   /// manner.
0256   ///
0257   /// If \p E is not a constant or cannot be modeled, returns \c std::nullopt.
0258   std::optional<SVal> getConstantVal(const Expr *E);
0259 
0260   NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) {
0261     return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals));
0262   }
0263 
0264   NonLoc makeLazyCompoundVal(const StoreRef &store,
0265                              const TypedValueRegion *region) {
0266     return nonloc::LazyCompoundVal(
0267         BasicVals.getLazyCompoundValData(store, region));
0268   }
0269 
0270   NonLoc makePointerToMember(const DeclaratorDecl *DD) {
0271     return nonloc::PointerToMember(DD);
0272   }
0273 
0274   NonLoc makePointerToMember(const PointerToMemberData *PTMD) {
0275     return nonloc::PointerToMember(PTMD);
0276   }
0277 
0278   NonLoc makeZeroArrayIndex() {
0279     return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy));
0280   }
0281 
0282   NonLoc makeArrayIndex(uint64_t idx) {
0283     return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy));
0284   }
0285 
0286   SVal convertToArrayIndex(SVal val);
0287 
0288   nonloc::ConcreteInt makeIntVal(const IntegerLiteral* integer) {
0289     return nonloc::ConcreteInt(
0290         BasicVals.getValue(integer->getValue(),
0291                      integer->getType()->isUnsignedIntegerOrEnumerationType()));
0292   }
0293 
0294   nonloc::ConcreteInt makeBoolVal(const ObjCBoolLiteralExpr *boolean) {
0295     return makeTruthVal(boolean->getValue(), boolean->getType());
0296   }
0297 
0298   nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean);
0299 
0300   nonloc::ConcreteInt makeIntVal(const llvm::APSInt& integer) {
0301     return nonloc::ConcreteInt(BasicVals.getValue(integer));
0302   }
0303 
0304   loc::ConcreteInt makeIntLocVal(const llvm::APSInt &integer) {
0305     return loc::ConcreteInt(BasicVals.getValue(integer));
0306   }
0307 
0308   NonLoc makeIntVal(const llvm::APInt& integer, bool isUnsigned) {
0309     return nonloc::ConcreteInt(BasicVals.getValue(integer, isUnsigned));
0310   }
0311 
0312   DefinedSVal makeIntVal(uint64_t integer, QualType type) {
0313     if (Loc::isLocType(type))
0314       return loc::ConcreteInt(BasicVals.getValue(integer, type));
0315 
0316     return nonloc::ConcreteInt(BasicVals.getValue(integer, type));
0317   }
0318 
0319   NonLoc makeIntVal(uint64_t integer, bool isUnsigned) {
0320     return nonloc::ConcreteInt(BasicVals.getIntValue(integer, isUnsigned));
0321   }
0322 
0323   NonLoc makeIntValWithWidth(QualType ptrType, uint64_t integer) {
0324     return nonloc::ConcreteInt(BasicVals.getValue(integer, ptrType));
0325   }
0326 
0327   NonLoc makeLocAsInteger(Loc loc, unsigned bits) {
0328     return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(loc, bits));
0329   }
0330 
0331   nonloc::SymbolVal makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
0332                                APSIntPtr rhs, QualType type);
0333 
0334   nonloc::SymbolVal makeNonLoc(APSIntPtr rhs, BinaryOperator::Opcode op,
0335                                const SymExpr *lhs, QualType type);
0336 
0337   nonloc::SymbolVal makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
0338                                const SymExpr *rhs, QualType type);
0339 
0340   NonLoc makeNonLoc(const SymExpr *operand, UnaryOperator::Opcode op,
0341                     QualType type);
0342 
0343   /// Create a NonLoc value for cast.
0344   nonloc::SymbolVal makeNonLoc(const SymExpr *operand, QualType fromTy,
0345                                QualType toTy);
0346 
0347   nonloc::ConcreteInt makeTruthVal(bool b, QualType type) {
0348     return nonloc::ConcreteInt(BasicVals.getTruthValue(b, type));
0349   }
0350 
0351   nonloc::ConcreteInt makeTruthVal(bool b) {
0352     return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
0353   }
0354 
0355   /// Create NULL pointer, with proper pointer bit-width for given address
0356   /// space.
0357   /// \param type pointer type.
0358   loc::ConcreteInt makeNullWithType(QualType type) {
0359     // We cannot use the `isAnyPointerType()`.
0360     assert((type->isPointerType() || type->isObjCObjectPointerType() ||
0361             type->isBlockPointerType() || type->isNullPtrType() ||
0362             type->isReferenceType()) &&
0363            "makeNullWithType must use pointer type");
0364 
0365     // The `sizeof(T&)` is `sizeof(T)`, thus we replace the reference with a
0366     // pointer. Here we assume that references are actually implemented by
0367     // pointers under-the-hood.
0368     type = type->isReferenceType()
0369                ? Context.getPointerType(type->getPointeeType())
0370                : type;
0371     return loc::ConcreteInt(BasicVals.getZeroWithTypeSize(type));
0372   }
0373 
0374   loc::MemRegionVal makeLoc(SymbolRef sym) {
0375     return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
0376   }
0377 
0378   loc::MemRegionVal makeLoc(const MemRegion *region) {
0379     return loc::MemRegionVal(region);
0380   }
0381 
0382   loc::GotoLabel makeLoc(const AddrLabelExpr *expr) {
0383     return loc::GotoLabel(expr->getLabel());
0384   }
0385 
0386   loc::ConcreteInt makeLoc(const llvm::APSInt &integer) {
0387     return loc::ConcreteInt(BasicVals.getValue(integer));
0388   }
0389 
0390   /// Return MemRegionVal on success cast, otherwise return std::nullopt.
0391   std::optional<loc::MemRegionVal>
0392   getCastedMemRegionVal(const MemRegion *region, QualType type);
0393 
0394   /// Make an SVal that represents the given symbol. This follows the convention
0395   /// of representing Loc-type symbols (symbolic pointers and references)
0396   /// as Loc values wrapping the symbol rather than as plain symbol values.
0397   DefinedSVal makeSymbolVal(SymbolRef Sym) {
0398     if (Loc::isLocType(Sym->getType()))
0399       return makeLoc(Sym);
0400     return nonloc::SymbolVal(Sym);
0401   }
0402 
0403   /// Return a memory region for the 'this' object reference.
0404   loc::MemRegionVal getCXXThis(const CXXMethodDecl *D,
0405                                const StackFrameContext *SFC);
0406 
0407   /// Return a memory region for the 'this' object reference.
0408   loc::MemRegionVal getCXXThis(const CXXRecordDecl *D,
0409                                const StackFrameContext *SFC);
0410 };
0411 
0412 SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
0413                                      ASTContext &context,
0414                                      ProgramStateManager &stateMgr);
0415 
0416 } // namespace ento
0417 
0418 } // namespace clang
0419 
0420 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H