Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //== SValExplainer.h - Symbolic value explainer -----------------*- 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 SValExplainer, a class for pretty-printing a
0010 //  human-readable description of a symbolic value. For example,
0011 //  "reg_$0<x>" is turned into "initial value of variable 'x'".
0012 //
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
0016 #define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
0017 
0018 #include "clang/AST/Attr.h"
0019 #include "clang/AST/DeclCXX.h"
0020 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
0021 #include "llvm/ADT/StringExtras.h"
0022 
0023 namespace clang {
0024 
0025 namespace ento {
0026 
0027 class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
0028 private:
0029   ASTContext &ACtx;
0030 
0031   std::string printStmt(const Stmt *S) {
0032     std::string Str;
0033     llvm::raw_string_ostream OS(Str);
0034     S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
0035     return Str;
0036   }
0037 
0038   bool isThisObject(const SymbolicRegion *R) {
0039     if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
0040       if (isa<CXXThisRegion>(S->getRegion()))
0041         return true;
0042     return false;
0043   }
0044 
0045   bool isThisObject(const ElementRegion *R) {
0046     if (const auto *Idx = R->getIndex().getAsInteger()) {
0047       if (const auto *SR = R->getSuperRegion()->getAs<SymbolicRegion>()) {
0048         QualType Ty = SR->getPointeeStaticType();
0049         bool IsNotReinterpretCast = R->getValueType() == Ty;
0050         if (Idx->isZero() && IsNotReinterpretCast)
0051           return isThisObject(SR);
0052       }
0053     }
0054     return false;
0055   }
0056 
0057 public:
0058   SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
0059 
0060   std::string VisitUnknownVal(UnknownVal V) {
0061     return "unknown value";
0062   }
0063 
0064   std::string VisitUndefinedVal(UndefinedVal V) {
0065     return "undefined value";
0066   }
0067 
0068   std::string VisitMemRegionVal(loc::MemRegionVal V) {
0069     const MemRegion *R = V.getRegion();
0070     // Avoid the weird "pointer to pointee of ...".
0071     if (auto SR = dyn_cast<SymbolicRegion>(R)) {
0072       // However, "pointer to 'this' object" is fine.
0073       if (!isThisObject(SR))
0074         return Visit(SR->getSymbol());
0075     }
0076     return "pointer to " + Visit(R);
0077   }
0078 
0079   std::string VisitConcreteInt(loc::ConcreteInt V) {
0080     const llvm::APSInt &I = V.getValue();
0081     std::string Str;
0082     llvm::raw_string_ostream OS(Str);
0083     OS << "concrete memory address '" << I << "'";
0084     return Str;
0085   }
0086 
0087   std::string VisitSymbolVal(nonloc::SymbolVal V) {
0088     return Visit(V.getSymbol());
0089   }
0090 
0091   std::string VisitConcreteInt(nonloc::ConcreteInt V) {
0092     const llvm::APSInt &I = V.getValue();
0093     std::string Str;
0094     llvm::raw_string_ostream OS(Str);
0095     OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
0096        << "-bit integer '" << I << "'";
0097     return Str;
0098   }
0099 
0100   std::string VisitLazyCompoundVal(nonloc::LazyCompoundVal V) {
0101     return "lazily frozen compound value of " + Visit(V.getRegion());
0102   }
0103 
0104   std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
0105     const MemRegion *R = S->getRegion();
0106     // Special handling for argument values.
0107     if (auto V = dyn_cast<VarRegion>(R))
0108       if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
0109         return "argument '" + D->getQualifiedNameAsString() + "'";
0110     return "initial value of " + Visit(R);
0111   }
0112 
0113   std::string VisitSymbolConjured(const SymbolConjured *S) {
0114     return "symbol of type '" + S->getType().getAsString() +
0115            "' conjured at statement '" + printStmt(S->getStmt()) + "'";
0116   }
0117 
0118   std::string VisitSymbolDerived(const SymbolDerived *S) {
0119     return "value derived from (" + Visit(S->getParentSymbol()) +
0120            ") for " + Visit(S->getRegion());
0121   }
0122 
0123   std::string VisitSymbolExtent(const SymbolExtent *S) {
0124     return "extent of " + Visit(S->getRegion());
0125   }
0126 
0127   std::string VisitSymbolMetadata(const SymbolMetadata *S) {
0128     return "metadata of type '" + S->getType().getAsString() + "' tied to " +
0129            Visit(S->getRegion());
0130   }
0131 
0132   std::string VisitSymIntExpr(const SymIntExpr *S) {
0133     std::string Str;
0134     llvm::raw_string_ostream OS(Str);
0135     OS << "(" << Visit(S->getLHS()) << ") "
0136        << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
0137        << S->getRHS();
0138     return Str;
0139   }
0140 
0141   // TODO: IntSymExpr doesn't appear in practice.
0142   // Add the relevant code once it does.
0143 
0144   std::string VisitSymSymExpr(const SymSymExpr *S) {
0145     return "(" + Visit(S->getLHS()) + ") " +
0146            std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
0147            " (" + Visit(S->getRHS()) + ")";
0148   }
0149 
0150   std::string VisitUnarySymExpr(const UnarySymExpr *S) {
0151     return std::string(UnaryOperator::getOpcodeStr(S->getOpcode())) + " (" +
0152            Visit(S->getOperand()) + ")";
0153   }
0154 
0155   // TODO: SymbolCast doesn't appear in practice.
0156   // Add the relevant code once it does.
0157 
0158   std::string VisitSymbolicRegion(const SymbolicRegion *R) {
0159     // Explain 'this' object here - if it's not wrapped by an ElementRegion.
0160     // TODO: Explain CXXThisRegion itself, find a way to test it.
0161     if (isThisObject(R))
0162       return "'this' object";
0163     // Objective-C objects are not normal symbolic regions. At least,
0164     // they're always on the heap.
0165     if (R->getSymbol()->getType()
0166             .getCanonicalType()->getAs<ObjCObjectPointerType>())
0167       return "object at " + Visit(R->getSymbol());
0168     // Other heap-based symbolic regions are also special.
0169     if (isa<HeapSpaceRegion>(R->getMemorySpace()))
0170       return "heap segment that starts at " + Visit(R->getSymbol());
0171     return "pointee of " + Visit(R->getSymbol());
0172   }
0173 
0174   std::string VisitAllocaRegion(const AllocaRegion *R) {
0175     return "region allocated by '" + printStmt(R->getExpr()) + "'";
0176   }
0177 
0178   std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
0179     return "compound literal " + printStmt(R->getLiteralExpr());
0180   }
0181 
0182   std::string VisitStringRegion(const StringRegion *R) {
0183     return "string literal " + R->getString();
0184   }
0185 
0186   std::string VisitElementRegion(const ElementRegion *R) {
0187     std::string Str;
0188     llvm::raw_string_ostream OS(Str);
0189 
0190     // Explain 'this' object here.
0191     // They are represented by a SymRegion wrapped by an ElementRegion; so
0192     // match and handle it here.
0193     if (isThisObject(R))
0194       return "'this' object";
0195 
0196     OS << "element of type '" << R->getElementType() << "' with index ";
0197     // For concrete index: omit type of the index integer.
0198     if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
0199       OS << I->getValue();
0200     else
0201       OS << "'" << Visit(R->getIndex()) << "'";
0202     OS << " of " + Visit(R->getSuperRegion());
0203     return Str;
0204   }
0205 
0206   std::string VisitNonParamVarRegion(const NonParamVarRegion *R) {
0207     const VarDecl *VD = R->getDecl();
0208     std::string Name = VD->getQualifiedNameAsString();
0209     if (isa<ParmVarDecl>(VD))
0210       return "parameter '" + Name + "'";
0211     else if (VD->hasAttr<BlocksAttr>())
0212       return "block variable '" + Name + "'";
0213     else if (VD->hasLocalStorage())
0214       return "local variable '" + Name + "'";
0215     else if (VD->isStaticLocal())
0216       return "static local variable '" + Name + "'";
0217     else if (VD->hasGlobalStorage())
0218       return "global variable '" + Name + "'";
0219     else
0220       llvm_unreachable("A variable is either local or global");
0221   }
0222 
0223   std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
0224     return "instance variable '" + R->getDecl()->getNameAsString() + "' of " +
0225            Visit(R->getSuperRegion());
0226   }
0227 
0228   std::string VisitFieldRegion(const FieldRegion *R) {
0229     return "field '" + R->getDecl()->getNameAsString() + "' of " +
0230            Visit(R->getSuperRegion());
0231   }
0232 
0233   std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
0234     return "temporary object constructed at statement '" +
0235            printStmt(R->getExpr()) + "'";
0236   }
0237 
0238   std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
0239     return "base object '" + R->getDecl()->getQualifiedNameAsString() +
0240            "' inside " + Visit(R->getSuperRegion());
0241   }
0242 
0243   std::string VisitParamVarRegion(const ParamVarRegion *R) {
0244     std::string Str;
0245     llvm::raw_string_ostream OS(Str);
0246 
0247     const ParmVarDecl *PVD = R->getDecl();
0248     std::string Name = PVD->getQualifiedNameAsString();
0249     if (!Name.empty()) {
0250       OS << "parameter '" << Name << "'";
0251       return std::string(OS.str());
0252     }
0253 
0254     unsigned Index = R->getIndex() + 1;
0255     OS << Index << llvm::getOrdinalSuffix(Index) << " parameter of ";
0256     const Decl *Parent = R->getStackFrame()->getDecl();
0257     if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
0258       OS << "function '" << FD->getQualifiedNameAsString() << "()'";
0259     else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
0260       OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
0261     else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
0262       if (MD->isClassMethod())
0263         OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
0264       else
0265         OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
0266     } else if (isa<BlockDecl>(Parent)) {
0267       if (cast<BlockDecl>(Parent)->isConversionFromLambda())
0268         OS << "lambda";
0269       else
0270         OS << "block";
0271     }
0272 
0273     return std::string(OS.str());
0274   }
0275 
0276   std::string VisitSVal(SVal V) {
0277     std::string Str;
0278     llvm::raw_string_ostream OS(Str);
0279     OS << V;
0280     return "a value unsupported by the explainer: (" +
0281            std::string(OS.str()) + ")";
0282   }
0283 
0284   std::string VisitSymExpr(SymbolRef S) {
0285     std::string Str;
0286     llvm::raw_string_ostream OS(Str);
0287     S->dumpToStream(OS);
0288     return "a symbolic expression unsupported by the explainer: (" +
0289            std::string(OS.str()) + ")";
0290   }
0291 
0292   std::string VisitMemRegion(const MemRegion *R) {
0293     std::string Str;
0294     llvm::raw_string_ostream OS(Str);
0295     OS << R;
0296     return "a memory region unsupported by the explainer (" +
0297            std::string(OS.str()) + ")";
0298   }
0299 };
0300 
0301 } // end namespace ento
0302 
0303 } // end namespace clang
0304 
0305 #endif