//== Environment.cpp - Map from Stmt* to Locations/Values -------*- C++ -*--==// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defined the Environment and EnvironmentManager classes. // //===----------------------------------------------------------------------===// #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "llvm/Support/raw_ostream.h" using namespace clang; using namespace ento; static const Expr *ignoreTransparentExprs(const Expr *E) { E = E->IgnoreParens(); switch (E->getStmtClass()) { case Stmt::OpaqueValueExprClass: E = cast<OpaqueValueExpr>(E)->getSourceExpr(); break; case Stmt::ExprWithCleanupsClass: E = cast<ExprWithCleanups>(E)->getSubExpr(); break; case Stmt::CXXBindTemporaryExprClass: E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); break; case Stmt::SubstNonTypeTemplateParmExprClass: E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(); break; default: // This is the base case: we can't look through more than we already have. return E; } return ignoreTransparentExprs(E); } static const Stmt *ignoreTransparentExprs(const Stmt *S) { if (const Expr *E = dyn_cast<Expr>(S)) return ignoreTransparentExprs(E); return S; } EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L) : std::pair<const Stmt *, const StackFrameContext *>(ignoreTransparentExprs(S), L ? L->getCurrentStackFrame() : nullptr) {} SVal Environment::lookupExpr(const EnvironmentEntry &E) const { const SVal* X = ExprBindings.lookup(E); if (X) { SVal V = *X; return V; } return UnknownVal(); } SVal Environment::getSVal(const EnvironmentEntry &Entry, SValBuilder& svalBuilder) const { const Stmt *S = Entry.getStmt(); const LocationContext *LCtx = Entry.getLocationContext(); switch (S->getStmtClass()) { case Stmt::CXXBindTemporaryExprClass: case Stmt::ExprWithCleanupsClass: case Stmt::GenericSelectionExprClass: case Stmt::OpaqueValueExprClass: case Stmt::ParenExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: llvm_unreachable("Should have been handled by ignoreTransparentExprs"); case Stmt::AddrLabelExprClass: case Stmt::CharacterLiteralClass: case Stmt::CXXBoolLiteralExprClass: case Stmt::CXXScalarValueInitExprClass: case Stmt::ImplicitValueInitExprClass: case Stmt::IntegerLiteralClass: case Stmt::ObjCBoolLiteralExprClass: case Stmt::CXXNullPtrLiteralExprClass: case Stmt::ObjCStringLiteralClass: case Stmt::StringLiteralClass: // Known constants; defer to SValBuilder. return svalBuilder.getConstantVal(cast<Expr>(S)).getValue(); case Stmt::ReturnStmtClass: { const ReturnStmt *RS = cast<ReturnStmt>(S); if (const Expr *RE = RS->getRetValue()) return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder); return UndefinedVal(); } // Handle all other Stmt* using a lookup. default: return lookupExpr(EnvironmentEntry(S, LCtx)); } } Environment EnvironmentManager::bindExpr(Environment Env, const EnvironmentEntry &E, SVal V, bool Invalidate) { if (V.isUnknown()) { if (Invalidate) return Environment(F.remove(Env.ExprBindings, E)); else return Env; } return Environment(F.add(Env.ExprBindings, E, V)); } namespace { class MarkLiveCallback : public SymbolVisitor { SymbolReaper &SymReaper; public: MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} bool VisitSymbol(SymbolRef sym) override { SymReaper.markLive(sym); return true; } bool VisitMemRegion(const MemRegion *R) override { SymReaper.markLive(R); return true; } }; } // end anonymous namespace // removeDeadBindings: // - Remove subexpression bindings. // - Remove dead block expression bindings. // - Keep live block expression bindings: // - Mark their reachable symbols live in SymbolReaper, // see ScanReachableSymbols. // - Mark the region in DRoots if the binding is a loc::MemRegionVal. Environment EnvironmentManager::removeDeadBindings(Environment Env, SymbolReaper &SymReaper, ProgramStateRef ST) { // We construct a new Environment object entirely, as this is cheaper than // individually removing all the subexpression bindings (which will greatly // outnumber block-level expression bindings). Environment NewEnv = getInitialEnvironment(); MarkLiveCallback CB(SymReaper); ScanReachableSymbols RSScaner(ST, CB); llvm::ImmutableMapRef<EnvironmentEntry,SVal> EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), F.getTreeFactory()); // Iterate over the block-expr bindings. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { const EnvironmentEntry &BlkExpr = I.getKey(); const SVal &X = I.getData(); if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) { // Copy the binding to the new map. EBMapRef = EBMapRef.add(BlkExpr, X); // If the block expr's value is a memory region, then mark that region. if (Optional<loc::MemRegionVal> R = X.getAs<loc::MemRegionVal>()) SymReaper.markLive(R->getRegion()); // Mark all symbols in the block expr's value live. RSScaner.scan(X); continue; } else { SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); for (; SI != SE; ++SI) SymReaper.maybeDead(*SI); } } NewEnv.ExprBindings = EBMapRef.asImmutableMap(); return NewEnv; } void Environment::print(raw_ostream &Out, const char *NL, const char *Sep) const { bool isFirst = true; for (Environment::iterator I = begin(), E = end(); I != E; ++I) { const EnvironmentEntry &En = I.getKey(); if (isFirst) { Out << NL << NL << "Expressions:" << NL; isFirst = false; } else { Out << NL; } const Stmt *S = En.getStmt(); assert(S != nullptr && "Expected non-null Stmt"); Out << " (" << (const void*) En.getLocationContext() << ',' << (const void*) S << ") "; LangOptions LO; // FIXME. S->printPretty(Out, nullptr, PrintingPolicy(LO)); Out << " : " << I.getData(); } }