#define DEBUG_TYPE "ExprEngine"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/Statistic.h"
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
#endif
using namespace clang;
using namespace ento;
using llvm::APSInt;
STATISTIC(NumRemoveDeadBindings,
"The # of times RemoveDeadBindings is called");
STATISTIC(NumMaxBlockCountReached,
"The # of aborted paths due to reaching the maximum block count in "
"a top level function");
STATISTIC(NumMaxBlockCountReachedInInlined,
"The # of aborted paths due to reaching the maximum block count in "
"an inlined function");
STATISTIC(NumTimesRetriedWithoutInlining,
"The # of times we re-evaluated a call without inlining");
ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS)
: AMgr(mgr),
AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
Engine(*this, FS),
G(Engine.getGraph()),
StateMgr(getContext(), mgr.getStoreManagerCreator(),
mgr.getConstraintManagerCreator(), G.getAllocator(),
this),
SymMgr(StateMgr.getSymbolManager()),
svalBuilder(StateMgr.getSValBuilder()),
EntryNode(NULL),
currStmt(NULL), currStmtIdx(0), currBldrCtx(0),
ObjCNoRet(mgr.getASTContext()),
ObjCGCEnabled(gcEnabled), BR(mgr, *this),
VisitedCallees(VisitedCalleesIn)
{
if (mgr.options.eagerlyTrimExplodedGraph) {
G.enableNodeReclamation();
}
}
ExprEngine::~ExprEngine() {
BR.FlushReports();
}
ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
ProgramStateRef state = StateMgr.getInitialState(InitLoc);
const Decl *D = InitLoc->getDecl();
do {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
const IdentifierInfo *II = FD->getIdentifier();
if (!II || !(II->getName() == "main" && FD->getNumParams() > 0))
break;
const ParmVarDecl *PD = FD->getParamDecl(0);
QualType T = PD->getType();
if (!T->isIntegerType())
break;
const MemRegion *R = state->getRegion(PD, InitLoc);
if (!R)
break;
SVal V = state->getSVal(loc::MemRegionVal(R));
SVal Constraint_untested = evalBinOp(state, BO_GT, V,
svalBuilder.makeZeroVal(T),
getContext().IntTy);
DefinedOrUnknownSVal *Constraint =
dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
if (!Constraint)
break;
if (ProgramStateRef newState = state->assume(*Constraint, true))
state = newState;
}
break;
}
while (0);
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
const ImplicitParamDecl *SelfD = MD->getSelfDecl();
const MemRegion *R = state->getRegion(SelfD, InitLoc);
SVal V = state->getSVal(loc::MemRegionVal(R));
if (const Loc *LV = dyn_cast<Loc>(&V)) {
state = state->assume(*LV, true);
assert(state && "'self' cannot be null");
}
}
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
if (!MD->isStatic()) {
const StackFrameContext *SFC = InitLoc->getCurrentStackFrame();
if (SFC->getParent() == 0) {
loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC);
SVal V = state->getSVal(L);
if (const Loc *LV = dyn_cast<Loc>(&V)) {
state = state->assume(*LV, true);
assert(state && "'this' cannot be null");
}
}
}
}
return state;
}
static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
const LocationContext *LC,
const Expr *E) {
SVal V = State->getSVal(E, LC);
if (isa<NonLoc>(V)) {
MemRegionManager &MRMgr = State->getStateManager().getRegionManager();
const MemRegion *R = MRMgr.getCXXTempObjectRegion(E, LC);
State = State->bindLoc(loc::MemRegionVal(R), V);
State = State->BindExpr(E, LC, loc::MemRegionVal(R));
}
return State;
}
ProgramStateRef ExprEngine::processAssume(ProgramStateRef state,
SVal cond, bool assumption) {
return getCheckerManager().runCheckersForEvalAssume(state, cond, assumption);
}
bool ExprEngine::wantsRegionChangeUpdate(ProgramStateRef state) {
return getCheckerManager().wantsRegionChangeUpdate(state);
}
ProgramStateRef
ExprEngine::processRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) {
return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
Explicits, Regions, Call);
}
void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) {
getCheckerManager().runCheckersForPrintState(Out, State, NL, Sep);
}
void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
}
void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
unsigned StmtIdx, NodeBuilderContext *Ctx) {
currStmtIdx = StmtIdx;
currBldrCtx = Ctx;
switch (E.getKind()) {
case CFGElement::Invalid:
llvm_unreachable("Unexpected CFGElement kind.");
case CFGElement::Statement:
ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Pred);
return;
case CFGElement::Initializer:
ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), Pred);
return;
case CFGElement::AutomaticObjectDtor:
case CFGElement::BaseDtor:
case CFGElement::MemberDtor:
case CFGElement::TemporaryDtor:
ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred);
return;
}
currBldrCtx = 0;
}
static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
const CFGStmt S,
const ExplodedNode *Pred,
const LocationContext *LC) {
if (AMgr.options.AnalysisPurgeOpt == PurgeNone)
return false;
if (isa<BlockEntrance>(Pred->getLocation()))
return true;
if (!isa<Expr>(S.getStmt()))
return true;
if (CallEvent::isCallStmt(S.getStmt()))
return true;
ParentMap &PM = LC->getAnalysisDeclContext()->getParentMap();
return !PM.isConsumedExpr(cast<Expr>(S.getStmt()));
}
void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
const Stmt *ReferenceStmt,
const LocationContext *LC,
const Stmt *DiagnosticStmt,
ProgramPoint::Kind K) {
assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
ReferenceStmt == 0) && "PreStmt is not generally supported by "
"the SymbolReaper yet");
NumRemoveDeadBindings++;
CleanedState = Pred->getState();
SymbolReaper SymReaper(LC, ReferenceStmt, SymMgr, getStoreManager());
getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
const StackFrameContext *SFC = LC->getCurrentStackFrame();
CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper);
static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node");
if (!SymReaper.hasDeadSymbols()) {
StmtNodeBuilder Bldr(Pred, Out, *currBldrCtx);
Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, &cleanupTag, K);
} else {
ExplodedNodeSet CheckedSet;
getCheckerManager().runCheckersForDeadSymbols(CheckedSet, Pred, SymReaper,
DiagnosticStmt, *this, K);
StmtNodeBuilder Bldr(CheckedSet, Out, *currBldrCtx);
for (ExplodedNodeSet::const_iterator
I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) {
ProgramStateRef CheckerState = (*I)->getState();
CheckerState = getConstraintManager().removeDeadBindings(CheckerState,
SymReaper);
assert(StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) &&
"Checkers are not allowed to modify the Environment as a part of "
"checkDeadSymbols processing.");
assert(StateMgr.haveEqualStores(CheckerState, Pred->getState()) &&
"Checkers are not allowed to modify the Store as a part of "
"checkDeadSymbols processing.");
ProgramStateRef CleanedCheckerSt =
StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, &cleanupTag, K);
}
}
}
void ExprEngine::ProcessStmt(const CFGStmt S,
ExplodedNode *Pred) {
G.reclaimRecentlyAllocatedNodes();
currStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
currStmt->getLocStart(),
"Error evaluating statement");
EntryNode = Pred;
ExplodedNodeSet CleanedStates;
if (shouldRemoveDeadBindings(AMgr, S, Pred, EntryNode->getLocationContext())){
removeDead(EntryNode, CleanedStates, currStmt,
Pred->getLocationContext(), currStmt);
} else
CleanedStates.Add(EntryNode);
ExplodedNodeSet Dst;
for (ExplodedNodeSet::iterator I = CleanedStates.begin(),
E = CleanedStates.end(); I != E; ++I) {
ExplodedNodeSet DstI;
Visit(currStmt, *I, DstI);
Dst.insert(DstI);
}
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
CleanedState = NULL;
EntryNode = NULL;
currStmt = 0;
}
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
ExplodedNode *Pred) {
const CXXCtorInitializer *BMI = Init.getInitializer();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
BMI->getSourceLocation(),
"Error evaluating initializer");
const StackFrameContext *stackFrame =
cast<StackFrameContext>(Pred->getLocationContext());
const CXXConstructorDecl *decl =
cast<CXXConstructorDecl>(stackFrame->getDecl());
ProgramStateRef State = Pred->getState();
SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame));
PostInitializer PP(BMI, stackFrame);
ExplodedNodeSet Tmp(Pred);
if (BMI->isAnyMemberInitializer()) {
const Expr *Init = BMI->getInit();
if (!isa<CXXConstructExpr>(Init)) {
SVal FieldLoc;
if (BMI->isIndirectMemberInitializer())
FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal);
else
FieldLoc = State->getLValue(BMI->getMember(), thisVal);
SVal InitVal = State->getSVal(BMI->getInit(), stackFrame);
Tmp.clear();
evalBind(Tmp, Init, Pred, FieldLoc, InitVal, true, &PP);
}
} else {
assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
}
ExplodedNodeSet Dst;
NodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
ExplodedNode *N = *I;
Bldr.generateNode(PP, N->getState(), N);
}
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
ExplodedNode *Pred) {
ExplodedNodeSet Dst;
switch (D.getKind()) {
case CFGElement::AutomaticObjectDtor:
ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), Pred, Dst);
break;
case CFGElement::BaseDtor:
ProcessBaseDtor(cast<CFGBaseDtor>(D), Pred, Dst);
break;
case CFGElement::MemberDtor:
ProcessMemberDtor(cast<CFGMemberDtor>(D), Pred, Dst);
break;
case CFGElement::TemporaryDtor:
ProcessTemporaryDtor(cast<CFGTemporaryDtor>(D), Pred, Dst);
break;
default:
llvm_unreachable("Unexpected dtor kind.");
}
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ProgramStateRef state = Pred->getState();
const VarDecl *varDecl = Dtor.getVarDecl();
QualType varType = varDecl->getType();
if (const ReferenceType *refType = varType->getAs<ReferenceType>())
varType = refType->getPointeeType();
Loc dest = state->getLValue(varDecl, Pred->getLocationContext());
VisitCXXDestructor(varType, cast<loc::MemRegionVal>(dest).getRegion(),
Dtor.getTriggerStmt(), false, Pred, Dst);
}
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor,
LCtx->getCurrentStackFrame());
SVal ThisVal = Pred->getState()->getSVal(ThisPtr);
QualType BaseTy = D.getBaseSpecifier()->getType();
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
VisitCXXDestructor(BaseTy, cast<loc::MemRegionVal>(BaseVal).getRegion(),
CurDtor->getBody(), true, Pred, Dst);
}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
const FieldDecl *Member = D.getFieldDecl();
ProgramStateRef State = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
Loc ThisVal = getSValBuilder().getCXXThis(CurDtor,
LCtx->getCurrentStackFrame());
SVal FieldVal = State->getLValue(Member, cast<Loc>(State->getSVal(ThisVal)));
VisitCXXDestructor(Member->getType(),
cast<loc::MemRegionVal>(FieldVal).getRegion(),
CurDtor->getBody(), false, Pred, Dst);
}
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {}
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet &DstTop) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
S->getLocStart(),
"Error evaluating statement");
ExplodedNodeSet Dst;
StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx);
if (const Expr *Ex = dyn_cast<Expr>(S))
S = Ex->IgnoreParens();
if (S != currStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
return;
switch (S->getStmtClass()) {
case Expr::ObjCIndirectCopyRestoreExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTryStmtClass:
case Stmt::CXXTypeidExprClass:
case Stmt::CXXUuidofExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::UnaryTypeTraitExprClass:
case Stmt::BinaryTypeTraitExprClass:
case Stmt::TypeTraitExprClass:
case Stmt::ArrayTypeTraitExprClass:
case Stmt::ExpressionTraitExprClass:
case Stmt::UnresolvedLookupExprClass:
case Stmt::UnresolvedMemberExprClass:
case Stmt::CXXNoexceptExprClass:
case Stmt::PackExpansionExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
case Stmt::FunctionParmPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::LambdaExprClass:
case Stmt::SEHFinallyStmtClass: {
const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
Engine.addAbortedBlock(node, currBldrCtx->getBlock());
break;
}
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
case Stmt::GenericSelectionExprClass:
llvm_unreachable("GenericSelectionExprs already handled.");
case Stmt::BreakStmtClass:
case Stmt::CaseStmtClass:
case Stmt::CompoundStmtClass:
case Stmt::ContinueStmtClass:
case Stmt::CXXForRangeStmtClass:
case Stmt::DefaultStmtClass:
case Stmt::DoStmtClass:
case Stmt::ForStmtClass:
case Stmt::GotoStmtClass:
case Stmt::IfStmtClass:
case Stmt::IndirectGotoStmtClass:
case Stmt::LabelStmtClass:
case Stmt::AttributedStmtClass:
case Stmt::NoStmtClass:
case Stmt::NullStmtClass:
case Stmt::SwitchStmtClass:
case Stmt::WhileStmtClass:
case Expr::MSDependentExistsStmtClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
case Stmt::ObjCSubscriptRefExprClass:
case Stmt::ObjCPropertyRefExprClass:
llvm_unreachable("These are handled by PseudoObjectExpr");
case Stmt::GNUNullExprClass: {
ProgramStateRef state = Pred->getState();
state = state->BindExpr(S, Pred->getLocationContext(),
svalBuilder.makeIntValWithPtrWidth(0, false));
Bldr.generateNode(S, Pred, state);
break;
}
case Stmt::ObjCAtSynchronizedStmtClass:
Bldr.takeNodes(Pred);
VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::ExprWithCleanupsClass:
break;
case Stmt::DesignatedInitExprClass:
case Stmt::ExtVectorElementExprClass:
case Stmt::ImaginaryLiteralClass:
case Stmt::ObjCAtCatchStmtClass:
case Stmt::ObjCAtFinallyStmtClass:
case Stmt::ObjCAtTryStmtClass:
case Stmt::ObjCAutoreleasePoolStmtClass:
case Stmt::ObjCEncodeExprClass:
case Stmt::ObjCIsaExprClass:
case Stmt::ObjCProtocolExprClass:
case Stmt::ObjCSelectorExprClass:
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
case Stmt::VAArgExprClass:
case Stmt::CUDAKernelCallExprClass:
case Stmt::OpaqueValueExprClass:
case Stmt::AsTypeExprClass:
case Stmt::AtomicExprClass:
case Stmt::AddrLabelExprClass:
case Stmt::IntegerLiteralClass:
case Stmt::CharacterLiteralClass:
case Stmt::ImplicitValueInitExprClass:
case Stmt::CXXScalarValueInitExprClass:
case Stmt::CXXBoolLiteralExprClass:
case Stmt::ObjCBoolLiteralExprClass:
case Stmt::FloatingLiteralClass:
case Stmt::SizeOfPackExprClass:
case Stmt::StringLiteralClass:
case Stmt::ObjCStringLiteralClass:
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXDefaultArgExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::CXXNullPtrLiteralExprClass: {
Bldr.takeNodes(Pred);
ExplodedNodeSet preVisit;
getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this);
Bldr.addNodes(Dst);
break;
}
case Expr::ObjCArrayLiteralClass:
case Expr::ObjCDictionaryLiteralClass:
case Expr::ObjCBoxedExprClass: {
Bldr.takeNodes(Pred);
ExplodedNodeSet preVisit;
getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx);
const Expr *Ex = cast<Expr>(S);
QualType resultType = Ex->getType();
for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end();
it != et; ++it) {
ExplodedNode *N = *it;
const LocationContext *LCtx = N->getLocationContext();
SVal result = svalBuilder.conjureSymbolVal(0, Ex, LCtx, resultType,
currBldrCtx->blockCount());
ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result);
Bldr2.generateNode(S, N, state);
}
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
Bldr.addNodes(Dst);
break;
}
case Stmt::ArraySubscriptExprClass:
Bldr.takeNodes(Pred);
VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::GCCAsmStmtClass:
Bldr.takeNodes(Pred);
VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::MSAsmStmtClass:
Bldr.takeNodes(Pred);
VisitMSAsmStmt(cast<MSAsmStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::BlockExprClass:
Bldr.takeNodes(Pred);
VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::BinaryOperatorClass: {
const BinaryOperator* B = cast<BinaryOperator>(S);
if (B->isLogicalOp()) {
Bldr.takeNodes(Pred);
VisitLogicalExpr(B, Pred, Dst);
Bldr.addNodes(Dst);
break;
}
else if (B->getOpcode() == BO_Comma) {
ProgramStateRef state = Pred->getState();
Bldr.generateNode(B, Pred,
state->BindExpr(B, Pred->getLocationContext(),
state->getSVal(B->getRHS(),
Pred->getLocationContext())));
break;
}
Bldr.takeNodes(Pred);
if (AMgr.options.eagerlyAssumeBinOpBifurcation &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S));
}
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::CXXOperatorCallExprClass: {
const CXXOperatorCallExpr *OCE = cast<CXXOperatorCallExpr>(S);
const Decl *Callee = OCE->getCalleeDecl();
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) {
if (MD->isInstance()) {
ProgramStateRef State = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef NewState =
createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0));
if (NewState != State)
Pred = Bldr.generateNode(OCE, Pred, NewState, 0,
ProgramPoint::PreStmtKind);
}
}
}
case Stmt::CallExprClass:
case Stmt::CXXMemberCallExprClass:
case Stmt::UserDefinedLiteralClass: {
Bldr.takeNodes(Pred);
VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::CXXCatchStmtClass: {
Bldr.takeNodes(Pred);
VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXConstructExprClass: {
Bldr.takeNodes(Pred);
VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::CXXNewExprClass: {
Bldr.takeNodes(Pred);
const CXXNewExpr *NE = cast<CXXNewExpr>(S);
VisitCXXNewExpr(NE, Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::CXXDeleteExprClass: {
Bldr.takeNodes(Pred);
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
VisitCXXDeleteExpr(CDE, Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::ChooseExprClass: { Bldr.takeNodes(Pred);
const ChooseExpr *C = cast<ChooseExpr>(S);
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::CompoundAssignOperatorClass:
Bldr.takeNodes(Pred);
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::CompoundLiteralExprClass:
Bldr.takeNodes(Pred);
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: { Bldr.takeNodes(Pred);
const AbstractConditionalOperator *C
= cast<AbstractConditionalOperator>(S);
VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::CXXThisExprClass:
Bldr.takeNodes(Pred);
VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::DeclRefExprClass: {
Bldr.takeNodes(Pred);
const DeclRefExpr *DE = cast<DeclRefExpr>(S);
VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::DeclStmtClass:
Bldr.takeNodes(Pred);
VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass:
case Stmt::CXXStaticCastExprClass:
case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXReinterpretCastExprClass:
case Stmt::CXXConstCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
case Stmt::ObjCBridgedCastExprClass: {
Bldr.takeNodes(Pred);
const CastExpr *C = cast<CastExpr>(S);
ExplodedNodeSet dstPrevisit;
getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this);
ExplodedNodeSet dstExpr;
for (ExplodedNodeSet::iterator i = dstPrevisit.begin(),
e = dstPrevisit.end(); i != e ; ++i) {
VisitCast(C, C->getSubExpr(), *i, dstExpr);
}
getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
Bldr.addNodes(Dst);
break;
}
case Expr::MaterializeTemporaryExprClass: {
Bldr.takeNodes(Pred);
const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S);
CreateCXXTemporaryObject(MTE, Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::InitListExprClass:
Bldr.takeNodes(Pred);
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::MemberExprClass:
Bldr.takeNodes(Pred);
VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::ObjCIvarRefExprClass:
Bldr.takeNodes(Pred);
VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::ObjCForCollectionStmtClass:
Bldr.takeNodes(Pred);
VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::ObjCMessageExprClass:
Bldr.takeNodes(Pred);
VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::ObjCAtThrowStmtClass:
case Stmt::CXXThrowExprClass:
Bldr.generateSink(S, Pred, Pred->getState());
break;
case Stmt::ReturnStmtClass:
Bldr.takeNodes(Pred);
VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::OffsetOfExprClass:
Bldr.takeNodes(Pred);
VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::UnaryExprOrTypeTraitExprClass:
Bldr.takeNodes(Pred);
VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
Pred, Dst);
Bldr.addNodes(Dst);
break;
case Stmt::StmtExprClass: {
const StmtExpr *SE = cast<StmtExpr>(S);
if (SE->getSubStmt()->body_empty()) {
assert(SE->getType() == getContext().VoidTy
&& "Empty statement expression must have void type.");
break;
}
if (Expr *LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
ProgramStateRef state = Pred->getState();
Bldr.generateNode(SE, Pred,
state->BindExpr(SE, Pred->getLocationContext(),
state->getSVal(LastExpr,
Pred->getLocationContext())));
}
break;
}
case Stmt::UnaryOperatorClass: {
Bldr.takeNodes(Pred);
const UnaryOperator *U = cast<UnaryOperator>(S);
if (AMgr.options.eagerlyAssumeBinOpBifurcation && (U->getOpcode() == UO_LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp);
evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U);
}
else
VisitUnaryOperator(U, Pred, Dst);
Bldr.addNodes(Dst);
break;
}
case Stmt::PseudoObjectExprClass: {
Bldr.takeNodes(Pred);
ProgramStateRef state = Pred->getState();
const PseudoObjectExpr *PE = cast<PseudoObjectExpr>(S);
if (const Expr *Result = PE->getResultExpr()) {
SVal V = state->getSVal(Result, Pred->getLocationContext());
Bldr.generateNode(S, Pred,
state->BindExpr(S, Pred->getLocationContext(), V));
}
else
Bldr.generateNode(S, Pred,
state->BindExpr(S, Pred->getLocationContext(),
UnknownVal()));
Bldr.addNodes(Dst);
break;
}
}
}
bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
const LocationContext *CalleeLC) {
const StackFrameContext *CalleeSF = CalleeLC->getCurrentStackFrame();
const StackFrameContext *CallerSF = CalleeSF->getParent()->getCurrentStackFrame();
assert(CalleeSF && CallerSF);
ExplodedNode *BeforeProcessingCall = 0;
const Stmt *CE = CalleeSF->getCallSite();
while (N) {
ProgramPoint L = N->getLocation();
BeforeProcessingCall = N;
N = N->pred_empty() ? NULL : *(N->pred_begin());
if (L.getLocationContext()->getCurrentStackFrame() != CallerSF)
continue;
if (L.isPurgeKind())
continue;
if (isa<PreImplicitCall>(&L))
continue;
if (isa<CallEnter>(&L))
continue;
if (const StmtPoint *SP = dyn_cast<StmtPoint>(&L))
if (SP->getStmt() == CE)
continue;
break;
}
if (!BeforeProcessingCall)
return false;
ProgramPoint NewNodeLoc =
EpsilonPoint(BeforeProcessingCall->getLocationContext(), CE);
ProgramStateRef NewNodeState = BeforeProcessingCall->getState();
NewNodeState = NewNodeState->set<ReplayWithoutInlining>((void*)CE);
bool IsNew = false;
ExplodedNode *NewNode = G.getNode(NewNodeLoc, NewNodeState, false, &IsNew);
if (!IsNew)
return true;
NewNode->addPredecessor(BeforeProcessingCall, G);
Engine.enqueueStmtNode(NewNode, CalleeSF->getCallSiteBlock(),
CalleeSF->getIndex());
NumTimesRetriedWithoutInlining++;
return true;
}
void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
NodeBuilderWithSinks &nodeBuilder) {
ExplodedNode *pred = nodeBuilder.getContext().getPred();
if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) {
static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
const ExplodedNode *Sink =
nodeBuilder.generateSink(pred->getState(), pred, &tag);
const LocationContext *CalleeLC = pred->getLocation().getLocationContext();
const LocationContext *CalleeSF = CalleeLC->getCurrentStackFrame();
const LocationContext *RootLC =
(*G.roots_begin())->getLocation().getLocationContext();
if (RootLC->getCurrentStackFrame() != CalleeSF) {
Engine.FunctionSummaries->markReachedMaxBlockCount(CalleeSF->getDecl());
if ((!AMgr.options.NoRetryExhausted &&
replayWithoutInlining(pred, CalleeLC)))
return;
NumMaxBlockCountReachedInInlined++;
} else
NumMaxBlockCountReached++;
Engine.blocksExhausted.push_back(std::make_pair(L, Sink));
}
}
static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr,
ProgramStateRef state,
const Stmt *Condition,
const LocationContext *LCtx,
ASTContext &Ctx) {
const Expr *Ex = dyn_cast<Expr>(Condition);
if (!Ex)
return UnknownVal();
uint64_t bits = 0;
bool bitsInit = false;
while (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
QualType T = CE->getType();
if (!T->isIntegerType())
return UnknownVal();
uint64_t newBits = Ctx.getTypeSize(T);
if (!bitsInit || newBits < bits) {
bitsInit = true;
bits = newBits;
}
Ex = CE->getSubExpr();
}
QualType T = Ex->getType();
if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits)
return UnknownVal();
return state->getSVal(Ex, LCtx);
}
static const Stmt *ResolveCondition(const Stmt *Condition,
const CFGBlock *B) {
if (const Expr *Ex = dyn_cast<Expr>(Condition))
Condition = Ex->IgnoreParens();
const BinaryOperator *BO = dyn_cast<BinaryOperator>(Condition);
if (!BO || !BO->isLogicalOp())
return Condition;
CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend();
for (; I != E; ++I) {
CFGElement Elem = *I;
CFGStmt *CS = dyn_cast<CFGStmt>(&Elem);
if (!CS)
continue;
if (CS->getStmt() != Condition)
break;
return Condition;
}
assert(I != E);
while (Condition) {
BO = dyn_cast<BinaryOperator>(Condition);
if (!BO || !BO->isLogicalOp())
return Condition;
Condition = BO->getRHS()->IgnoreParens();
}
llvm_unreachable("could not resolve condition");
}
void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
NodeBuilderContext& BldCtx,
ExplodedNode *Pred,
ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
currBldrCtx = &BldCtx;
if (!Condition) {
BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF);
NullCondBldr.markInfeasible(false);
NullCondBldr.generateNode(Pred->getState(), true, Pred);
return;
}
if (const Expr *Ex = dyn_cast<Expr>(Condition))
Condition = Ex->IgnoreParens();
Condition = ResolveCondition(Condition, BldCtx.getBlock());
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Condition->getLocStart(),
"Error evaluating branch");
ExplodedNodeSet CheckersOutSet;
getCheckerManager().runCheckersForBranchCondition(Condition, CheckersOutSet,
Pred, *this);
if (CheckersOutSet.empty())
return;
BranchNodeBuilder builder(CheckersOutSet, Dst, BldCtx, DstT, DstF);
for (NodeBuilder::iterator I = CheckersOutSet.begin(),
E = CheckersOutSet.end(); E != I; ++I) {
ExplodedNode *PredI = *I;
if (PredI->isSink())
continue;
ProgramStateRef PrevState = Pred->getState();
SVal X = PrevState->getSVal(Condition, Pred->getLocationContext());
if (X.isUnknownOrUndef()) {
if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
if (Ex->getType()->isIntegerType()) {
SVal recovered = RecoverCastedSymbol(getStateManager(),
PrevState, Condition,
Pred->getLocationContext(),
getContext());
if (!recovered.isUnknown()) {
X = recovered;
}
}
}
}
if (X.isUnknownOrUndef()) {
builder.generateNode(PrevState, true, PredI);
builder.generateNode(PrevState, false, PredI);
continue;
}
DefinedSVal V = cast<DefinedSVal>(X);
if (builder.isFeasible(true)) {
if (ProgramStateRef state = PrevState->assume(V, true))
builder.generateNode(state, true, PredI);
else
builder.markInfeasible(true);
}
if (builder.isFeasible(false)) {
if (ProgramStateRef state = PrevState->assume(V, false))
builder.generateNode(state, false, PredI);
else
builder.markInfeasible(false);
}
}
currBldrCtx = 0;
}
void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
ProgramStateRef state = builder.getState();
SVal V = state->getSVal(builder.getTarget(), builder.getLocationContext());
typedef IndirectGotoNodeBuilder::iterator iterator;
if (isa<loc::GotoLabel>(V)) {
const LabelDecl *L = cast<loc::GotoLabel>(V).getLabel();
for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) {
if (I.getLabel() == L) {
builder.generateNode(I, state);
return;
}
}
llvm_unreachable("No block with label.");
}
if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
return;
}
for (iterator I=builder.begin(), E=builder.end(); I != E; ++I)
builder.generateNode(I, state);
}
void ExprEngine::processEndOfFunction(NodeBuilderContext& BC) {
StateMgr.EndPath(BC.Pred->getState());
ExplodedNodeSet Dst;
getCheckerManager().runCheckersForEndPath(BC, Dst, *this);
Engine.enqueueEndOfFunction(Dst);
}
void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
typedef SwitchNodeBuilder::iterator iterator;
ProgramStateRef state = builder.getState();
const Expr *CondE = builder.getCondition();
SVal CondV_untested = state->getSVal(CondE, builder.getLocationContext());
if (CondV_untested.isUndef()) {
return;
}
DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
ProgramStateRef DefaultSt = state;
iterator I = builder.begin(), EI = builder.end();
bool defaultIsFeasible = I == EI;
for ( ; I != EI; ++I) {
if (!I.getBlock())
continue;
const CaseStmt *Case = I.getCase();
llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext());
assert(V1.getBitWidth() == getContext().getTypeSize(CondE->getType()));
llvm::APSInt V2;
if (const Expr *E = Case->getRHS())
V2 = E->EvaluateKnownConstInt(getContext());
else
V2 = V1;
do {
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1));
DefinedOrUnknownSVal Res = svalBuilder.evalEQ(DefaultSt ? DefaultSt : state,
CondV, CaseVal);
if (ProgramStateRef stateNew = state->assume(Res, true)) {
builder.generateCaseStmtNode(I, stateNew);
if (isa<nonloc::ConcreteInt>(CondV))
return;
}
if (DefaultSt) {
if (ProgramStateRef stateNew = DefaultSt->assume(Res, false)) {
defaultIsFeasible = true;
DefaultSt = stateNew;
}
else {
defaultIsFeasible = false;
DefaultSt = NULL;
}
}
if (V1 == V2)
break;
++V1;
assert (V1 <= V2);
} while (true);
}
if (!defaultIsFeasible)
return;
const SwitchStmt *SS = builder.getSwitch();
const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts();
if (CondExpr->getType()->getAs<EnumType>()) {
if (SS->isAllEnumCasesCovered())
return;
}
builder.generateDefaultCaseNode(DefaultSt);
}
void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
assert(Ex->isGLValue());
SVal V = state->getLValue(VD, Pred->getLocationContext());
if (VD->getType()->isReferenceType()) {
if (const MemRegion *R = V.getAsRegion())
V = state->getSVal(R);
else
V = UnknownVal();
}
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
}
if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) {
assert(!Ex->isGLValue());
SVal V = svalBuilder.makeIntVal(ED->getInitVal());
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V));
return;
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
SVal V = svalBuilder.getFunctionPointer(FD);
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
}
if (isa<FieldDecl>(D)) {
SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
currBldrCtx->blockCount());
state = state->assume(cast<DefinedOrUnknownSVal>(V), true);
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
}
llvm_unreachable("Support for this Decl not implemented.");
}
void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
ExplodedNode *Pred,
ExplodedNodeSet &Dst){
const Expr *Base = A->getBase()->IgnoreParens();
const Expr *Idx = A->getIdx()->IgnoreParens();
ExplodedNodeSet checkerPreStmt;
getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
StmtNodeBuilder Bldr(checkerPreStmt, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(),
ei = checkerPreStmt.end(); it != ei; ++it) {
const LocationContext *LCtx = (*it)->getLocationContext();
ProgramStateRef state = (*it)->getState();
SVal V = state->getLValue(A->getType(),
state->getSVal(Idx, LCtx),
state->getSVal(Base, LCtx));
assert(A->isGLValue());
Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0,
ProgramPoint::PostLValueKind);
}
}
void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
ExplodedNodeSet &TopDst) {
StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx);
ExplodedNodeSet Dst;
ValueDecl *Member = M->getMemberDecl();
if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) {
Bldr.takeNodes(Pred);
VisitCommonDeclRefExpr(M, Member, Pred, Dst);
Bldr.addNodes(Dst);
return;
}
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
Expr *BaseExpr = M->getBase();
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
if (MD->isInstance())
state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
SVal MDVal = svalBuilder.getFunctionPointer(MD);
state = state->BindExpr(M, LCtx, MDVal);
Bldr.generateNode(M, Pred, state);
return;
}
state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
SVal baseExprVal = state->getSVal(BaseExpr, LCtx);
FieldDecl *field = cast<FieldDecl>(Member);
SVal L = state->getLValue(field, baseExprVal);
if (M->isGLValue()) {
if (field->getType()->isReferenceType()) {
if (const MemRegion *R = L.getAsRegion())
L = state->getSVal(R);
else
L = UnknownVal();
}
Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0,
ProgramPoint::PostLValueKind);
} else {
Bldr.takeNodes(Pred);
evalLoad(Dst, M, M, Pred, state, L);
Bldr.addNodes(Dst);
}
}
void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
ExplodedNode *Pred,
SVal location, SVal Val,
bool atDeclInit, const ProgramPoint *PP) {
const LocationContext *LC = Pred->getLocationContext();
PostStmt PS(StoreE, LC);
if (!PP)
PP = &PS;
ExplodedNodeSet CheckedSet;
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
StoreE, *this, *PP);
if (!isa<Loc>(location)) {
Dst = CheckedSet;
return;
}
ExplodedNodeSet TmpDst;
StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
ExplodedNode *PredI = *I;
ProgramStateRef state = PredI->getState();
state = state->bindLoc(cast<Loc>(location),
Val, !atDeclInit);
const MemRegion *LocReg = 0;
if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) {
LocReg = LocRegVal->getRegion();
}
const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0);
Bldr.generateNode(L, state, PredI);
}
Dst.insert(TmpDst);
}
void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
const Expr *LocationE,
ExplodedNode *Pred,
ProgramStateRef state, SVal location, SVal Val,
const ProgramPointTag *tag) {
const Expr *StoreE = AssignE ? AssignE : LocationE;
ExplodedNodeSet Tmp;
evalLocation(Tmp, AssignE, LocationE, Pred, state, location, tag, false);
if (Tmp.empty())
return;
if (location.isUndef())
return;
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
evalBind(Dst, StoreE, *NI, location, Val, false);
}
void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
const Expr *NodeEx,
const Expr *BoundEx,
ExplodedNode *Pred,
ProgramStateRef state,
SVal location,
const ProgramPointTag *tag,
QualType LoadTy)
{
assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
if (const TypedValueRegion *TR =
dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
QualType ValTy = TR->getValueType();
if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
static SimpleProgramPointTag
loadReferenceTag("ExprEngine : Load Reference");
ExplodedNodeSet Tmp;
evalLoadCommon(Tmp, NodeEx, BoundEx, Pred, state,
location, &loadReferenceTag,
getContext().getPointerType(RT->getPointeeType()));
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
state = (*I)->getState();
location = state->getSVal(BoundEx, (*I)->getLocationContext());
evalLoadCommon(Dst, NodeEx, BoundEx, *I, state, location, tag, LoadTy);
}
return;
}
}
evalLoadCommon(Dst, NodeEx, BoundEx, Pred, state, location, tag, LoadTy);
}
void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
const Expr *NodeEx,
const Expr *BoundEx,
ExplodedNode *Pred,
ProgramStateRef state,
SVal location,
const ProgramPointTag *tag,
QualType LoadTy) {
assert(NodeEx);
assert(BoundEx);
ExplodedNodeSet Tmp;
evalLocation(Tmp, NodeEx, BoundEx, Pred, state, location, tag, true);
if (Tmp.empty())
return;
StmtNodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
if (location.isUndef())
return;
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
state = (*NI)->getState();
const LocationContext *LCtx = (*NI)->getLocationContext();
if (location.isUnknown()) {
Bldr.generateNode(NodeEx, *NI,
state->BindExpr(BoundEx, LCtx, UnknownVal()),
tag, ProgramPoint::PostLoadKind);
}
else {
if (LoadTy.isNull())
LoadTy = BoundEx->getType();
SVal V = state->getSVal(cast<Loc>(location), LoadTy);
Bldr.generateNode(NodeEx, *NI,
state->bindExprAndLocation(BoundEx, LCtx, location, V),
tag, ProgramPoint::PostLoadKind);
}
}
}
void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
const Stmt *NodeEx,
const Stmt *BoundEx,
ExplodedNode *Pred,
ProgramStateRef state,
SVal location,
const ProgramPointTag *tag,
bool isLoad) {
StmtNodeBuilder BldrTop(Pred, Dst, *currBldrCtx);
if (location.isUnknown()) {
return;
}
ExplodedNodeSet Src;
BldrTop.takeNodes(Pred);
StmtNodeBuilder Bldr(Pred, Src, *currBldrCtx);
if (Pred->getState() != state) {
static SimpleProgramPointTag tag("ExprEngine: Location");
Bldr.generateNode(NodeEx, Pred, state, &tag);
}
ExplodedNodeSet Tmp;
getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad,
NodeEx, BoundEx, *this);
BldrTop.addNodes(Tmp);
}
std::pair<const ProgramPointTag *, const ProgramPointTag*>
ExprEngine::geteagerlyAssumeBinOpBifurcationTags() {
static SimpleProgramPointTag
eagerlyAssumeBinOpBifurcationTrue("ExprEngine : Eagerly Assume True"),
eagerlyAssumeBinOpBifurcationFalse("ExprEngine : Eagerly Assume False");
return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue,
&eagerlyAssumeBinOpBifurcationFalse);
}
void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
ExplodedNodeSet &Src,
const Expr *Ex) {
StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
ExplodedNode *Pred = *I;
ProgramPoint P = Pred->getLocation();
if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
continue;
}
ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(Ex, Pred->getLocationContext());
nonloc::SymbolVal *SEV = dyn_cast<nonloc::SymbolVal>(&V);
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
geteagerlyAssumeBinOpBifurcationTags();
if (ProgramStateRef StateTrue = state->assume(*SEV, true)) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
}
if (ProgramStateRef StateFalse = state->assume(*SEV, false)) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateFalse, tags.second);
}
}
}
}
void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
SVal X = state->getSVal(*OI, Pred->getLocationContext());
assert (!isa<NonLoc>(X));
if (isa<Loc>(X))
state = state->bindLoc(cast<Loc>(X), UnknownVal());
}
Bldr.generateNode(A, Pred, state);
}
void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(A, Pred, Pred->getState());
}
#ifndef NDEBUG
static ExprEngine* GraphPrintCheckerState;
static SourceManager* GraphPrintSourceManager;
namespace llvm {
template<>
struct DOTGraphTraits<ExplodedNode*> :
public DefaultDOTGraphTraits {
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
static std::string getNodeAttributes(const ExplodedNode *N, void*) {
#if 0
if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
GraphPrintCheckerState->isExplicitNullDeref(N) ||
GraphPrintCheckerState->isUndefDeref(N) ||
GraphPrintCheckerState->isUndefStore(N) ||
GraphPrintCheckerState->isUndefControlFlow(N) ||
GraphPrintCheckerState->isUndefResult(N) ||
GraphPrintCheckerState->isBadCall(N) ||
GraphPrintCheckerState->isUndefArg(N))
return "color=\"red\",style=\"filled\"";
if (GraphPrintCheckerState->isNoReturnCall(N))
return "color=\"blue\",style=\"filled\"";
#endif
return "";
}
static void printLocation(llvm::raw_ostream &Out, SourceLocation SLoc) {
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getExpansionLineNumber(SLoc)
<< " col="
<< GraphPrintSourceManager->getExpansionColumnNumber(SLoc)
<< "\\l";
}
}
static std::string getNodeLabel(const ExplodedNode *N, void*){
std::string sbuf;
llvm::raw_string_ostream Out(sbuf);
ProgramPoint Loc = N->getLocation();
switch (Loc.getKind()) {
case ProgramPoint::BlockEntranceKind: {
Out << "Block Entrance: B"
<< cast<BlockEntrance>(Loc).getBlock()->getBlockID();
if (const NamedDecl *ND =
dyn_cast<NamedDecl>(Loc.getLocationContext()->getDecl())) {
Out << " (";
ND->printName(Out);
Out << ")";
}
break;
}
case ProgramPoint::BlockExitKind:
assert (false);
break;
case ProgramPoint::CallEnterKind:
Out << "CallEnter";
break;
case ProgramPoint::CallExitBeginKind:
Out << "CallExitBegin";
break;
case ProgramPoint::CallExitEndKind:
Out << "CallExitEnd";
break;
case ProgramPoint::PostStmtPurgeDeadSymbolsKind:
Out << "PostStmtPurgeDeadSymbols";
break;
case ProgramPoint::PreStmtPurgeDeadSymbolsKind:
Out << "PreStmtPurgeDeadSymbols";
break;
case ProgramPoint::EpsilonKind:
Out << "Epsilon Point";
break;
case ProgramPoint::PreImplicitCallKind: {
ImplicitCallPoint *PC = cast<ImplicitCallPoint>(&Loc);
Out << "PreCall: ";
PC->getDecl()->print(Out, LangOptions());
printLocation(Out, PC->getLocation());
break;
}
case ProgramPoint::PostImplicitCallKind: {
ImplicitCallPoint *PC = cast<ImplicitCallPoint>(&Loc);
Out << "PostCall: ";
PC->getDecl()->print(Out, LangOptions());
printLocation(Out, PC->getLocation());
break;
}
default: {
if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
const Stmt *S = L->getStmt();
Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
LangOptions LO; S->printPretty(Out, 0, PrintingPolicy(LO));
printLocation(Out, S->getLocStart());
if (isa<PreStmt>(Loc))
Out << "\\lPreStmt\\l;";
else if (isa<PostLoad>(Loc))
Out << "\\lPostLoad\\l;";
else if (isa<PostStore>(Loc))
Out << "\\lPostStore\\l";
else if (isa<PostLValue>(Loc))
Out << "\\lPostLValue\\l";
#if 0
if (GraphPrintCheckerState->isImplicitNullDeref(N))
Out << "\\|Implicit-Null Dereference.\\l";
else if (GraphPrintCheckerState->isExplicitNullDeref(N))
Out << "\\|Explicit-Null Dereference.\\l";
else if (GraphPrintCheckerState->isUndefDeref(N))
Out << "\\|Dereference of undefialied value.\\l";
else if (GraphPrintCheckerState->isUndefStore(N))
Out << "\\|Store to Undefined Loc.";
else if (GraphPrintCheckerState->isUndefResult(N))
Out << "\\|Result of operation is undefined.";
else if (GraphPrintCheckerState->isNoReturnCall(N))
Out << "\\|Call to function marked \"noreturn\".";
else if (GraphPrintCheckerState->isBadCall(N))
Out << "\\|Call to NULL/Undefined.";
else if (GraphPrintCheckerState->isUndefArg(N))
Out << "\\|Argument in call is undefined";
#endif
break;
}
const BlockEdge &E = cast<BlockEdge>(Loc);
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
<< E.getDst()->getBlockID() << ')';
if (const Stmt *T = E.getSrc()->getTerminator()) {
SourceLocation SLoc = T->getLocStart();
Out << "\\|Terminator: ";
LangOptions LO; E.getSrc()->printTerminator(Out, LO);
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getExpansionLineNumber(SLoc)
<< " col="
<< GraphPrintSourceManager->getExpansionColumnNumber(SLoc);
}
if (isa<SwitchStmt>(T)) {
const Stmt *Label = E.getDst()->getLabel();
if (Label) {
if (const CaseStmt *C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
LangOptions LO; C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO));
if (const Stmt *RHS = C->getRHS()) {
Out << " .. ";
RHS->printPretty(Out, 0, PrintingPolicy(LO));
}
Out << ":";
}
else {
assert (isa<DefaultStmt>(Label));
Out << "\\ldefault:";
}
}
else
Out << "\\l(implicit) default:";
}
else if (isa<IndirectGotoStmt>(T)) {
}
else {
Out << "\\lCondition: ";
if (*E.getSrc()->succ_begin() == E.getDst())
Out << "true";
else
Out << "false";
}
Out << "\\l";
}
#if 0
if (GraphPrintCheckerState->isUndefControlFlow(N)) {
Out << "\\|Control-flow based on\\lUndefined value.\\l";
}
#endif
}
}
ProgramStateRef state = N->getState();
Out << "\\|StateID: " << (const void*) state.getPtr()
<< " NodeID: " << (const void*) N << "\\|";
state->printDOT(Out);
Out << "\\l";
if (const ProgramPointTag *tag = Loc.getTag()) {
Out << "\\|Tag: " << tag->getTagDescription();
Out << "\\l";
}
return Out.str();
}
};
} #endif
#ifndef NDEBUG
template <typename ITERATOR>
ExplodedNode *GetGraphNode(ITERATOR I) { return *I; }
template <> ExplodedNode*
GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
(llvm::DenseMap<ExplodedNode*, Expr*>::iterator I) {
return I->first;
}
#endif
void ExprEngine::ViewGraph(bool trim) {
#ifndef NDEBUG
if (trim) {
std::vector<ExplodedNode*> Src;
for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I)
const_cast<BugType*>(*I)->FlushReports(BR);
for (BugReporter::EQClasses_iterator
EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) {
ExplodedNode *N = const_cast<ExplodedNode*>(EI->begin()->getErrorNode());
if (N) Src.push_back(N);
}
ViewGraph(&Src[0], &Src[0]+Src.size());
}
else {
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
llvm::ViewGraph(*G.roots_begin(), "ExprEngine");
GraphPrintCheckerState = NULL;
GraphPrintSourceManager = NULL;
}
#endif
}
void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) {
#ifndef NDEBUG
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first);
if (!TrimmedG.get())
llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
else
llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine");
GraphPrintCheckerState = NULL;
GraphPrintSourceManager = NULL;
#endif
}