David Blaikie 903c29347a Wdeprecated: CollectReachableSymbolsCallback are move constructed/returned by value, so make sure they're copy/moveable
(return by value is in ExprEngine::processPointerEscapedOnBind and any
other call to the scanReachableSymbols function template used there)

Protect the special members in the base class to avoid slicing, and make
derived classes final so these special members don't accidentally become
public on an intermediate base which would open up the possibility of
slicing again.

llvm-svn: 244975
2015-08-13 22:50:09 +00:00

217 lines
6.7 KiB
C++

//== 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 final : 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();
}
}