Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //== SValExplainer.h - Symbolic value explainer -----------------*- 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 SValExplainer, a class for pretty-printing a
  10. //  human-readable description of a symbolic value. For example,
  11. //  "reg_$0<x>" is turned into "initial value of variable 'x'".
  12. //
  13. //===----------------------------------------------------------------------===//
  14.  
  15. #ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
  16. #define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
  17.  
  18. #include "clang/AST/Attr.h"
  19. #include "clang/AST/DeclCXX.h"
  20. #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
  21. #include "llvm/ADT/StringExtras.h"
  22.  
  23. namespace clang {
  24.  
  25. namespace ento {
  26.  
  27. class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
  28. private:
  29.   ASTContext &ACtx;
  30.  
  31.   std::string printStmt(const Stmt *S) {
  32.     std::string Str;
  33.     llvm::raw_string_ostream OS(Str);
  34.     S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
  35.     return Str;
  36.   }
  37.  
  38.   bool isThisObject(const SymbolicRegion *R) {
  39.     if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
  40.       if (isa<CXXThisRegion>(S->getRegion()))
  41.         return true;
  42.     return false;
  43.   }
  44.  
  45.   bool isThisObject(const ElementRegion *R) {
  46.     if (const auto *Idx = R->getIndex().getAsInteger()) {
  47.       if (const auto *SR = R->getSuperRegion()->getAs<SymbolicRegion>()) {
  48.         QualType Ty = SR->getPointeeStaticType();
  49.         bool IsNotReinterpretCast = R->getValueType() == Ty;
  50.         if (Idx->isZero() && IsNotReinterpretCast)
  51.           return isThisObject(SR);
  52.       }
  53.     }
  54.     return false;
  55.   }
  56.  
  57. public:
  58.   SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
  59.  
  60.   std::string VisitUnknownVal(UnknownVal V) {
  61.     return "unknown value";
  62.   }
  63.  
  64.   std::string VisitUndefinedVal(UndefinedVal V) {
  65.     return "undefined value";
  66.   }
  67.  
  68.   std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
  69.     const MemRegion *R = V.getRegion();
  70.     // Avoid the weird "pointer to pointee of ...".
  71.     if (auto SR = dyn_cast<SymbolicRegion>(R)) {
  72.       // However, "pointer to 'this' object" is fine.
  73.       if (!isThisObject(SR))
  74.         return Visit(SR->getSymbol());
  75.     }
  76.     return "pointer to " + Visit(R);
  77.   }
  78.  
  79.   std::string VisitLocConcreteInt(loc::ConcreteInt V) {
  80.     const llvm::APSInt &I = V.getValue();
  81.     std::string Str;
  82.     llvm::raw_string_ostream OS(Str);
  83.     OS << "concrete memory address '" << I << "'";
  84.     return Str;
  85.   }
  86.  
  87.   std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
  88.     return Visit(V.getSymbol());
  89.   }
  90.  
  91.   std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
  92.     const llvm::APSInt &I = V.getValue();
  93.     std::string Str;
  94.     llvm::raw_string_ostream OS(Str);
  95.     OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
  96.        << "-bit integer '" << I << "'";
  97.     return Str;
  98.   }
  99.  
  100.   std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
  101.     return "lazily frozen compound value of " + Visit(V.getRegion());
  102.   }
  103.  
  104.   std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
  105.     const MemRegion *R = S->getRegion();
  106.     // Special handling for argument values.
  107.     if (auto V = dyn_cast<VarRegion>(R))
  108.       if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
  109.         return "argument '" + D->getQualifiedNameAsString() + "'";
  110.     return "initial value of " + Visit(R);
  111.   }
  112.  
  113.   std::string VisitSymbolConjured(const SymbolConjured *S) {
  114.     return "symbol of type '" + S->getType().getAsString() +
  115.            "' conjured at statement '" + printStmt(S->getStmt()) + "'";
  116.   }
  117.  
  118.   std::string VisitSymbolDerived(const SymbolDerived *S) {
  119.     return "value derived from (" + Visit(S->getParentSymbol()) +
  120.            ") for " + Visit(S->getRegion());
  121.   }
  122.  
  123.   std::string VisitSymbolExtent(const SymbolExtent *S) {
  124.     return "extent of " + Visit(S->getRegion());
  125.   }
  126.  
  127.   std::string VisitSymbolMetadata(const SymbolMetadata *S) {
  128.     return "metadata of type '" + S->getType().getAsString() + "' tied to " +
  129.            Visit(S->getRegion());
  130.   }
  131.  
  132.   std::string VisitSymIntExpr(const SymIntExpr *S) {
  133.     std::string Str;
  134.     llvm::raw_string_ostream OS(Str);
  135.     OS << "(" << Visit(S->getLHS()) << ") "
  136.        << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
  137.        << S->getRHS();
  138.     return Str;
  139.   }
  140.  
  141.   // TODO: IntSymExpr doesn't appear in practice.
  142.   // Add the relevant code once it does.
  143.  
  144.   std::string VisitSymSymExpr(const SymSymExpr *S) {
  145.     return "(" + Visit(S->getLHS()) + ") " +
  146.            std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
  147.            " (" + Visit(S->getRHS()) + ")";
  148.   }
  149.  
  150.   std::string VisitUnarySymExpr(const UnarySymExpr *S) {
  151.     return std::string(UnaryOperator::getOpcodeStr(S->getOpcode())) + " (" +
  152.            Visit(S->getOperand()) + ")";
  153.   }
  154.  
  155.   // TODO: SymbolCast doesn't appear in practice.
  156.   // Add the relevant code once it does.
  157.  
  158.   std::string VisitSymbolicRegion(const SymbolicRegion *R) {
  159.     // Explain 'this' object here - if it's not wrapped by an ElementRegion.
  160.     // TODO: Explain CXXThisRegion itself, find a way to test it.
  161.     if (isThisObject(R))
  162.       return "'this' object";
  163.     // Objective-C objects are not normal symbolic regions. At least,
  164.     // they're always on the heap.
  165.     if (R->getSymbol()->getType()
  166.             .getCanonicalType()->getAs<ObjCObjectPointerType>())
  167.       return "object at " + Visit(R->getSymbol());
  168.     // Other heap-based symbolic regions are also special.
  169.     if (isa<HeapSpaceRegion>(R->getMemorySpace()))
  170.       return "heap segment that starts at " + Visit(R->getSymbol());
  171.     return "pointee of " + Visit(R->getSymbol());
  172.   }
  173.  
  174.   std::string VisitAllocaRegion(const AllocaRegion *R) {
  175.     return "region allocated by '" + printStmt(R->getExpr()) + "'";
  176.   }
  177.  
  178.   std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
  179.     return "compound literal " + printStmt(R->getLiteralExpr());
  180.   }
  181.  
  182.   std::string VisitStringRegion(const StringRegion *R) {
  183.     return "string literal " + R->getString();
  184.   }
  185.  
  186.   std::string VisitElementRegion(const ElementRegion *R) {
  187.     std::string Str;
  188.     llvm::raw_string_ostream OS(Str);
  189.  
  190.     // Explain 'this' object here.
  191.     // They are represented by a SymRegion wrapped by an ElementRegion; so
  192.     // match and handle it here.
  193.     if (isThisObject(R))
  194.       return "'this' object";
  195.  
  196.     OS << "element of type '" << R->getElementType() << "' with index ";
  197.     // For concrete index: omit type of the index integer.
  198.     if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
  199.       OS << I->getValue();
  200.     else
  201.       OS << "'" << Visit(R->getIndex()) << "'";
  202.     OS << " of " + Visit(R->getSuperRegion());
  203.     return Str;
  204.   }
  205.  
  206.   std::string VisitNonParamVarRegion(const NonParamVarRegion *R) {
  207.     const VarDecl *VD = R->getDecl();
  208.     std::string Name = VD->getQualifiedNameAsString();
  209.     if (isa<ParmVarDecl>(VD))
  210.       return "parameter '" + Name + "'";
  211.     else if (VD->hasAttr<BlocksAttr>())
  212.       return "block variable '" + Name + "'";
  213.     else if (VD->hasLocalStorage())
  214.       return "local variable '" + Name + "'";
  215.     else if (VD->isStaticLocal())
  216.       return "static local variable '" + Name + "'";
  217.     else if (VD->hasGlobalStorage())
  218.       return "global variable '" + Name + "'";
  219.     else
  220.       llvm_unreachable("A variable is either local or global");
  221.   }
  222.  
  223.   std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
  224.     return "instance variable '" + R->getDecl()->getNameAsString() + "' of " +
  225.            Visit(R->getSuperRegion());
  226.   }
  227.  
  228.   std::string VisitFieldRegion(const FieldRegion *R) {
  229.     return "field '" + R->getDecl()->getNameAsString() + "' of " +
  230.            Visit(R->getSuperRegion());
  231.   }
  232.  
  233.   std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
  234.     return "temporary object constructed at statement '" +
  235.            printStmt(R->getExpr()) + "'";
  236.   }
  237.  
  238.   std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
  239.     return "base object '" + R->getDecl()->getQualifiedNameAsString() +
  240.            "' inside " + Visit(R->getSuperRegion());
  241.   }
  242.  
  243.   std::string VisitParamVarRegion(const ParamVarRegion *R) {
  244.     std::string Str;
  245.     llvm::raw_string_ostream OS(Str);
  246.  
  247.     const ParmVarDecl *PVD = R->getDecl();
  248.     std::string Name = PVD->getQualifiedNameAsString();
  249.     if (!Name.empty()) {
  250.       OS << "parameter '" << Name << "'";
  251.       return std::string(OS.str());
  252.     }
  253.  
  254.     unsigned Index = R->getIndex() + 1;
  255.     OS << Index << llvm::getOrdinalSuffix(Index) << " parameter of ";
  256.     const Decl *Parent = R->getStackFrame()->getDecl();
  257.     if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
  258.       OS << "function '" << FD->getQualifiedNameAsString() << "()'";
  259.     else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
  260.       OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
  261.     else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
  262.       if (MD->isClassMethod())
  263.         OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
  264.       else
  265.         OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
  266.     } else if (isa<BlockDecl>(Parent)) {
  267.       if (cast<BlockDecl>(Parent)->isConversionFromLambda())
  268.         OS << "lambda";
  269.       else
  270.         OS << "block";
  271.     }
  272.  
  273.     return std::string(OS.str());
  274.   }
  275.  
  276.   std::string VisitSVal(SVal V) {
  277.     std::string Str;
  278.     llvm::raw_string_ostream OS(Str);
  279.     OS << V;
  280.     return "a value unsupported by the explainer: (" +
  281.            std::string(OS.str()) + ")";
  282.   }
  283.  
  284.   std::string VisitSymExpr(SymbolRef S) {
  285.     std::string Str;
  286.     llvm::raw_string_ostream OS(Str);
  287.     S->dumpToStream(OS);
  288.     return "a symbolic expression unsupported by the explainer: (" +
  289.            std::string(OS.str()) + ")";
  290.   }
  291.  
  292.   std::string VisitMemRegion(const MemRegion *R) {
  293.     std::string Str;
  294.     llvm::raw_string_ostream OS(Str);
  295.     OS << R;
  296.     return "a memory region unsupported by the explainer (" +
  297.            std::string(OS.str()) + ")";
  298.   }
  299. };
  300.  
  301. } // end namespace ento
  302.  
  303. } // end namespace clang
  304.  
  305. #endif
  306.