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 22 namespace clang { 23 24 namespace ento { 25 26 class SValExplainer : public FullSValVisitor<SValExplainer, std::string> { 27 private: 28 ASTContext &ACtx; 29 30 std::string printStmt(const Stmt *S) { 31 std::string Str; 32 llvm::raw_string_ostream OS(Str); 33 S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts())); 34 return OS.str(); 35 } 36 37 bool isThisObject(const SymbolicRegion *R) { 38 if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol())) 39 if (isa<CXXThisRegion>(S->getRegion())) 40 return true; 41 return false; 42 } 43 44 public: 45 SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {} 46 47 std::string VisitUnknownVal(UnknownVal V) { 48 return "unknown value"; 49 } 50 51 std::string VisitUndefinedVal(UndefinedVal V) { 52 return "undefined value"; 53 } 54 55 std::string VisitLocMemRegionVal(loc::MemRegionVal V) { 56 const MemRegion *R = V.getRegion(); 57 // Avoid the weird "pointer to pointee of ...". 58 if (auto SR = dyn_cast<SymbolicRegion>(R)) { 59 // However, "pointer to 'this' object" is fine. 60 if (!isThisObject(SR)) 61 return Visit(SR->getSymbol()); 62 } 63 return "pointer to " + Visit(R); 64 } 65 66 std::string VisitLocConcreteInt(loc::ConcreteInt V) { 67 llvm::APSInt I = V.getValue(); 68 std::string Str; 69 llvm::raw_string_ostream OS(Str); 70 OS << "concrete memory address '" << I << "'"; 71 return OS.str(); 72 } 73 74 std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) { 75 return Visit(V.getSymbol()); 76 } 77 78 std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) { 79 llvm::APSInt I = V.getValue(); 80 std::string Str; 81 llvm::raw_string_ostream OS(Str); 82 OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth() 83 << "-bit integer '" << I << "'"; 84 return OS.str(); 85 } 86 87 std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) { 88 return "lazily frozen compound value of " + Visit(V.getRegion()); 89 } 90 91 std::string VisitSymbolRegionValue(const SymbolRegionValue *S) { 92 const MemRegion *R = S->getRegion(); 93 // Special handling for argument values. 94 if (auto V = dyn_cast<VarRegion>(R)) 95 if (auto D = dyn_cast<ParmVarDecl>(V->getDecl())) 96 return "argument '" + D->getQualifiedNameAsString() + "'"; 97 return "initial value of " + Visit(R); 98 } 99 100 std::string VisitSymbolConjured(const SymbolConjured *S) { 101 return "symbol of type '" + S->getType().getAsString() + 102 "' conjured at statement '" + printStmt(S->getStmt()) + "'"; 103 } 104 105 std::string VisitSymbolDerived(const SymbolDerived *S) { 106 return "value derived from (" + Visit(S->getParentSymbol()) + 107 ") for " + Visit(S->getRegion()); 108 } 109 110 std::string VisitSymbolExtent(const SymbolExtent *S) { 111 return "extent of " + Visit(S->getRegion()); 112 } 113 114 std::string VisitSymbolMetadata(const SymbolMetadata *S) { 115 return "metadata of type '" + S->getType().getAsString() + "' tied to " + 116 Visit(S->getRegion()); 117 } 118 119 std::string VisitSymIntExpr(const SymIntExpr *S) { 120 std::string Str; 121 llvm::raw_string_ostream OS(Str); 122 OS << "(" << Visit(S->getLHS()) << ") " 123 << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " " 124 << S->getRHS(); 125 return OS.str(); 126 } 127 128 // TODO: IntSymExpr doesn't appear in practice. 129 // Add the relevant code once it does. 130 131 std::string VisitSymSymExpr(const SymSymExpr *S) { 132 return "(" + Visit(S->getLHS()) + ") " + 133 std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) + 134 " (" + Visit(S->getRHS()) + ")"; 135 } 136 137 // TODO: SymbolCast doesn't appear in practice. 138 // Add the relevant code once it does. 139 140 std::string VisitSymbolicRegion(const SymbolicRegion *R) { 141 // Explain 'this' object here. 142 // TODO: Explain CXXThisRegion itself, find a way to test it. 143 if (isThisObject(R)) 144 return "'this' object"; 145 // Objective-C objects are not normal symbolic regions. At least, 146 // they're always on the heap. 147 if (R->getSymbol()->getType() 148 .getCanonicalType()->getAs<ObjCObjectPointerType>()) 149 return "object at " + Visit(R->getSymbol()); 150 // Other heap-based symbolic regions are also special. 151 if (isa<HeapSpaceRegion>(R->getMemorySpace())) 152 return "heap segment that starts at " + Visit(R->getSymbol()); 153 return "pointee of " + Visit(R->getSymbol()); 154 } 155 156 std::string VisitAllocaRegion(const AllocaRegion *R) { 157 return "region allocated by '" + printStmt(R->getExpr()) + "'"; 158 } 159 160 std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) { 161 return "compound literal " + printStmt(R->getLiteralExpr()); 162 } 163 164 std::string VisitStringRegion(const StringRegion *R) { 165 return "string literal " + R->getString(); 166 } 167 168 std::string VisitElementRegion(const ElementRegion *R) { 169 std::string Str; 170 llvm::raw_string_ostream OS(Str); 171 OS << "element of type '" << R->getElementType().getAsString() 172 << "' with index "; 173 // For concrete index: omit type of the index integer. 174 if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>()) 175 OS << I->getValue(); 176 else 177 OS << "'" << Visit(R->getIndex()) << "'"; 178 OS << " of " + Visit(R->getSuperRegion()); 179 return OS.str(); 180 } 181 182 std::string VisitVarRegion(const VarRegion *R) { 183 const VarDecl *VD = R->getDecl(); 184 std::string Name = VD->getQualifiedNameAsString(); 185 if (isa<ParmVarDecl>(VD)) 186 return "parameter '" + Name + "'"; 187 else if (VD->hasAttr<BlocksAttr>()) 188 return "block variable '" + Name + "'"; 189 else if (VD->hasLocalStorage()) 190 return "local variable '" + Name + "'"; 191 else if (VD->isStaticLocal()) 192 return "static local variable '" + Name + "'"; 193 else if (VD->hasGlobalStorage()) 194 return "global variable '" + Name + "'"; 195 else 196 llvm_unreachable("A variable is either local or global"); 197 } 198 199 std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) { 200 return "instance variable '" + R->getDecl()->getNameAsString() + "' of " + 201 Visit(R->getSuperRegion()); 202 } 203 204 std::string VisitFieldRegion(const FieldRegion *R) { 205 return "field '" + R->getDecl()->getNameAsString() + "' of " + 206 Visit(R->getSuperRegion()); 207 } 208 209 std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) { 210 return "temporary object constructed at statement '" + 211 printStmt(R->getExpr()) + "'"; 212 } 213 214 std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) { 215 return "base object '" + R->getDecl()->getQualifiedNameAsString() + 216 "' inside " + Visit(R->getSuperRegion()); 217 } 218 219 std::string VisitSVal(SVal V) { 220 std::string Str; 221 llvm::raw_string_ostream OS(Str); 222 OS << V; 223 return "a value unsupported by the explainer: (" + 224 std::string(OS.str()) + ")"; 225 } 226 227 std::string VisitSymExpr(SymbolRef S) { 228 std::string Str; 229 llvm::raw_string_ostream OS(Str); 230 S->dumpToStream(OS); 231 return "a symbolic expression unsupported by the explainer: (" + 232 std::string(OS.str()) + ")"; 233 } 234 235 std::string VisitMemRegion(const MemRegion *R) { 236 std::string Str; 237 llvm::raw_string_ostream OS(Str); 238 OS << R; 239 return "a memory region unsupported by the explainer (" + 240 std::string(OS.str()) + ")"; 241 } 242 }; 243 244 } // end namespace ento 245 246 } // end namespace clang 247 248 #endif 249