summaryrefslogtreecommitdiff
path: root/lib/Analysis
diff options
context:
space:
mode:
authorEd Schouten <ed@FreeBSD.org>2009-06-27 10:45:02 +0000
committerEd Schouten <ed@FreeBSD.org>2009-06-27 10:45:02 +0000
commit4ebdf5c4f587daef4e0be499802eac3a7a49bf2f (patch)
tree2c5a83521a20c02e7805581a174008aa9bc23579 /lib/Analysis
parentf698f7e71940663e26a4806a96fb0bdfa160c886 (diff)
Notes
Diffstat (limited to 'lib/Analysis')
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp12
-rw-r--r--lib/Analysis/BasicStore.cpp14
-rw-r--r--lib/Analysis/BugReporter.cpp2
-rw-r--r--lib/Analysis/CFRefCount.cpp33
-rw-r--r--lib/Analysis/CMakeLists.txt3
-rw-r--r--lib/Analysis/CheckObjCUnusedIVars.cpp5
-rw-r--r--lib/Analysis/GRExprEngine.cpp101
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp3
-rw-r--r--lib/Analysis/GRSimpleVals.cpp415
-rw-r--r--lib/Analysis/GRSimpleVals.h86
-rw-r--r--lib/Analysis/GRState.cpp79
-rw-r--r--lib/Analysis/GRTransferFuncs.cpp27
-rw-r--r--lib/Analysis/PathDiagnostic.cpp2
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp8
-rw-r--r--lib/Analysis/RegionStore.cpp219
-rw-r--r--lib/Analysis/SVals.cpp29
-rw-r--r--lib/Analysis/SimpleSValuator.cpp346
-rw-r--r--lib/Analysis/SymbolManager.cpp6
18 files changed, 608 insertions, 782 deletions
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index ffa8a8625bdf4..cb89d30651079 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -83,7 +83,7 @@ public:
const GRState* RemoveDeadBindings(const GRState* state, SymbolReaper& SymReaper);
- void print(const GRState* state, std::ostream& Out,
+ void print(const GRState* state, llvm::raw_ostream& Out,
const char* nl, const char *sep);
};
@@ -280,7 +280,7 @@ BasicConstraintManager::RemoveDeadBindings(const GRState* state,
return state->set<ConstNotEq>(CNE);
}
-void BasicConstraintManager::print(const GRState* state, std::ostream& Out,
+void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
const char* nl, const char *sep) {
// Print equality constraints.
@@ -288,12 +288,8 @@ void BasicConstraintManager::print(const GRState* state, std::ostream& Out,
if (!CE.isEmpty()) {
Out << nl << sep << "'==' constraints:";
-
- for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
- Out << nl << " $" << I.getKey();
- llvm::raw_os_ostream OS(Out);
- OS << " : " << *I.getData();
- }
+ for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I)
+ Out << nl << " $" << I.getKey() << " : " << *I.getData();
}
// Print != constraints.
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 6b346cd52557e..8fbce528fa9a6 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -112,7 +112,8 @@ public:
return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
}
- void print(Store store, std::ostream& Out, const char* nl, const char *sep);
+ void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ const char *sep);
private:
ASTContext& getContext() { return StateMgr.getContext(); }
@@ -535,7 +536,7 @@ Store BasicStoreManager::getInitialStore() {
// Initialize globals and parameters to symbolic values.
// Initialize local variables to undefined.
- const MemRegion *R = StateMgr.getRegion(VD);
+ const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD);
SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
isa<ImplicitParamDecl>(VD))
? ValMgr.getRegionValueSymbolVal(R)
@@ -602,18 +603,19 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
return store;
}
-void BasicStoreManager::print(Store store, std::ostream& O,
+void BasicStoreManager::print(Store store, llvm::raw_ostream& Out,
const char* nl, const char *sep) {
- llvm::raw_os_ostream Out(O);
BindingsTy B = GetBindings(store);
Out << "Variables:" << nl;
bool isFirst = true;
for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
- if (isFirst) isFirst = false;
- else Out << nl;
+ if (isFirst)
+ isFirst = false;
+ else
+ Out << nl;
Out << ' ' << I.getKey() << " : ";
I.getData().print(Out);
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 9c9029cfff347..38ea458a65994 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines BugReporter, a utility class for generating
-// PathDiagnostics for analyses based on GRSimpleVals.
+// PathDiagnostics.
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 46333a74f27d7..f4a28e0c19fd2 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#include "GRSimpleVals.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
@@ -22,6 +21,7 @@
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
@@ -30,7 +30,6 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/STLExtras.h"
-#include <ostream>
#include <stdarg.h>
using namespace clang;
@@ -1674,10 +1673,10 @@ public:
ID.Add(T);
}
- void print(std::ostream& Out) const;
+ void print(llvm::raw_ostream& Out) const;
};
-void RefVal::print(std::ostream& Out) const {
+void RefVal::print(llvm::raw_ostream& Out) const {
if (!T.isNull())
Out << "Tracked Type:" << T.getAsString() << '\n';
@@ -1827,11 +1826,11 @@ static const GRState * SendAutorelease(const GRState *state,
namespace {
-class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
+class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs {
public:
class BindingsPrinter : public GRState::Printer {
public:
- virtual void Print(std::ostream& Out, const GRState* state,
+ virtual void Print(llvm::raw_ostream& Out, const GRState* state,
const char* nl, const char* sep);
};
@@ -1959,7 +1958,8 @@ public:
} // end anonymous namespace
-static void PrintPool(std::ostream &Out, SymbolRef Sym, const GRState *state) {
+static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym,
+ const GRState *state) {
Out << ' ';
if (Sym)
Out << Sym->getSymbolID();
@@ -1975,10 +1975,9 @@ static void PrintPool(std::ostream &Out, SymbolRef Sym, const GRState *state) {
Out << '}';
}
-void CFRefCount::BindingsPrinter::Print(std::ostream& Out, const GRState* state,
+void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out,
+ const GRState* state,
const char* nl, const char* sep) {
-
-
RefBindings B = state->get<RefBindings>();
@@ -2790,10 +2789,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
if (Summ.getArg(idx) == DoNothingByRef)
continue;
- // Invalidate the value of the variable passed by reference.
-
- // FIXME: Either this logic should also be replicated in GRSimpleVals
- // or should be pulled into a separate "constraint engine."
+ // Invalidate the value of the variable passed by reference.
// FIXME: We can have collisions on the conjured symbol if the
// expression *I also creates conjured symbols. We probably want
@@ -2942,11 +2938,10 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
default:
assert (false && "Unhandled RetEffect."); break;
- case RetEffect::NoRet: {
-
+ case RetEffect::NoRet: {
// Make up a symbol for the return value (not reference counted).
- // FIXME: This is basically copy-and-paste from GRSimpleVals. We
- // should compose behavior, not copy it.
+ // FIXME: Most of this logic is not specific to the retain/release
+ // checker.
// FIXME: We eventually should handle structs and other compound types
// that are returned by value.
@@ -3091,7 +3086,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
if (Expr* Receiver = ME->getReceiver()) {
SVal X = St->getSValAsScalarOrLoc(Receiver);
if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X))
- if (L->getRegion() == Eng.getStateManager().getSelfRegion(St)) {
+ if (L->getRegion() == St->getSelfRegion()) {
// Update the summary to make the default argument effect
// 'StopTracking'.
Summ = Summaries.copySummary(Summ);
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index e064e3c71a832..7d6a619736e0f 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -18,15 +18,14 @@ add_clang_library(clangAnalysis
GRCoreEngine.cpp
GRExprEngine.cpp
GRExprEngineInternalChecks.cpp
- GRSimpleVals.cpp
GRState.cpp
- GRTransferFuncs.cpp
LiveVariables.cpp
MemRegion.cpp
PathDiagnostic.cpp
RangeConstraintManager.cpp
RegionStore.cpp
SimpleConstraintManager.cpp
+ SimpleSValuator.cpp
Store.cpp
SVals.cpp
SymbolManager.cpp
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp
index 92c50e2a9185c..21dc658dfa1a5 100644
--- a/lib/Analysis/CheckObjCUnusedIVars.cpp
+++ b/lib/Analysis/CheckObjCUnusedIVars.cpp
@@ -20,7 +20,6 @@
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
-#include <sstream>
using namespace clang;
@@ -97,8 +96,8 @@ void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) {
// Find ivars that are unused.
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
if (I->second == Unused) {
-
- std::ostringstream os;
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
os << "Instance variable '" << I->first->getNameAsString()
<< "' in class '" << ID->getNameAsString()
<< "' is never used by the methods in its @implementation "
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 7d56d108debe2..8b4f5c8f11c10 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -15,7 +15,6 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
@@ -29,7 +28,6 @@
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
-#include <sstream>
#endif
using namespace clang;
@@ -126,6 +124,7 @@ GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx,
StateMgr(G.getContext(), SMC, CMC, G.getAllocator(), cfg, CD, L),
SymMgr(StateMgr.getSymbolManager()),
ValMgr(StateMgr.getValueManager()),
+ SVator(clang::CreateSimpleSValuator(ValMgr)), // FIXME: Generalize later.
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", G.getContext())),
@@ -176,7 +175,7 @@ const GRState* GRExprEngine::getInitialState() {
const ParmVarDecl *PD = FD->getParamDecl(0);
QualType T = PD->getType();
if (T->isIntegerType())
- if (const MemRegion *R = StateMgr.getRegion(PD)) {
+ if (const MemRegion *R = state->getRegion(PD)) {
SVal V = state->getSVal(loc::MemRegionVal(R));
SVal Constraint = EvalBinOp(state, BinaryOperator::GT, V,
ValMgr.makeZeroVal(T),
@@ -1046,7 +1045,7 @@ void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
else {
// We are binding to a value other than 'unknown'. Perform the binding
// using the StoreManager.
- newState = StateMgr.BindLoc(state, cast<Loc>(location), Val);
+ newState = state->bindLoc(cast<Loc>(location), Val);
}
// The next thing to do is check if the GRTransferFuncs object wants to
@@ -1296,9 +1295,8 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet<GRState>& Dst,
SVal oldValueVal = stateLoad->getSVal(oldValueExpr);
// Perform the comparison.
- SVal Cmp = Engine.EvalBinOp(stateLoad,
- BinaryOperator::EQ, theValueVal, oldValueVal,
- Engine.getContext().IntTy);
+ SVal Cmp = Engine.EvalBinOp(stateLoad, BinaryOperator::EQ, theValueVal,
+ oldValueVal, Engine.getContext().IntTy);
const GRState *stateEqual = stateLoad->assume(Cmp, true);
@@ -2247,17 +2245,17 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
InitVal = ValMgr.getConjuredSymbolVal(InitEx, Count);
}
- state = StateMgr.BindDecl(state, VD, InitVal);
+ state = state->bindDecl(VD, InitVal);
// The next thing to do is check if the GRTransferFuncs object wants to
// update the state based on the new binding. If the GRTransferFunc
// object doesn't do anything, just auto-propagate the current state.
GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true);
- getTF().EvalBind(BuilderRef, loc::MemRegionVal(StateMgr.getRegion(VD)),
+ getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD)),
InitVal);
}
else {
- state = StateMgr.BindDeclWithNoInit(state, VD);
+ state = state->bindDeclWithNoInit(VD);
MakeNode(Dst, DS, *I, state);
}
}
@@ -2562,7 +2560,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
case UnaryOperator::Minus:
// FIXME: Do we need to handle promotions?
- state = state->bindExpr(U, EvalMinus(U, cast<NonLoc>(V)));
+ state = state->bindExpr(U, EvalMinus(cast<NonLoc>(V)));
break;
case UnaryOperator::LNot:
@@ -2571,25 +2569,21 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
//
// Note: technically we do "E == 0", but this is the same in the
// transfer functions as "0 == E".
+ SVal Result;
if (isa<Loc>(V)) {
Loc X = ValMgr.makeNull();
- SVal Result = EvalBinOp(state,BinaryOperator::EQ, cast<Loc>(V), X,
- U->getType());
- state = state->bindExpr(U, Result);
+ Result = EvalBinOp(state, BinaryOperator::EQ, cast<Loc>(V), X,
+ U->getType());
}
else {
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
-#if 0
- SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X);
- state = SetSVal(state, U, Result);
-#else
- EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I,
- U->getType());
- continue;
-#endif
+ Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X,
+ U->getType());
}
+ state = state->bindExpr(U, Result);
+
break;
}
@@ -2640,8 +2634,8 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
Builder->getCurrentBlockCount());
// If the value is a location, ++/-- should always preserve
- // non-nullness. Check if the original value was non-null, and if so propagate
- // that constraint.
+ // non-nullness. Check if the original value was non-null, and if so
+ // propagate that constraint.
if (Loc::IsLocType(U->getType())) {
SVal Constraint = EvalBinOp(state, BinaryOperator::EQ, V2,
ValMgr.makeZeroVal(U->getType()),
@@ -2907,9 +2901,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
if (B->isAssignmentOp())
break;
- // Process non-assignements except commas or short-circuited
- // logical expressions (LAnd and LOr).
-
+ // Process non-assignments except commas or short-circuited
+ // logical expressions (LAnd and LOr).
SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
if (Result.isUnknown()) {
@@ -3024,7 +3017,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
}
// Compute the result of the operation.
- SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
+ SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
B->getType());
if (Result.isUndef()) {
@@ -3073,26 +3066,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// Transfer-function Helpers.
//===----------------------------------------------------------------------===//
-void GRExprEngine::EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
- BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R,
- ExplodedNode<GRState>* Pred, QualType T) {
-
- GRStateSet OStates;
- EvalBinOp(OStates, GetState(Pred), Ex, Op, L, R, T);
-
- for (GRStateSet::iterator I=OStates.begin(), E=OStates.end(); I!=E; ++I)
- MakeNode(Dst, Ex, Pred, *I);
-}
-
-void GRExprEngine::EvalBinOp(GRStateSet& OStates, const GRState* state,
- Expr* Ex, BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R, QualType T) {
-
- GRStateSet::AutoPopulate AP(OStates, state);
- if (R.isValid()) getTF().EvalBinOpNN(OStates, *this, state, Ex, Op, L, R, T);
-}
-
SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
SVal L, SVal R, QualType T) {
@@ -3104,9 +3077,9 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
if (isa<Loc>(L)) {
if (isa<Loc>(R))
- return getTF().EvalBinOp(*this, Op, cast<Loc>(L), cast<Loc>(R));
+ return SVator->EvalBinOpLL(Op, cast<Loc>(L), cast<Loc>(R), T);
else
- return getTF().EvalBinOp(*this, state, Op, cast<Loc>(L), cast<NonLoc>(R));
+ return SVator->EvalBinOpLN(state, Op, cast<Loc>(L), cast<NonLoc>(R), T);
}
if (isa<Loc>(R)) {
@@ -3116,11 +3089,10 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
// Commute the operands.
- return getTF().EvalBinOp(*this, state, Op, cast<Loc>(R), cast<NonLoc>(L));
+ return SVator->EvalBinOpLN(state, Op, cast<Loc>(R), cast<NonLoc>(L), T);
}
else
- return getTF().DetermEvalBinOpNN(*this, Op, cast<NonLoc>(L),
- cast<NonLoc>(R), T);
+ return SVator->EvalBinOpNN(Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
}
//===----------------------------------------------------------------------===//
@@ -3156,8 +3128,11 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
return "";
}
- static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) {
- std::ostringstream Out;
+ static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*,
+ bool ShortNames) {
+
+ std::string sbuf;
+ llvm::raw_string_ostream Out(sbuf);
// Program Location.
ProgramPoint Loc = N->getLocation();
@@ -3179,9 +3154,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
SourceLocation SLoc = S->getLocStart();
Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
- llvm::raw_os_ostream OutS(Out);
- S->printPretty(OutS);
- OutS.flush();
+ S->printPretty(Out);
if (SLoc.isFileID()) {
Out << "\\lline="
@@ -3235,10 +3208,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
SourceLocation SLoc = T->getLocStart();
Out << "\\|Terminator: ";
-
- llvm::raw_os_ostream OutS(Out);
- E.getSrc()->printTerminator(OutS);
- OutS.flush();
+ E.getSrc()->printTerminator(Out);
if (SLoc.isFileID()) {
Out << "\\lline="
@@ -3253,14 +3223,11 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
if (Label) {
if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
- llvm::raw_os_ostream OutS(Out);
- C->getLHS()->printPretty(OutS);
- OutS.flush();
+ C->getLHS()->printPretty(Out);
if (Stmt* RHS = C->getRHS()) {
Out << " .. ";
- RHS->printPretty(OutS);
- OutS.flush();
+ RHS->printPretty(Out);
}
Out << ":";
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index 13df89ebbfdc4..76d26dd9f02af 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -672,7 +672,6 @@ public:
return NULL;
if (!StoreSite) {
- GRStateManager &StateMgr = BRC.getStateManager();
const ExplodedNode<GRState> *Node = N, *Last = NULL;
for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
@@ -686,7 +685,7 @@ public:
}
}
- if (StateMgr.GetSVal(Node->getState(), R) != V)
+ if (Node->getState()->getSVal(R) != V)
break;
}
diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp
deleted file mode 100644
index 480612113d10e..0000000000000
--- a/lib/Analysis/GRSimpleVals.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-// GRSimpleVals.cpp - Transfer functions for tracking simple 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 defines GRSimpleVals, a sub-class of GRTransferFuncs that
-// provides transfer functions for performing simple value tracking with
-// limited support for symbolics.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRSimpleVals.h"
-#include "BasicObjCFoundationChecks.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "llvm/Support/Compiler.h"
-#include <sstream>
-
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// Transfer Function creation for External clients.
-//===----------------------------------------------------------------------===//
-
-GRTransferFuncs* clang::MakeGRSimpleValsTF() { return new GRSimpleVals(); }
-
-//===----------------------------------------------------------------------===//
-// Transfer function for Casts.
-//===----------------------------------------------------------------------===//
-
-SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLoc X, QualType T) {
-
- if (!isa<nonloc::ConcreteInt>(X))
- return UnknownVal();
-
- bool isLocType = Loc::IsLocType(T);
-
- // Only handle casts from integers to integers.
- if (!isLocType && !T->isIntegerType())
- return UnknownVal();
-
- BasicValueFactory& BasicVals = Eng.getBasicVals();
-
- llvm::APSInt V = cast<nonloc::ConcreteInt>(X).getValue();
- V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
- V.extOrTrunc(Eng.getContext().getTypeSize(T));
-
- if (isLocType)
- return loc::ConcreteInt(BasicVals.getValue(V));
- else
- return nonloc::ConcreteInt(BasicVals.getValue(V));
-}
-
-// Casts.
-
-SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, Loc X, QualType T) {
-
- // Casts from pointers -> pointers, just return the lval.
- //
- // Casts from pointers -> references, just return the lval. These
- // can be introduced by the frontend for corner cases, e.g
- // casting from va_list* to __builtin_va_list&.
- //
- assert (!X.isUnknownOrUndef());
-
- if (Loc::IsLocType(T) || T->isReferenceType())
- return X;
-
- // FIXME: Handle transparent unions where a value can be "transparently"
- // lifted into a union type.
- if (T->isUnionType())
- return UnknownVal();
-
- assert (T->isIntegerType());
- BasicValueFactory& BasicVals = Eng.getBasicVals();
- unsigned BitWidth = Eng.getContext().getTypeSize(T);
-
- if (!isa<loc::ConcreteInt>(X))
- return Eng.getValueManager().makeLocAsInteger(X, BitWidth);
-
- llvm::APSInt V = cast<loc::ConcreteInt>(X).getValue();
- V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
- V.extOrTrunc(BitWidth);
- return nonloc::ConcreteInt(BasicVals.getValue(V));
-}
-
-// Unary operators.
-
-SVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLoc X){
-
- switch (X.getSubKind()) {
-
- case nonloc::ConcreteIntKind:
- return cast<nonloc::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U);
-
- default:
- return UnknownVal();
- }
-}
-
-SVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLoc X) {
-
- switch (X.getSubKind()) {
-
- case nonloc::ConcreteIntKind:
- return cast<nonloc::ConcreteInt>(X).EvalComplement(Eng.getBasicVals());
-
- default:
- return UnknownVal();
- }
-}
-
-// Binary operators.
-
-static unsigned char LNotOpMap[] = {
- (unsigned char) BinaryOperator::GE, /* LT => GE */
- (unsigned char) BinaryOperator::LE, /* GT => LE */
- (unsigned char) BinaryOperator::GT, /* LE => GT */
- (unsigned char) BinaryOperator::LT, /* GE => LT */
- (unsigned char) BinaryOperator::NE, /* EQ => NE */
- (unsigned char) BinaryOperator::EQ /* NE => EQ */
-};
-
-SVal GRSimpleVals::DetermEvalBinOpNN(GRExprEngine& Eng,
- BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R,
- QualType T) {
- BasicValueFactory& BasicVals = Eng.getBasicVals();
- ValueManager& ValMgr = Eng.getValueManager();
- unsigned subkind = L.getSubKind();
-
- while (1) {
-
- switch (subkind) {
- default:
- return UnknownVal();
-
- case nonloc::LocAsIntegerKind: {
- Loc LL = cast<nonloc::LocAsInteger>(L).getLoc();
-
- switch (R.getSubKind()) {
- case nonloc::LocAsIntegerKind:
- return EvalBinOp(Eng, Op, LL,
- cast<nonloc::LocAsInteger>(R).getLoc());
-
- case nonloc::ConcreteIntKind: {
- // Transform the integer into a location and compare.
- ASTContext& Ctx = Eng.getContext();
- llvm::APSInt V = cast<nonloc::ConcreteInt>(R).getValue();
- V.setIsUnsigned(true);
- V.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
- return EvalBinOp(Eng, Op, LL, ValMgr.makeLoc(V));
- }
-
- default:
- switch (Op) {
- case BinaryOperator::EQ:
- return ValMgr.makeTruthVal(false);
- case BinaryOperator::NE:
- return ValMgr.makeTruthVal(true);
- default:
- // This case also handles pointer arithmetic.
- return UnknownVal();
- }
- }
- }
-
- case nonloc::SymExprValKind: {
- // Logical not?
- if (!(Op == BinaryOperator::EQ && R.isZeroConstant()))
- return UnknownVal();
-
- const SymExpr &SE=*cast<nonloc::SymExprVal>(L).getSymbolicExpression();
-
- // Only handle ($sym op constant) for now.
- if (const SymIntExpr *E = dyn_cast<SymIntExpr>(&SE)) {
- BinaryOperator::Opcode Opc = E->getOpcode();
-
- if (Opc < BinaryOperator::LT || Opc > BinaryOperator::NE)
- return UnknownVal();
-
- // For comparison operators, translate the constraint by
- // changing the opcode.
- int idx = (unsigned) Opc - (unsigned) BinaryOperator::LT;
-
- assert (idx >= 0 &&
- (unsigned) idx < sizeof(LNotOpMap)/sizeof(unsigned char));
-
- Opc = (BinaryOperator::Opcode) LNotOpMap[idx];
- assert(E->getType(Eng.getContext()) == T);
- E = Eng.getSymbolManager().getSymIntExpr(E->getLHS(), Opc,
- E->getRHS(), T);
- return nonloc::SymExprVal(E);
- }
-
- return UnknownVal();
- }
-
- case nonloc::ConcreteIntKind:
-
- if (isa<nonloc::ConcreteInt>(R)) {
- const nonloc::ConcreteInt& L_CI = cast<nonloc::ConcreteInt>(L);
- const nonloc::ConcreteInt& R_CI = cast<nonloc::ConcreteInt>(R);
- return L_CI.EvalBinOp(BasicVals, Op, R_CI);
- }
- else {
- subkind = R.getSubKind();
- NonLoc tmp = R;
- R = L;
- L = tmp;
-
- // Swap the operators.
- switch (Op) {
- case BinaryOperator::LT: Op = BinaryOperator::GT; break;
- case BinaryOperator::GT: Op = BinaryOperator::LT; break;
- case BinaryOperator::LE: Op = BinaryOperator::GE; break;
- case BinaryOperator::GE: Op = BinaryOperator::LE; break;
- default: break;
- }
-
- continue;
- }
-
- case nonloc::SymbolValKind:
- if (isa<nonloc::ConcreteInt>(R)) {
- ValueManager &ValMgr = Eng.getValueManager();
- return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(L).getSymbol(), Op,
- cast<nonloc::ConcreteInt>(R).getValue(), T);
- }
- else
- return UnknownVal();
- }
- }
-}
-
-
-// Binary Operators (except assignments and comma).
-
-SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
- Loc L, Loc R) {
-
- switch (Op) {
- default:
- return UnknownVal();
- case BinaryOperator::EQ:
- case BinaryOperator::NE:
- return EvalEquality(Eng, L, R, Op == BinaryOperator::EQ);
- }
-}
-
-SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, const GRState *state,
- BinaryOperator::Opcode Op, Loc L, NonLoc R) {
-
- // Special case: 'R' is an integer that has the same width as a pointer and
- // we are using the integer location in a comparison. Normally this cannot be
- // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
- // can generate comparisons that trigger this code.
- // FIXME: Are all locations guaranteed to have pointer width?
- if (BinaryOperator::isEqualityOp(Op)) {
- if (nonloc::ConcreteInt *RInt = dyn_cast<nonloc::ConcreteInt>(&R)) {
- const llvm::APSInt *X = &RInt->getValue();
- ASTContext &C = Eng.getContext();
- if (C.getTypeSize(C.VoidPtrTy) == X->getBitWidth()) {
- // Convert the signedness of the integer (if necessary).
- if (X->isSigned())
- X = &Eng.getBasicVals().getValue(*X, true);
-
- return EvalBinOp(Eng, Op, L, loc::ConcreteInt(*X));
- }
- }
- }
-
- // Delegate pointer arithmetic to store manager.
- return Eng.getStoreManager().EvalBinOp(state, Op, L, R);
-}
-
-// Equality operators for Locs.
-// FIXME: All this logic will be revamped when we have MemRegion::getLocation()
-// implemented.
-
-SVal GRSimpleVals::EvalEquality(GRExprEngine& Eng, Loc L, Loc R, bool isEqual) {
-
- ValueManager& ValMgr = Eng.getValueManager();
-
- switch (L.getSubKind()) {
-
- default:
- assert(false && "EQ/NE not implemented for this Loc.");
- return UnknownVal();
-
- case loc::ConcreteIntKind:
-
- if (isa<loc::ConcreteInt>(R)) {
- bool b = cast<loc::ConcreteInt>(L).getValue() ==
- cast<loc::ConcreteInt>(R).getValue();
-
- // Are we computing '!='? Flip the result.
- if (!isEqual)
- b = !b;
-
- return ValMgr.makeTruthVal(b);
- }
- else if (SymbolRef Sym = R.getAsSymbol()) {
- const SymIntExpr * SE =
- Eng.getSymbolManager().getSymIntExpr(Sym,
- isEqual ? BinaryOperator::EQ
- : BinaryOperator::NE,
- cast<loc::ConcreteInt>(L).getValue(),
- Eng.getContext().IntTy);
- return nonloc::SymExprVal(SE);
- }
-
- break;
-
- case loc::MemRegionKind: {
- if (SymbolRef LSym = L.getAsLocSymbol()) {
- if (isa<loc::ConcreteInt>(R)) {
- const SymIntExpr *SE =
- Eng.getSymbolManager().getSymIntExpr(LSym,
- isEqual ? BinaryOperator::EQ
- : BinaryOperator::NE,
- cast<loc::ConcreteInt>(R).getValue(),
- Eng.getContext().IntTy);
-
- return nonloc::SymExprVal(SE);
- }
- }
- }
-
- // Fall-through.
-
- case loc::GotoLabelKind:
- return ValMgr.makeTruthVal(isEqual ? L == R : L != R);
- }
-
- return ValMgr.makeTruthVal(isEqual ? false : true);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function for function calls.
-//===----------------------------------------------------------------------===//
-
-void GRSimpleVals::EvalCall(ExplodedNodeSet<GRState>& Dst,
- GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred) {
-
- GRStateManager& StateMgr = Eng.getStateManager();
- const GRState* St = Builder.GetState(Pred);
-
- // Invalidate all arguments passed in by reference (Locs).
-
- for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I) {
-
- SVal V = St->getSVal(*I);
-
- if (isa<loc::MemRegionVal>(V)) {
- const MemRegion *R = cast<loc::MemRegionVal>(V).getRegion();
- if (R->isBoundable())
- St = StateMgr.BindLoc(St, cast<Loc>(V), UnknownVal());
- } else if (isa<nonloc::LocAsInteger>(V))
- St = StateMgr.BindLoc(St, cast<nonloc::LocAsInteger>(V).getLoc(),
- UnknownVal());
-
- }
-
- // Make up a symbol for the return value of this function.
- // FIXME: We eventually should handle structs and other compound types
- // that are returned by value.
- QualType T = CE->getType();
- if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
- unsigned Count = Builder.getCurrentBlockCount();
- SVal X = Eng.getValueManager().getConjuredSymbolVal(CE, Count);
- St = St->bindExpr(CE, X, Eng.getCFG().isBlkExpr(CE), false);
- }
-
- Builder.MakeNode(Dst, CE, Pred, St);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function for Objective-C message expressions.
-//===----------------------------------------------------------------------===//
-
-void GRSimpleVals::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
- GRExprEngine& Eng,
- GRStmtNodeBuilder<GRState>& Builder,
- ObjCMessageExpr* ME,
- ExplodedNode<GRState>* Pred) {
-
-
- // The basic transfer function logic for message expressions does nothing.
- // We just invalidate all arguments passed in by references.
- const GRState *St = Builder.GetState(Pred);
-
- for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
- I != E; ++I) {
-
- SVal V = St->getSVal(*I);
-
- if (isa<Loc>(V))
- St = St->bindLoc(cast<Loc>(V), UnknownVal());
- }
-
- Builder.MakeNode(Dst, ME, Pred, St);
-}
diff --git a/lib/Analysis/GRSimpleVals.h b/lib/Analysis/GRSimpleVals.h
deleted file mode 100644
index 6ef49dcdd22ee..0000000000000
--- a/lib/Analysis/GRSimpleVals.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// GRSimpleVals.h - Transfer functions for tracking simple 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 defines GRSimpleVals, a sub-class of GRTransferFuncs that
-// provides transfer functions for performing simple value tracking with
-// limited support for symbolics.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_GRSIMPLEVALS
-#define LLVM_CLANG_ANALYSIS_GRSIMPLEVALS
-
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-
-namespace clang {
-
-class PathDiagnostic;
-class ASTContext;
-
-class GRSimpleVals : public GRTransferFuncs {
-protected:
-
- virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng,
- BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R, QualType T);
-
-public:
- GRSimpleVals() {}
- virtual ~GRSimpleVals() {}
-
- // Casts.
-
- virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT);
- virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT);
-
- // Unary Operators.
-
- virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X);
-
- virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X);
-
- // Binary Operators.
-
- virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
- Loc L, Loc R);
-
- // Pointer arithmetic.
-
- virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state,
- BinaryOperator::Opcode Op, Loc L, NonLoc R);
-
- // Calls.
-
- virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
- GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode<GRState>* Pred);
-
- virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
- GRExprEngine& Engine,
- GRStmtNodeBuilder<GRState>& Builder,
- ObjCMessageExpr* ME,
- ExplodedNode<GRState>* Pred);
-
-
-
- static void GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
- ExplodedNode<GRState>* N);
-
-protected:
-
- // Equality (==, !=) operators for Locs.
- SVal EvalEquality(GRExprEngine& Engine, Loc L, Loc R, bool isEqual);
-};
-
-} // end clang namespace
-
-#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index a64b2d7f5f493..493edc37bacbb 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -1,4 +1,4 @@
-//= GRState*cpp - Path-Sens. "State" for tracking valuues -----*- C++ -*--=//
+//= GRState.cpp - Path-Sensitive "State" for tracking values -----*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines SymbolRef, ExprBindKey, and GRState*
+// This file implements GRState and GRStateManager.
//
//===----------------------------------------------------------------------===//
@@ -20,6 +20,7 @@
using namespace clang;
// Give the vtable for ConstraintManager somewhere to live.
+// FIXME: Move this elsewhere.
ConstraintManager::~ConstraintManager() {}
GRStateManager::~GRStateManager() {
@@ -56,16 +57,63 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
SymReaper);
}
-const GRState* GRStateManager::Unbind(const GRState* St, Loc LV) {
- Store OldStore = St->getStore();
- Store NewStore = StoreMgr->Remove(OldStore, LV);
+const GRState *GRState::unbindLoc(Loc LV) const {
+ Store OldStore = getStore();
+ Store NewStore = Mgr->StoreMgr->Remove(OldStore, LV);
if (NewStore == OldStore)
- return St;
+ return this;
- GRState NewSt = *St;
+ GRState NewSt = *this;
NewSt.St = NewStore;
- return getPersistentState(NewSt);
+ return Mgr->getPersistentState(NewSt);
+}
+
+SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
+ // We only want to do fetches from regions that we can actually bind
+ // values. For example, SymbolicRegions of type 'id<...>' cannot
+ // have direct bindings (but their can be bindings on their subregions).
+ if (!R->isBoundable())
+ return UnknownVal();
+
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ QualType T = TR->getValueType(Mgr->getContext());
+ if (Loc::IsLocType(T) || T->isIntegerType())
+ return getSVal(R);
+ }
+
+ return UnknownVal();
+}
+
+
+const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr,
+ bool Invalidate) const {
+
+ Environment NewEnv = Mgr->EnvMgr.BindExpr(Env, Ex, V, isBlkExpr, Invalidate);
+
+ if (NewEnv == Env)
+ return this;
+
+ GRState NewSt = *this;
+ NewSt.Env = NewEnv;
+ return Mgr->getPersistentState(NewSt);
+}
+
+const GRState *GRState::bindExpr(const Stmt* Ex, SVal V,
+ bool Invalidate) const {
+
+ bool isBlkExpr = false;
+
+ if (Ex == Mgr->CurrentStmt) {
+ // FIXME: Should this just be an assertion? When would we want to set
+ // the value of a block-level expression if it wasn't CurrentStmt?
+ isBlkExpr = Mgr->cfg.isBlkExpr(Ex);
+
+ if (!isBlkExpr)
+ return this;
+ }
+
+ return bindExpr(Ex, V, isBlkExpr, Invalidate);
}
const GRState* GRStateManager::getInitialState() {
@@ -101,7 +149,8 @@ const GRState* GRState::makeWithStore(Store store) const {
// State pretty-printing.
//===----------------------------------------------------------------------===//
-void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
+void GRState::print(llvm::raw_ostream& Out, const char* nl,
+ const char* sep) const {
// Print the store.
Mgr->getStoreManager().print(getStore(), Out, nl, sep);
@@ -117,9 +166,7 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
else { Out << nl; }
Out << " (" << (void*) I.getKey() << ") ";
- llvm::raw_os_ostream OutS(Out);
- I.getKey()->printPretty(OutS);
- OutS.flush();
+ I.getKey()->printPretty(Out);
Out << " : ";
I.getData().print(Out);
}
@@ -136,9 +183,7 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
else { Out << nl; }
Out << " (" << (void*) I.getKey() << ") ";
- llvm::raw_os_ostream OutS(Out);
- I.getKey()->printPretty(OutS);
- OutS.flush();
+ I.getKey()->printPretty(Out);
Out << " : ";
I.getData().print(Out);
}
@@ -152,12 +197,12 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
}
}
-void GRState::printDOT(std::ostream& Out) const {
+void GRState::printDOT(llvm::raw_ostream& Out) const {
print(Out, "\\l", "\\|");
}
void GRState::printStdErr() const {
- print(*llvm::cerr);
+ print(llvm::errs());
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/GRTransferFuncs.cpp b/lib/Analysis/GRTransferFuncs.cpp
deleted file mode 100644
index 3c14ee9ab5c2d..0000000000000
--- a/lib/Analysis/GRTransferFuncs.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-//== GRTransferFuncs.cpp - Path-Sens. Transfer Functions Interface -*- C++ -*--=
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines GRTransferFuncs, which provides a base-class that
-// defines an interface for transfer functions used by GRExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-void GRTransferFuncs::EvalBinOpNN(GRStateSet& OStates,
- GRExprEngine& Eng,
- const GRState *St, Expr* Ex,
- BinaryOperator::Opcode Op,
- NonLoc L, NonLoc R, QualType T) {
-
- OStates.Add(St->bindExpr(Ex, DetermEvalBinOpNN(Eng, Op, L, R, T)));
-}
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
index ec96329852d48..a608ce0d5884c 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -18,7 +18,7 @@
#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Casting.h"
-#include <sstream>
+
using namespace clang;
using llvm::dyn_cast;
using llvm::isa;
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index 73c68bcaea033..079462e8d19f4 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -200,7 +200,7 @@ public:
return newRanges;
}
- void Print(std::ostream &os) const {
+ void print(llvm::raw_ostream &os) const {
bool isFirst = true;
os << "{ ";
for (iterator i = begin(), e = end(); i != e; ++i) {
@@ -265,7 +265,7 @@ public:
const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper);
- void print(const GRState* St, std::ostream& Out,
+ void print(const GRState* St, llvm::raw_ostream& Out,
const char* nl, const char *sep);
private:
@@ -341,7 +341,7 @@ AssumeX(GE)
// Pretty-printing.
//===------------------------------------------------------------------------===/
-void RangeConstraintManager::print(const GRState* St, std::ostream& Out,
+void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out,
const char* nl, const char *sep) {
ConstraintRangeTy Ranges = St->get<ConstraintRange>();
@@ -353,6 +353,6 @@ void RangeConstraintManager::print(const GRState* St, std::ostream& Out,
for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){
Out << nl << ' ' << I.getKey() << " : ";
- I.getData().Print(Out);
+ I.getData().print(Out);
}
}
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 77f5b7cb39bbd..d45048de1a42f 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -103,25 +103,6 @@ namespace clang {
}
//===----------------------------------------------------------------------===//
-// Region "killsets".
-//===----------------------------------------------------------------------===//
-//
-// RegionStore lazily adds value bindings to regions when the analyzer handles
-// assignment statements. Killsets track which default values have been
-// killed, thus distinguishing between "unknown" values and default
-// values. Regions are added to killset only when they are assigned "unknown"
-// directly, otherwise we should have their value in the region bindings.
-//
-namespace { class VISIBILITY_HIDDEN RegionKills {}; }
-static int RegionKillsIndex = 0;
-namespace clang {
- template<> struct GRStateTrait<RegionKills>
- : public GRStatePartialTrait< llvm::ImmutableSet<const MemRegion*> > {
- static void* GDMIndex() { return &RegionKillsIndex; }
- };
-}
-
-//===----------------------------------------------------------------------===//
// Regions with default values.
//===----------------------------------------------------------------------===//
//
@@ -238,10 +219,8 @@ public:
CastResult CastRegion(const GRState *state, const MemRegion* R,
QualType CastToTy);
- SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,NonLoc R);
-
-
-
+ SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,
+ NonLoc R, QualType resultTy);
Store getInitialStore() { return RBFactory.GetEmptyMap().getRoot(); }
@@ -260,8 +239,6 @@ public:
return SelfRegion;
}
-
-
//===-------------------------------------------------------------------===//
// Binding values to regions.
@@ -306,7 +283,11 @@ public:
/// else
/// return symbolic
SVal Retrieve(const GRState *state, Loc L, QualType T = QualType());
-
+
+ SVal RetrieveElement(const GRState* state, const ElementRegion* R);
+
+ SVal RetrieveField(const GRState* state, const FieldRegion* R);
+
/// Retrieve the values in a struct and return a CompoundVal, used when doing
/// struct copy:
/// struct s x, y;
@@ -352,7 +333,8 @@ public:
return RegionBindingsTy(static_cast<const RegionBindingsTy::TreeTy*>(store));
}
- void print(Store store, std::ostream& Out, const char* nl, const char *sep);
+ void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ const char *sep);
void iterBindings(Store store, BindingsHandler& f) {
// FIXME: Implement.
@@ -740,7 +722,8 @@ RegionStoreManager::CastRegion(const GRState *state, const MemRegion* R,
//===----------------------------------------------------------------------===//
SVal RegionStoreManager::EvalBinOp(const GRState *state,
- BinaryOperator::Opcode Op, Loc L, NonLoc R) {
+ BinaryOperator::Opcode Op, Loc L, NonLoc R,
+ QualType resultTy) {
// Assume the base location is MemRegionVal.
if (!isa<loc::MemRegionVal>(L))
return UnknownVal();
@@ -798,7 +781,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
//
nonloc::ConcreteInt OffConverted(getBasicVals().Convert(Base->getValue(),
Offset->getValue()));
- SVal NewIdx = Base->EvalBinOp(getBasicVals(), Op, OffConverted);
+ SVal NewIdx = Base->evalBinOp(ValMgr, Op, OffConverted);
const MemRegion* NewER =
MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion(),
getContext());
@@ -839,6 +822,12 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
const TypedRegion *R = cast<TypedRegion>(MR);
assert(R && "bad region");
+ if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
+ return RetrieveField(state, FR);
+
+ if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
+ return RetrieveElement(state, ER);
+
// FIXME: We should eventually handle funny addressing. e.g.:
//
// int x = ...;
@@ -867,42 +856,6 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
if (V)
return *V;
- // Check if the region is in killset.
- if (state->contains<RegionKills>(R))
- return UnknownVal();
-
- // Check if the region is an element region of a string literal.
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- if (const StringRegion *StrR=dyn_cast<StringRegion>(ER->getSuperRegion())) {
- const StringLiteral *Str = StrR->getStringLiteral();
- SVal Idx = ER->getIndex();
- if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
- int64_t i = CI->getValue().getSExtValue();
- char c;
- if (i == Str->getByteLength())
- c = '\0';
- else
- c = Str->getStrData()[i];
- const llvm::APSInt &V = getBasicVals().getValue(c, getContext().CharTy);
- return nonloc::ConcreteInt(V);
- }
- }
- }
-
- // If the region is an element or field, it may have a default value.
- if (isa<ElementRegion>(R) || isa<FieldRegion>(R)) {
- const MemRegion* SuperR = cast<SubRegion>(R)->getSuperRegion();
- GRStateTrait<RegionDefaultValue>::lookup_type D =
- state->get<RegionDefaultValue>(SuperR);
- if (D) {
- // If the default value is symbolic, we need to create a new symbol.
- if (D->hasConjuredSymbol())
- return ValMgr.getRegionValueSymbolVal(R);
- else
- return *D;
- }
- }
-
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
const MemRegion *SR = IVR->getSuperRegion();
@@ -961,6 +914,97 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
return UnknownVal();
}
+SVal RegionStoreManager::RetrieveElement(const GRState* state,
+ const ElementRegion* R) {
+ // Check if the region has a binding.
+ RegionBindingsTy B = GetRegionBindings(state->getStore());
+ const SVal* V = B.lookup(R);
+ if (V)
+ return *V;
+
+ // Check if the region is an element region of a string literal.
+ if (const StringRegion *StrR=dyn_cast<StringRegion>(R->getSuperRegion())) {
+ const StringLiteral *Str = StrR->getStringLiteral();
+ SVal Idx = R->getIndex();
+ if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
+ int64_t i = CI->getValue().getSExtValue();
+ char c;
+ if (i == Str->getByteLength())
+ c = '\0';
+ else
+ c = Str->getStrData()[i];
+ return ValMgr.makeIntVal(c, getContext().CharTy);
+ }
+ }
+
+ const MemRegion* SuperR = R->getSuperRegion();
+ const SVal* D = state->get<RegionDefaultValue>(SuperR);
+
+ if (D) {
+ if (D->hasConjuredSymbol())
+ return ValMgr.getRegionValueSymbolVal(R);
+ else
+ return *D;
+ }
+
+ if (R->hasHeapOrStackStorage())
+ return UndefinedVal();
+
+ QualType Ty = R->getValueType(getContext());
+
+ // If the region is already cast to another type, use that type to create the
+ // symbol value.
+ if (const QualType *p = state->get<RegionCasts>(R))
+ Ty = (*p)->getAsPointerType()->getPointeeType();
+
+ if (Loc::IsLocType(Ty) || Ty->isIntegerType())
+ return ValMgr.getRegionValueSymbolVal(R, Ty);
+ else
+ return UnknownVal();
+}
+
+SVal RegionStoreManager::RetrieveField(const GRState* state,
+ const FieldRegion* R) {
+ QualType Ty = R->getValueType(getContext());
+
+ // Check if the region has a binding.
+ RegionBindingsTy B = GetRegionBindings(state->getStore());
+ const SVal* V = B.lookup(R);
+ if (V)
+ return *V;
+
+ const MemRegion* SuperR = R->getSuperRegion();
+ const SVal* D = state->get<RegionDefaultValue>(SuperR);
+ if (D) {
+ if (D->hasConjuredSymbol())
+ return ValMgr.getRegionValueSymbolVal(R);
+
+ if (D->isZeroConstant())
+ return ValMgr.makeZeroVal(Ty);
+
+ if (D->isUnknown())
+ return *D;
+
+ assert(0 && "Unknown default value");
+ }
+
+ if (R->hasHeapOrStackStorage())
+ return UndefinedVal();
+
+ // If the region is already cast to another type, use that type to create the
+ // symbol value.
+ if (const QualType *p = state->get<RegionCasts>(R)) {
+ QualType tmp = *p;
+ Ty = tmp->getAsPointerType()->getPointeeType();
+ }
+
+ // All other integer values are symbolic.
+ if (Loc::IsLocType(Ty) || Ty->isIntegerType())
+ return ValMgr.getRegionValueSymbolVal(R, Ty);
+ else
+ return UnknownVal();
+}
+
SVal RegionStoreManager::RetrieveStruct(const GRState *state,
const TypedRegion* R){
QualType T = R->getValueType(getContext());
@@ -1040,12 +1084,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
RegionBindingsTy B = GetRegionBindings(state->getStore());
- if (V.isUnknown()) {
- B = RBFactory.Remove(B, R); // Remove the binding.
- state = state->add<RegionKills>(R); // Add the region to the killset.
- }
- else
- B = RBFactory.Add(B, R, V);
+ B = RBFactory.Add(B, R, V);
return state->makeWithStore(B.getRoot());
}
@@ -1127,15 +1166,12 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
state = Bind(state, ValMgr.makeLoc(ER), *VI);
}
- // If the init list is shorter than the array length, bind the rest elements
- // to 0.
- if (ElementTy->isIntegerType()) {
- while (i < Size) {
- SVal Idx = ValMgr.makeIntVal(i);
- ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx,R,getContext());
+ // If the init list is shorter than the array length, set the array default
+ // value.
+ if (i < Size) {
+ if (ElementTy->isIntegerType()) {
SVal V = ValMgr.makeZeroVal(ElementTy);
- state = Bind(state, ValMgr.makeLoc(ER), V);
- ++i;
+ state = setDefaultValue(state, R, V);
}
}
@@ -1186,15 +1222,8 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
}
// There may be fewer values in the initialize list than the fields of struct.
- while (FI != FE) {
- QualType FTy = (*FI)->getType();
- if (FTy->isIntegerType()) {
- FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
- state = Bind(state, ValMgr.makeLoc(FR), ValMgr.makeZeroVal(FTy));
- }
-
- ++FI;
- }
+ if (FI != FE)
+ state = setDefaultValue(state, R, ValMgr.makeIntVal(0, false));
return state;
}
@@ -1202,20 +1231,17 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
const GRState *RegionStoreManager::KillStruct(const GRState *state,
const TypedRegion* R){
- // (1) Kill the struct region because it is assigned "unknown".
- // (2) Set the default value of the struct region to "unknown".
- state = state->add<RegionKills>(R)->set<RegionDefaultValue>(R, UnknownVal());
- Store store = state->getStore();
- RegionBindingsTy B = GetRegionBindings(store);
+ // Set the default value of the struct region to "unknown".
+ state = state->set<RegionDefaultValue>(R, UnknownVal());
// Remove all bindings for the subregions of the struct.
+ Store store = state->getStore();
+ RegionBindingsTy B = GetRegionBindings(store);
for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion* R = I.getKey();
if (const SubRegion* subRegion = dyn_cast<SubRegion>(R))
if (subRegion->isSubRegionOf(R))
store = Remove(store, ValMgr.makeLoc(subRegion));
- // FIXME: Maybe we should also remove the bindings for the "views" of the
- // subregions.
}
return state->makeWithStore(store);
@@ -1427,9 +1453,8 @@ Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
// Utility methods.
//===----------------------------------------------------------------------===//
-void RegionStoreManager::print(Store store, std::ostream& Out,
+void RegionStoreManager::print(Store store, llvm::raw_ostream& OS,
const char* nl, const char *sep) {
- llvm::raw_os_ostream OS(Out);
RegionBindingsTy B = GetRegionBindings(store);
OS << "Store:" << nl;
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index dd9490bebb960..7d1850d730957 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -188,12 +188,11 @@ bool SVal::isZeroConstant() const {
// Transfer function dispatch for Non-Locs.
//===----------------------------------------------------------------------===//
-SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
- BinaryOperator::Opcode Op,
- const nonloc::ConcreteInt& R) const {
-
+SVal nonloc::ConcreteInt::evalBinOp(ValueManager &ValMgr,
+ BinaryOperator::Opcode Op,
+ const nonloc::ConcreteInt& R) const {
const llvm::APSInt* X =
- BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue());
+ ValMgr.getBasicValueFactory().EvaluateAPSInt(Op, getValue(), R.getValue());
if (X)
return nonloc::ConcreteInt(*X);
@@ -201,20 +200,13 @@ SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
return UndefinedVal();
}
- // Bitwise-Complement.
-
nonloc::ConcreteInt
-nonloc::ConcreteInt::EvalComplement(BasicValueFactory& BasicVals) const {
- return BasicVals.getValue(~getValue());
+nonloc::ConcreteInt::evalComplement(ValueManager &ValMgr) const {
+ return ValMgr.makeIntVal(~getValue());
}
- // Unary Minus.
-
-nonloc::ConcreteInt
-nonloc::ConcreteInt::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const {
- assert (U->getType() == U->getSubExpr()->getType());
- assert (U->getType()->isIntegerType());
- return BasicVals.getValue(-getValue());
+nonloc::ConcreteInt nonloc::ConcreteInt::evalMinus(ValueManager &ValMgr) const {
+ return ValMgr.makeIntVal(-getValue());
}
//===----------------------------------------------------------------------===//
@@ -242,11 +234,6 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
void SVal::printStdErr() const { print(llvm::errs()); }
-void SVal::print(std::ostream& Out) const {
- llvm::raw_os_ostream out(Out);
- print(out);
-}
-
void SVal::print(llvm::raw_ostream& Out) const {
switch (getBaseKind()) {
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
new file mode 100644
index 0000000000000..76a8bc782eb57
--- /dev/null
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -0,0 +1,346 @@
+// SimpleSValuator.cpp - A basic SValuator ------------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SimpleSValuator, a basic implementation of SValuator.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/SValuator.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN SimpleSValuator : public SValuator {
+public:
+ SimpleSValuator(ValueManager &valMgr) : SValuator(valMgr) {}
+ virtual ~SimpleSValuator() {}
+
+ virtual SVal EvalCast(NonLoc val, QualType castTy);
+ virtual SVal EvalCast(Loc val, QualType castTy);
+ virtual SVal EvalMinus(NonLoc val);
+ virtual SVal EvalComplement(NonLoc val);
+ virtual SVal EvalBinOpNN(BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs,
+ QualType resultTy);
+ virtual SVal EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
+ QualType resultTy);
+ virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
+ Loc lhs, NonLoc rhs, QualType resultTy);
+};
+} // end anonymous namespace
+
+SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) {
+ return new SimpleSValuator(valMgr);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for Casts.
+//===----------------------------------------------------------------------===//
+
+SVal SimpleSValuator::EvalCast(NonLoc val, QualType castTy) {
+ if (!isa<nonloc::ConcreteInt>(val))
+ return UnknownVal();
+
+ bool isLocType = Loc::IsLocType(castTy);
+
+ // Only handle casts from integers to integers.
+ if (!isLocType && !castTy->isIntegerType())
+ return UnknownVal();
+
+ llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
+ i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+ i.extOrTrunc(ValMgr.getContext().getTypeSize(castTy));
+
+ if (isLocType)
+ return ValMgr.makeIntLocVal(i);
+ else
+ return ValMgr.makeIntVal(i);
+}
+
+SVal SimpleSValuator::EvalCast(Loc val, QualType castTy) {
+
+ // Casts from pointers -> pointers, just return the lval.
+ //
+ // Casts from pointers -> references, just return the lval. These
+ // can be introduced by the frontend for corner cases, e.g
+ // casting from va_list* to __builtin_va_list&.
+ //
+ assert(!val.isUnknownOrUndef());
+
+ if (Loc::IsLocType(castTy) || castTy->isReferenceType())
+ return val;
+
+ // FIXME: Handle transparent unions where a value can be "transparently"
+ // lifted into a union type.
+ if (castTy->isUnionType())
+ return UnknownVal();
+
+ assert(castTy->isIntegerType());
+ unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
+
+ if (!isa<loc::ConcreteInt>(val))
+ return ValMgr.makeLocAsInteger(val, BitWidth);
+
+ llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
+ i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+ i.extOrTrunc(BitWidth);
+ return ValMgr.makeIntVal(i);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for unary operators.
+//===----------------------------------------------------------------------===//
+
+SVal SimpleSValuator::EvalMinus(NonLoc val) {
+ switch (val.getSubKind()) {
+ case nonloc::ConcreteIntKind:
+ return cast<nonloc::ConcreteInt>(val).evalMinus(ValMgr);
+ default:
+ return UnknownVal();
+ }
+}
+
+SVal SimpleSValuator::EvalComplement(NonLoc X) {
+ switch (X.getSubKind()) {
+ case nonloc::ConcreteIntKind:
+ return cast<nonloc::ConcreteInt>(X).evalComplement(ValMgr);
+ default:
+ return UnknownVal();
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for binary operators.
+//===----------------------------------------------------------------------===//
+
+static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
+ switch (op) {
+ default:
+ assert(false && "Invalid opcode.");
+ case BinaryOperator::LT: return BinaryOperator::GE;
+ case BinaryOperator::GT: return BinaryOperator::LE;
+ case BinaryOperator::LE: return BinaryOperator::GT;
+ case BinaryOperator::GE: return BinaryOperator::LT;
+ case BinaryOperator::EQ: return BinaryOperator::NE;
+ case BinaryOperator::NE: return BinaryOperator::EQ;
+ }
+}
+
+// Equality operators for Locs.
+// FIXME: All this logic will be revamped when we have MemRegion::getLocation()
+// implemented.
+
+static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual,
+ QualType resultTy) {
+
+ switch (lhs.getSubKind()) {
+ default:
+ assert(false && "EQ/NE not implemented for this Loc.");
+ return UnknownVal();
+
+ case loc::ConcreteIntKind: {
+ if (SymbolRef rSym = rhs.getAsSymbol())
+ return ValMgr.makeNonLoc(rSym,
+ isEqual ? BinaryOperator::EQ
+ : BinaryOperator::NE,
+ cast<loc::ConcreteInt>(lhs).getValue(),
+ resultTy);
+ break;
+ }
+ case loc::MemRegionKind: {
+ if (SymbolRef lSym = lhs.getAsLocSymbol()) {
+ if (isa<loc::ConcreteInt>(rhs)) {
+ return ValMgr.makeNonLoc(lSym,
+ isEqual ? BinaryOperator::EQ
+ : BinaryOperator::NE,
+ cast<loc::ConcreteInt>(rhs).getValue(),
+ resultTy);
+ }
+ }
+ break;
+ }
+
+ case loc::GotoLabelKind:
+ break;
+ }
+
+ return ValMgr.makeTruthVal(isEqual ? lhs == rhs : lhs != rhs, resultTy);
+}
+
+SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
+ NonLoc lhs, NonLoc rhs,
+ QualType resultTy) {
+ while (1) {
+ switch (lhs.getSubKind()) {
+ default:
+ return UnknownVal();
+ case nonloc::LocAsIntegerKind: {
+ Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
+ switch (rhs.getSubKind()) {
+ case nonloc::LocAsIntegerKind:
+ return EvalBinOpLL(op, lhsL, cast<nonloc::LocAsInteger>(rhs).getLoc(),
+ resultTy);
+ case nonloc::ConcreteIntKind: {
+ // Transform the integer into a location and compare.
+ ASTContext& Ctx = ValMgr.getContext();
+ llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
+ i.setIsUnsigned(true);
+ i.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
+ return EvalBinOpLL(op, lhsL, ValMgr.makeLoc(i), resultTy);
+ }
+ default:
+ switch (op) {
+ case BinaryOperator::EQ:
+ return ValMgr.makeTruthVal(false, resultTy);
+ case BinaryOperator::NE:
+ return ValMgr.makeTruthVal(true, resultTy);
+ default:
+ // This case also handles pointer arithmetic.
+ return UnknownVal();
+ }
+ }
+ }
+ case nonloc::SymExprValKind: {
+ // Logical not?
+ if (!(op == BinaryOperator::EQ && rhs.isZeroConstant()))
+ return UnknownVal();
+
+ const SymExpr *symExpr =
+ cast<nonloc::SymExprVal>(lhs).getSymbolicExpression();
+
+ // Only handle ($sym op constant) for now.
+ if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(symExpr)) {
+ BinaryOperator::Opcode opc = symIntExpr->getOpcode();
+ switch (opc) {
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ assert(false && "Logical operators handled by branching logic.");
+ return UnknownVal();
+ case BinaryOperator::Assign:
+ case BinaryOperator::MulAssign:
+ case BinaryOperator::DivAssign:
+ case BinaryOperator::RemAssign:
+ case BinaryOperator::AddAssign:
+ case BinaryOperator::SubAssign:
+ case BinaryOperator::ShlAssign:
+ case BinaryOperator::ShrAssign:
+ case BinaryOperator::AndAssign:
+ case BinaryOperator::XorAssign:
+ case BinaryOperator::OrAssign:
+ case BinaryOperator::Comma:
+ assert(false && "'=' and ',' operators handled by GRExprEngine.");
+ return UnknownVal();
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ assert(false && "Pointer arithmetic not handled here.");
+ return UnknownVal();
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
+ case BinaryOperator::Add:
+ case BinaryOperator::Sub:
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ // Not handled yet.
+ return UnknownVal();
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ opc = NegateComparison(opc);
+ assert(symIntExpr->getType(ValMgr.getContext()) == resultTy);
+ return ValMgr.makeNonLoc(symIntExpr->getLHS(), opc,
+ symIntExpr->getRHS(), resultTy);
+ }
+ }
+ }
+ case nonloc::ConcreteIntKind: {
+ if (isa<nonloc::ConcreteInt>(rhs)) {
+ const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs);
+ return lhsInt.evalBinOp(ValMgr, op, cast<nonloc::ConcreteInt>(rhs));
+ }
+ else {
+ // Swap the left and right sides and flip the operator if doing so
+ // allows us to better reason about the expression (this is a form
+ // of expression canonicalization).
+ NonLoc tmp = rhs;
+ rhs = lhs;
+ lhs = tmp;
+
+ switch (op) {
+ case BinaryOperator::LT: op = BinaryOperator::GT; continue;
+ case BinaryOperator::GT: op = BinaryOperator::LT; continue;
+ case BinaryOperator::LE: op = BinaryOperator::GE; continue;
+ case BinaryOperator::GE: op = BinaryOperator::LE; continue;
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ case BinaryOperator::Add:
+ case BinaryOperator::Mul:
+ continue;
+ default:
+ return UnknownVal();
+ }
+ }
+ }
+ case nonloc::SymbolValKind: {
+ if (isa<nonloc::ConcreteInt>(rhs)) {
+ return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(lhs).getSymbol(), op,
+ cast<nonloc::ConcreteInt>(rhs).getValue(),
+ resultTy);
+ }
+
+ return UnknownVal();
+ }
+ }
+ }
+}
+
+SVal SimpleSValuator::EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
+ QualType resultTy) {
+ switch (op) {
+ default:
+ return UnknownVal();
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ return EvalEquality(ValMgr, lhs, rhs, op == BinaryOperator::EQ, resultTy);
+ }
+}
+
+SVal SimpleSValuator::EvalBinOpLN(const GRState *state,
+ BinaryOperator::Opcode op,
+ Loc lhs, NonLoc rhs, QualType resultTy) {
+ // Special case: 'rhs' is an integer that has the same width as a pointer and
+ // we are using the integer location in a comparison. Normally this cannot be
+ // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
+ // can generate comparisons that trigger this code.
+ // FIXME: Are all locations guaranteed to have pointer width?
+ if (BinaryOperator::isEqualityOp(op)) {
+ if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
+ const llvm::APSInt *x = &rhsInt->getValue();
+ ASTContext &ctx = ValMgr.getContext();
+ if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
+ // Convert the signedness of the integer (if necessary).
+ if (x->isSigned())
+ x = &ValMgr.getBasicValueFactory().getValue(*x, true);
+
+ return EvalBinOpLL(op, lhs, loc::ConcreteInt(*x), resultTy);
+ }
+ }
+ }
+
+ // Delegate pointer arithmetic to the StoreManager.
+ return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs,
+ rhs, resultTy);
+}
diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp
index 4e38a3492c79a..275f30a2963e0 100644
--- a/lib/Analysis/SymbolManager.cpp
+++ b/lib/Analysis/SymbolManager.cpp
@@ -85,12 +85,6 @@ llvm::raw_ostream& llvm::operator<<(llvm::raw_ostream& os, const SymExpr *SE) {
return os;
}
-std::ostream& std::operator<<(std::ostream& os, const SymExpr *SE) {
- llvm::raw_os_ostream O(os);
- print(O, SE);
- return os;
-}
-
const SymbolRegionValue*
SymbolManager::getRegionValueSymbol(const MemRegion* R, QualType T) {
llvm::FoldingSetNodeID profile;