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