summaryrefslogtreecommitdiffstats
path: root/lib/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis')
-rw-r--r--lib/Analysis/AnalysisContext.cpp4
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp11
-rw-r--r--lib/Analysis/BugReporter.cpp19
-rw-r--r--lib/Analysis/CFRefCount.cpp25
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp18
-rw-r--r--lib/Analysis/Environment.cpp7
-rw-r--r--lib/Analysis/GRExprEngine.cpp133
-rw-r--r--lib/Analysis/GRState.cpp3
-rw-r--r--lib/Analysis/MemRegion.cpp65
-rw-r--r--lib/Analysis/OSAtomicChecker.cpp28
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp8
-rw-r--r--lib/Analysis/RegionStore.cpp223
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp14
-rw-r--r--lib/Analysis/SVals.cpp4
-rw-r--r--lib/Analysis/SValuator.cpp8
-rw-r--r--lib/Analysis/SimpleConstraintManager.cpp47
-rw-r--r--lib/Analysis/SimpleConstraintManager.h3
-rw-r--r--lib/Analysis/SimpleSValuator.cpp8
-rw-r--r--lib/Analysis/Store.cpp43
19 files changed, 454 insertions, 217 deletions
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 97e6d91..2093b5e 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -18,6 +18,7 @@
#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Support/BumpVector.h"
@@ -38,6 +39,9 @@ Stmt *AnalysisContext::getBody() {
return MD->getBody();
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getBody();
+ else if (const FunctionTemplateDecl *FunTmpl
+ = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ return FunTmpl->getTemplatedDecl()->getBody();
llvm_unreachable("unknown code decl");
}
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index 6c3f7b2..6dfc470 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -49,8 +49,9 @@ class BasicConstraintManager
: public SimpleConstraintManager {
GRState::IntSetTy::Factory ISetFactory;
public:
- BasicConstraintManager(GRStateManager& statemgr)
- : ISetFactory(statemgr.getAllocator()) {}
+ BasicConstraintManager(GRStateManager &statemgr, GRSubEngine &subengine)
+ : SimpleConstraintManager(subengine),
+ ISetFactory(statemgr.getAllocator()) {}
const GRState* AssumeSymNE(const GRState* state, SymbolRef sym,
const llvm::APSInt& V);
@@ -88,9 +89,9 @@ public:
} // end anonymous namespace
-ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& StateMgr)
-{
- return new BasicConstraintManager(StateMgr);
+ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& statemgr,
+ GRSubEngine &subengine) {
+ return new BasicConstraintManager(statemgr, subengine);
}
const GRState*
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index e648269..2a9531d 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -1818,8 +1818,23 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
R->getRanges(Beg, End);
Diagnostic& Diag = getDiagnostic();
FullSourceLoc L(R->getLocation(), getSourceManager());
- unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
- R->getShortDescription().c_str());
+
+ // Search the description for '%', as that will be interpretted as a
+ // format character by FormatDiagnostics.
+ llvm::StringRef desc = R->getShortDescription();
+ unsigned ErrorDiag;
+ {
+ llvm::SmallString<512> TmpStr;
+ llvm::raw_svector_ostream Out(TmpStr);
+ for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I)
+ if (*I == '%')
+ Out << "%%";
+ else
+ Out << *I;
+
+ Out.flush();
+ ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr);
+ }
switch (End-Beg) {
default: assert(0 && "Don't handle this many ranges yet!");
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index a15a8f1..5a15fbf 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -52,8 +52,8 @@ using namespace clang;
// not release it."
//
-using llvm::CStrInCStrNoCase;
-using llvm::StringsEqualNoCase;
+using llvm::StrInStrNoCase;
+using llvm::StringRef;
enum NamingConvention { NoConvention, CreateRule, InitRule };
@@ -122,20 +122,20 @@ static NamingConvention deriveNamingConvention(Selector S) {
break;
case 3:
// Methods starting with 'new' follow the create rule.
- if (AtBeginning && StringsEqualNoCase("new", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("new"))
C = CreateRule;
break;
case 4:
// Methods starting with 'alloc' or contain 'copy' follow the
// create rule
- if (C == NoConvention && StringsEqualNoCase("copy", s, len))
+ if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
C = CreateRule;
else // Methods starting with 'init' follow the init rule.
- if (AtBeginning && StringsEqualNoCase("init", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("init"))
C = InitRule;
break;
case 5:
- if (AtBeginning && StringsEqualNoCase("alloc", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
C = CreateRule;
break;
}
@@ -1372,11 +1372,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// "AppendValue", or "SetAttribute", then we assume that arguments may
// "escape." This means that something else holds on to the object,
// allowing it be used even after its local retain count drops to 0.
- ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") ||
- CStrInCStrNoCase(FName, "AddValue") ||
- CStrInCStrNoCase(FName, "SetValue") ||
- CStrInCStrNoCase(FName, "AppendValue") ||
- CStrInCStrNoCase(FName, "SetAttribute"))
+ ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
+ StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
+ StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
+ StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
+ StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
? MayEscape : DoNothing;
S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E);
@@ -1555,7 +1555,8 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
if (S.isKeywordSelector()) {
const std::string &str = S.getAsString();
assert(!str.empty());
- if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking;
+ if (StrInStrNoCase(str, "delegate:") != StringRef::npos)
+ ReceiverEff = StopTracking;
}
// Look for methods that return an owned object.
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index 3214101..f4874a5 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/TargetInfo.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
@@ -18,6 +19,12 @@
using namespace clang;
+static bool isArc4RandomAvailable(const ASTContext &Ctx) {
+ const llvm::Triple &T = Ctx.Target.getTriple();
+ return T.getVendor() == llvm::Triple::Apple ||
+ T.getOS() == llvm::Triple::FreeBSD;
+}
+
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
@@ -29,11 +36,14 @@ class WalkAST : public StmtVisitor<WalkAST> {
IdentifierInfo *II_random;
enum { num_setids = 6 };
IdentifierInfo *II_setid[num_setids];
+
+ const bool CheckRand;
public:
WalkAST(BugReporter &br) : BR(br),
II_gets(0), II_getpw(0), II_mktemp(0),
- II_rand(), II_random(0), II_setid() {}
+ II_rand(), II_random(0), II_setid(),
+ CheckRand(isArc4RandomAvailable(BR.getContext())) {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -83,8 +93,10 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
CheckCall_gets(CE, FD);
CheckCall_getpw(CE, FD);
CheckCall_mktemp(CE, FD);
- CheckCall_rand(CE, FD);
- CheckCall_random(CE, FD);
+ if (CheckRand) {
+ CheckCall_rand(CE, FD);
+ CheckCall_random(CE, FD);
+ }
}
// Recurse and check children.
diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp
index dd2f08b..f04cf7b 100644
--- a/lib/Analysis/Environment.cpp
+++ b/lib/Analysis/Environment.cpp
@@ -37,7 +37,12 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
}
case Stmt::IntegerLiteralClass: {
- return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
+ // In C++, this expression may have been bound to a temporary object.
+ SVal const *X = ExprBindings.lookup(E);
+ if (X)
+ return *X;
+ else
+ return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
}
// Casts where the source and target type are the same
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 2ce8edd..40c12c9 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -17,6 +17,7 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
@@ -47,10 +48,9 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
}
-static bool CalleeReturnsReference(const CallExpr *CE) {
+static QualType GetCalleeReturnType(const CallExpr *CE) {
const Expr *Callee = CE->getCallee();
QualType T = Callee->getType();
-
if (const PointerType *PT = T->getAs<PointerType>()) {
const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>();
T = FT->getResultType();
@@ -58,16 +58,35 @@ static bool CalleeReturnsReference(const CallExpr *CE) {
else {
const BlockPointerType *BT = T->getAs<BlockPointerType>();
T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
- }
- return T->isReferenceType();
+ }
+ return T;
+}
+
+static bool CalleeReturnsReference(const CallExpr *CE) {
+ return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>();
}
static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (!MD)
return false;
- return MD->getResultType()->isReferenceType();
+ return MD->getResultType()->getAs<ReferenceType>();
+}
+
+#ifndef NDEBUG
+static bool ReceiverReturnsReferenceOrRecord(const ObjCMessageExpr *ME) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (!MD)
+ return false;
+ QualType T = MD->getResultType();
+ return T->getAs<RecordType>() || T->getAs<ReferenceType>();
+}
+
+static bool CalleeReturnsReferenceOrRecord(const CallExpr *CE) {
+ QualType T = GetCalleeReturnType(CE);
+ return T->getAs<ReferenceType>() || T->getAs<RecordType>();
}
+#endif
//===----------------------------------------------------------------------===//
// Batch auditor. DEPRECATED.
@@ -300,23 +319,27 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterOSAtomicChecker(Eng);
}
-GRExprEngine::GRExprEngine(AnalysisManager &mgr)
+GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
: AMgr(mgr),
CoreEngine(mgr.getASTContext(), *this),
G(CoreEngine.getGraph()),
Builder(NULL),
StateMgr(G.getContext(), mgr.getStoreManagerCreator(),
- mgr.getConstraintManagerCreator(), G.getAllocator()),
+ mgr.getConstraintManagerCreator(), G.getAllocator(),
+ *this),
SymMgr(StateMgr.getSymbolManager()),
ValMgr(StateMgr.getValueManager()),
SVator(ValMgr.getSValuator()),
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", G.getContext())),
- BR(mgr, *this)
-{
+ BR(mgr, *this), TF(tf) {
// Register internal checks.
RegisterInternalChecks(*this);
+
+ // FIXME: Eventually remove the TF object entirely.
+ TF->RegisterChecks(*this);
+ TF->RegisterPrinters(getStateManager().Printers);
}
GRExprEngine::~GRExprEngine() {
@@ -330,13 +353,6 @@ GRExprEngine::~GRExprEngine() {
// Utility methods.
//===----------------------------------------------------------------------===//
-void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) {
- StateMgr.TF = tf;
- StateMgr.Checkers = &Checkers;
- tf->RegisterChecks(*this);
- tf->RegisterPrinters(getStateManager().Printers);
-}
-
void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) {
if (!BatchAuditor)
BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
@@ -415,6 +431,25 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
+/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
+/// logic for handling assumptions on symbolic values.
+const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond,
+ bool assumption) {
+ for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
+ I != E; ++I) {
+
+ if (!state)
+ return NULL;
+
+ state = I->second->EvalAssume(state, cond, assumption);
+ }
+
+ if (!state)
+ return NULL;
+
+ return TF->EvalAssume(state, cond, assumption);
+}
+
void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
CurrentStmt = CE.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
@@ -809,7 +844,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass: {
CallExpr *C = cast<CallExpr>(Ex);
- assert(CalleeReturnsReference(C));
+ assert(CalleeReturnsReferenceOrRecord(C));
VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
break;
}
@@ -840,7 +875,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::ObjCMessageExprClass: {
ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
- assert(ReceiverReturnsReference(ME));
+ assert(ReceiverReturnsReferenceOrRecord(ME));
VisitObjCMessageExpr(ME, Pred, Dst, true);
return;
}
@@ -871,6 +906,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::UnaryOperatorClass:
VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
return;
+
+ // In C++, binding an rvalue to a reference requires to create an object.
+ case Stmt::IntegerLiteralClass:
+ CreateCXXTemporaryObject(Ex, Pred, Dst);
+ return;
default:
// Arbitrary subexpressions can return aggregate temporaries that
@@ -1205,7 +1245,8 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
do {
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
- DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt, CondV, CaseVal);
+ DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state,
+ CondV, CaseVal);
// Now "assume" that the case matches.
if (const GRState* stateNew = state->Assume(Res, true)) {
@@ -1220,11 +1261,17 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
// Now "assume" that the case doesn't match. Add this state
// to the default state (if it is feasible).
- if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
- defaultIsFeasible = true;
- DefaultSt = stateNew;
+ if (DefaultSt) {
+ if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
+ defaultIsFeasible = true;
+ DefaultSt = stateNew;
+ }
+ else {
+ defaultIsFeasible = false;
+ DefaultSt = NULL;
+ }
}
-
+
// Concretize the next value in the range.
if (V1.Val.getInt() == V2.Val.getInt())
break;
@@ -2375,12 +2422,12 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
QualType T = Ex->getTypeOfArgument();
- uint64_t amt;
+ CharUnits amt;
if (Ex->isSizeOf()) {
if (T == getContext().VoidTy) {
// sizeof(void) == 1 byte.
- amt = 1;
+ amt = CharUnits::One();
}
else if (!T.getTypePtr()->isConstantSizeType()) {
// FIXME: Add support for VLAs.
@@ -2394,14 +2441,15 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
}
else {
// All other cases.
- amt = getContext().getTypeSize(T) / 8;
+ amt = getContext().getTypeSizeInChars(T);
}
}
else // Get alignment of the type.
- amt = getContext().getTypeAlign(T) / 8;
+ amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8);
MakeNode(Dst, Ex, Pred,
- GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType())));
+ GetState(Pred)->BindExpr(Ex,
+ ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
@@ -2695,8 +2743,13 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst) {
// Get the this object region from StoreManager.
- Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType());
- MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V));
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXThisRegion(TE->getType(),
+ Pred->getLocationContext());
+
+ const GRState *state = GetState(Pred);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
}
void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
@@ -2964,6 +3017,26 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
CheckerVisit(B, Dst, Tmp3, false);
}
+void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ ExplodedNodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+
+ // Bind the temporary object to the value of the expression. Then bind
+ // the expression to the location of the object.
+ SVal V = state->getSVal(Ex);
+
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXObjectRegion(Ex,
+ Pred->getLocationContext());
+
+ state = state->bindLoc(loc::MemRegionVal(R), V);
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
+ }
+}
+
//===----------------------------------------------------------------------===//
// Checker registration/lookup.
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index 7415fa5..051d465 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -267,6 +267,9 @@ bool ScanReachableSymbols::scan(SVal val) {
if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
return scan(X->getRegion());
+ if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val))
+ return scan(X->getLoc());
+
if (SymbolRef Sym = val.getAsSymbol())
return visitor.VisitSymbol(Sym);
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index 74fe3bf..87d60d3 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -17,6 +17,7 @@
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/PathSensitive/ValueManager.h"
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/StmtVisitor.h"
using namespace clang;
@@ -215,6 +216,18 @@ void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
ID.AddPointer(superRegion);
}
+void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const PointerType *PT,
+ const MemRegion *sRegion) {
+ ID.AddInteger((unsigned) CXXThisRegionKind);
+ ID.AddPointer(PT);
+ ID.AddPointer(sRegion);
+}
+
+void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
+}
+
void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
const MemRegion* superRegion, Kind k) {
ID.AddInteger((unsigned) k);
@@ -292,14 +305,14 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- QualType T,
+ Expr const *Ex,
const MemRegion *sReg) {
- ID.AddPointer(T.getTypePtr());
+ ID.AddPointer(Ex);
ID.AddPointer(sReg);
}
void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, T, getSuperRegion());
+ ProfileRegion(ID, Ex, getSuperRegion());
}
//===----------------------------------------------------------------------===//
@@ -343,6 +356,10 @@ void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "{ " << (void*) CL << " }";
}
+void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const {
+ os << "this";
+}
+
void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "element{" << superRegion << ','
<< Index << ',' << getElementType().getAsString() << '}';
@@ -551,7 +568,7 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
}
-const FieldRegion *
+const FieldRegion*
MemRegionManager::getFieldRegion(const FieldDecl* d,
const MemRegion* superRegion){
return getSubRegion<FieldRegion>(d, superRegion);
@@ -563,9 +580,22 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
-const CXXObjectRegion *
-MemRegionManager::getCXXObjectRegion(QualType T) {
- return getSubRegion<CXXObjectRegion>(T, getUnknownRegion());
+const CXXObjectRegion*
+MemRegionManager::getCXXObjectRegion(Expr const *E,
+ LocationContext const *LC) {
+ const StackFrameContext *SFC = LC->getCurrentStackFrame();
+ assert(SFC);
+ return getSubRegion<CXXObjectRegion>(E, getStackLocalsRegion(SFC));
+}
+
+const CXXThisRegion*
+MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
+ const LocationContext *LC) {
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ const PointerType *PT = thisPointerTy->getAs<PointerType>();
+ assert(PT);
+ return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
}
const AllocaRegion*
@@ -592,20 +622,11 @@ bool MemRegion::hasStackStorage() const {
return isa<StackSpaceRegion>(getMemorySpace());
}
-bool MemRegion::hasHeapStorage() const {
- return isa<HeapSpaceRegion>(getMemorySpace());
-}
-
-bool MemRegion::hasHeapOrStackStorage() const {
- const MemSpaceRegion *MS = getMemorySpace();
- return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS);
-}
-
-bool MemRegion::hasGlobalsStorage() const {
- return isa<GlobalsSpaceRegion>(getMemorySpace());
+bool MemRegion::hasStackNonParametersStorage() const {
+ return isa<StackLocalsSpaceRegion>(getMemorySpace());
}
-bool MemRegion::hasParametersStorage() const {
+bool MemRegion::hasStackParametersStorage() const {
return isa<StackArgumentsSpaceRegion>(getMemorySpace());
}
@@ -669,7 +690,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
}
RegionRawOffset ElementRegion::getAsRawOffset() const {
- int64_t offset = 0;
+ CharUnits offset = CharUnits::Zero();
const ElementRegion *ER = this;
const MemRegion *superR = NULL;
ASTContext &C = getContext();
@@ -694,7 +715,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
break;
}
- int64_t size = (int64_t) (C.getTypeSize(elemType) / 8);
+ CharUnits size = C.getTypeSizeInChars(elemType);
offset += (i * size);
}
@@ -707,7 +728,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
}
assert(superR && "super region cannot be NULL");
- return RegionRawOffset(superR, offset);
+ return RegionRawOffset(superR, offset.getQuantity());
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp
index cf16796..9d34e9e 100644
--- a/lib/Analysis/OSAtomicChecker.cpp
+++ b/lib/Analysis/OSAtomicChecker.cpp
@@ -103,19 +103,9 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
SVal location = state->getSVal(theValueExpr);
// Here we should use the value type of the region as the load type.
QualType LoadTy;
- if (const MemRegion *R = location.getAsRegion()) {
- // We must be careful, as SymbolicRegions aren't typed.
- const MemRegion *strippedR = R->StripCasts();
- // FIXME: This isn't quite the right solution. One test case in 'test/Analysis/NSString.m'
- // is giving the wrong result.
- const TypedRegion *typedR =
- isa<SymbolicRegion>(strippedR) ? cast<TypedRegion>(R) :
- dyn_cast<TypedRegion>(strippedR);
-
- if (typedR) {
- LoadTy = typedR->getValueType(Ctx);
- location = loc::MemRegionVal(typedR);
- }
+ if (const TypedRegion *TR =
+ dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ LoadTy = TR->getValueType(Ctx);
}
Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(),
state, location, OSAtomicLoadTag, LoadTy);
@@ -184,14 +174,22 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
E2 = TmpStore.end(); I2 != E2; ++I2) {
ExplodedNode *predNew = *I2;
const GRState *stateNew = predNew->getState();
- SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
+ // Check for 'void' return type if we have a bogus function prototype.
+ SVal Res = UnknownVal();
+ QualType T = CE->getType();
+ if (!T->isVoidType())
+ Res = Engine.getValueManager().makeTruthVal(true, T);
C.GenerateNode(stateNew->BindExpr(CE, Res), predNew);
}
}
// Were they not equal?
if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
- SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
+ // Check for 'void' return type if we have a bogus function prototype.
+ SVal Res = UnknownVal();
+ QualType T = CE->getType();
+ if (!T->isVoidType())
+ Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N);
}
}
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index 7330b62..2cf3dfb 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -234,7 +234,8 @@ namespace {
class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(const GRState *state, SymbolRef sym);
public:
- RangeConstraintManager() {}
+ RangeConstraintManager(GRSubEngine &subengine)
+ : SimpleConstraintManager(subengine) {}
const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
const llvm::APSInt& V);
@@ -273,8 +274,9 @@ private:
} // end anonymous namespace
-ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&) {
- return new RangeConstraintManager();
+ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&,
+ GRSubEngine &subeng) {
+ return new RangeConstraintManager(subeng);
}
const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 3bc9dcc..9b5b44b 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -28,9 +28,12 @@
using namespace clang;
-#define HEAP_UNDEFINED 0
#define USE_EXPLICIT_COMPOUND 0
+//===----------------------------------------------------------------------===//
+// Representation of value bindings.
+//===----------------------------------------------------------------------===//
+
namespace {
class BindingVal {
public:
@@ -77,8 +80,41 @@ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) {
}
} // end llvm namespace
+//===----------------------------------------------------------------------===//
+// Representation of binding keys.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class BindingKey : public std::pair<const MemRegion*, uint64_t> {
+public:
+ explicit BindingKey(const MemRegion *r, uint64_t offset)
+ : std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); }
+
+ const MemRegion *getRegion() const { return first; }
+ uint64_t getOffset() const { return second; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddPointer(getRegion());
+ ID.AddInteger(getOffset());
+ }
+
+ static BindingKey Make(const MemRegion *R);
+};
+} // end anonymous namespace
+
+namespace llvm {
+ static inline
+ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
+ os << '(' << K.getRegion() << ',' << K.getOffset() << ')';
+ return os;
+ }
+} // end llvm namespace
+
+//===----------------------------------------------------------------------===//
// Actual Store type.
-typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings;
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings;
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -283,6 +319,16 @@ private:
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
RegionStoreSubRegionMap &M);
+ RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V);
+ RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V);
+
+ const BindingVal *Lookup(RegionBindings B, BindingKey K);
+ const BindingVal *Lookup(RegionBindings B, const MemRegion *R);
+
+ RegionBindings Remove(RegionBindings B, BindingKey K);
+ RegionBindings Remove(RegionBindings B, const MemRegion *R);
+ Store Remove(Store store, BindingKey K);
+
public:
const GRState *Bind(const GRState *state, Loc LV, SVal V);
@@ -308,6 +354,7 @@ public:
Store KillStruct(Store store, const TypedRegion* R);
Store Remove(Store store, Loc LV);
+
//===------------------------------------------------------------------===//
// Loading values from regions.
@@ -438,7 +485,7 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
llvm::SmallVector<const SubRegion*, 10> WL;
for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I)
- if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey()))
+ if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion()))
M->process(WL, R);
// We also need to record in the subregion map "intermediate" regions that
@@ -467,8 +514,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I)
RemoveSubRegionBindings(B, *I, M);
-
- B = RBFactory.Remove(B, R);
+
+ B = Remove(B, R);
}
const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
@@ -544,8 +591,8 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
- Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ Count);
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -566,7 +613,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -574,7 +621,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V =
ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -583,14 +630,14 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// For fields and elements whose super region has also been invalidated,
// only remove the old binding. The super region will get set with a
// default value from which we can lazily derive a new symbolic value.
- B = RBFactory.Remove(B, R);
+ B = Remove(B, R);
continue;
}
// Invalidate the binding.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct));
+ B = Add(B, R, BindingVal(V, BindingVal::Direct));
}
// Create a new state with the updated bindings.
@@ -723,6 +770,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
const MemRegion *R) {
switch (R->getKind()) {
+ case MemRegion::CXXThisRegionKind:
+ assert(0 && "Cannot get size of 'this' region");
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -877,6 +926,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
// Technically this can happen if people do funny things with casts.
return UnknownVal();
+ case MemRegion::CXXThisRegionKind:
+ assert(0 &&
+ "Cannot perform pointer arithmetic on implicit argument 'this'");
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -921,7 +973,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
const MemRegion *R) {
- if (const BindingVal *BV = B.lookup(R))
+ if (const BindingVal *BV = Lookup(B, R))
return Optional<SVal>::create(BV->getDirectValue());
return Optional<SVal>();
@@ -935,7 +987,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
if (TR->getValueType(getContext())->isUnionType())
return UnknownVal();
- if (BindingVal const *V = B.lookup(R))
+ if (const BindingVal *V = Lookup(B, R))
return Optional<SVal>::create(V->getDefaultValue());
return Optional<SVal>();
@@ -943,7 +995,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
const MemRegion *R) {
- if (const BindingVal *BV = B.lookup(R))
+ if (const BindingVal *BV = Lookup(B, R))
return Optional<SVal>::create(BV->getValue());
return Optional<SVal>();
@@ -1051,22 +1103,46 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveField(state, FR), FR, T));
-
- if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
+ CastRetrievedVal(RetrieveField(state, FR), FR,
+ T, false));
+
+ if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the element type. Eventually we want to compose these values
+ // more intelligently. For example, an 'element' can encompass multiple
+ // bound regions (e.g., several bound bytes), or could be a subset of
+ // a larger value.
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveElement(state, ER), ER, T));
-
- if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
+ CastRetrievedVal(RetrieveElement(state, ER),
+ ER, T, false));
+ }
+
+ if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the ivar type. What we should model is stores to ivars
+ // that blow past the extent of the ivar. If the address of the ivar is
+ // reinterpretted, it is possible we stored a different value that could
+ // fit within the ivar. Either we need to cast these when storing them
+ // or reinterpret them lazily (as we do here).
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T));
+ CastRetrievedVal(RetrieveObjCIvar(state, IVR),
+ IVR, T, false));
+ }
- if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the variable type. What we should model is stores to variables
+ // that blow past the extent of the variable. If the address of the
+ // variable is reinterpretted, it is possible we stored a different value
+ // that could fit within the variable. Either we need to cast these when
+ // storing them or reinterpret them lazily (as we do here).
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveVar(state, VR), VR, T));
+ CastRetrievedVal(RetrieveVar(state, VR), VR, T,
+ false));
+ }
RegionBindings B = GetRegionBindings(state->getStore());
- RegionBindings::data_type* V = B.lookup(R);
+ const BindingVal *V = Lookup(B, R);
// Check if the region has a binding.
if (V)
@@ -1076,12 +1152,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// The location does not have a bound value. This means that it has
// the value it had upon its creation and/or entry to the analyzed
// function/method. These are either symbolic values or 'undefined'.
-
-#if HEAP_UNDEFINED
- if (R->hasHeapOrStackStorage()) {
-#else
- if (R->hasStackStorage()) {
-#endif
+ if (R->hasStackNonParametersStorage()) {
// All stack variables are considered to have undefined values
// upon creation. All heap allocated blocks are considered to
// have undefined values as well unless they are explicitly bound
@@ -1124,7 +1195,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
const ElementRegion* R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(state->getStore());
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
const MemRegion* superR = R->getSuperRegion();
@@ -1174,7 +1245,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
// Other cases: give up.
return UnknownVal();
}
-
+
return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR);
}
@@ -1240,8 +1311,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
cast<FieldRegion>(lazyBindingRegion));
}
- if (R->hasStackStorage() && !R->hasParametersStorage()) {
-
+ if (R->hasStackNonParametersStorage()) {
if (isa<ElementRegion>(R)) {
// Currently we don't reason specially about Clang-style vectors. Check
// if superR is a vector and if so return Unknown.
@@ -1369,15 +1439,9 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
//===----------------------------------------------------------------------===//
Store RegionStoreManager::Remove(Store store, Loc L) {
- const MemRegion* R = 0;
-
if (isa<loc::MemRegionVal>(L))
- R = cast<loc::MemRegionVal>(L).getRegion();
-
- if (R) {
- RegionBindings B = GetRegionBindings(store);
- return RBFactory.Remove(B, R).getRoot();
- }
+ if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
+ return Remove(store, BindingKey::Make(R));
return store;
}
@@ -1436,8 +1500,8 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
// Perform the binding.
RegionBindings B = GetRegionBindings(state->getStore());
- return state->makeWithStore(
- RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Direct)).getRoot());
}
const GRState *RegionStoreManager::BindDecl(const GRState *ST,
@@ -1483,9 +1547,9 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
else {
return state;
}
-
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
- return state->makeWithStore(B.getRoot());
+
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Default)).getRoot());
}
const GRState *RegionStoreManager::BindArray(const GRState *state,
@@ -1610,8 +1674,7 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
if (FI != FE) {
Store store = state->getStore();
RegionBindings B = GetRegionBindings(store);
- B = RBFactory.Add(B, R,
- BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
+ B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
state = state->makeWithStore(B.getRoot());
}
@@ -1625,7 +1688,7 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
RemoveSubRegionBindings(B, R, *SubRegions);
// Set the default value of the struct region to "unknown".
- B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
+ B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
return B.getRoot();
}
@@ -1646,8 +1709,58 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
// Now copy the bindings. This amounts to just binding 'V' to 'R'. This
// results in a zero-copy algorithm.
- return state->makeWithStore(
- RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Direct)).getRoot());
+}
+
+//===----------------------------------------------------------------------===//
+// "Raw" retrievals and bindings.
+//===----------------------------------------------------------------------===//
+
+BindingKey BindingKey::Make(const MemRegion *R) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ const RegionRawOffset &O = ER->getAsRawOffset();
+
+ if (O.getRegion())
+ return BindingKey(O.getRegion(), O.getByteOffset());
+
+ // FIXME: There are some ElementRegions for which we cannot compute
+ // raw offsets yet, including regions with symbolic offsets.
+ }
+
+ return BindingKey(R, 0);
+}
+
+RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K,
+ BindingVal V) {
+ return RBFactory.Add(B, K, V);
+}
+
+RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R,
+ BindingVal V) {
+ return Add(B, BindingKey::Make(R), V);
+}
+
+const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) {
+ return B.lookup(K);
+}
+
+const BindingVal *RegionStoreManager::Lookup(RegionBindings B,
+ const MemRegion *R) {
+ return Lookup(B, BindingKey::Make(R));
+}
+
+RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) {
+ return RBFactory.Remove(B, K);
+}
+
+RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){
+ return Remove(B, BindingKey::Make(R));
+}
+
+Store RegionStoreManager::Remove(Store store, BindingKey K) {
+ RegionBindings B = GetRegionBindings(store);
+ return Remove(B, K).getRoot();
}
//===----------------------------------------------------------------------===//
@@ -1674,7 +1787,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Scan the direct bindings for "intermediate" roots.
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion *R = I.getKey();
+ const MemRegion *R = I.getKey().getRegion();
IntermediateRoots.push_back(R);
}
@@ -1831,13 +1944,13 @@ tryAgain:
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion* R = I.getKey();
+ const MemRegion* R = I.getKey().getRegion();
// If this region live? Is so, none of its symbols are dead.
if (Visited.count(std::make_pair(&state, R)))
continue;
// Remove this dead region from the store.
- store = Remove(store, ValMgr.makeLoc(R));
+ store = Remove(store, I.getKey());
// Mark all non-live symbols that this region references as dead.
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp
index 3a6d8a4..4d7e8ad 100644
--- a/lib/Analysis/ReturnStackAddressChecker.cpp
+++ b/lib/Analysis/ReturnStackAddressChecker.cpp
@@ -67,6 +67,9 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
llvm::raw_svector_ostream os(buf);
SourceRange range;
+ // Get the base region, stripping away fields and elements.
+ R = R->getBaseRegion();
+
// Check if the region is a compound literal.
if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
const CompoundLiteralExpr* CL = CR->getLiteralExpr();
@@ -92,13 +95,18 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
<< C.getSourceManager().getInstantiationLineNumber(L)
<< " returned to caller";
}
- else {
+ else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
os << "Address of stack memory associated with local variable '"
- << R->getString() << "' returned.";
+ << VR->getString() << "' returned";
+ range = VR->getDecl()->getSourceRange();
+ }
+ else {
+ assert(false && "Invalid region in ReturnStackAddressChecker.");
+ return;
}
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(RS->getSourceRange());
+ report->addRange(RetE->getSourceRange());
if (range.isValid())
report->addRange(range);
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index 9163b27..fbdb73b 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -97,6 +97,10 @@ const MemRegion *SVal::getAsRegion() const {
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
return X->getRegion();
+ if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
+ return X->getLoc().getAsRegion();
+ }
+
return 0;
}
diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp
index 49bc0c4..8392fcf 100644
--- a/lib/Analysis/SValuator.cpp
+++ b/lib/Analysis/SValuator.cpp
@@ -62,8 +62,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
ASTContext &C = ValMgr.getContext();
// For const casts, just propagate the value.
- if (C.hasSameUnqualifiedType(castTy, originalTy))
- return CastResult(state, val);
+ if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
+ if (C.hasSameUnqualifiedType(castTy, originalTy))
+ return CastResult(state, val);
+
+ if (castTy->isIntegerType() && originalTy->isIntegerType())
+ return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy));
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp
index 23c3b41..eca20d5 100644
--- a/lib/Analysis/SimpleConstraintManager.cpp
+++ b/lib/Analysis/SimpleConstraintManager.cpp
@@ -65,25 +65,10 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state,
return Assume(state, cast<Loc>(Cond), Assumption);
}
-const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond,
- bool Assumption) {
-
- state = AssumeAux(state, Cond, Assumption);
-
- // EvalAssume is used to call into the GRTransferFunction object to perform
- // any checker-specific update of the state based on this assumption being
- // true or false.
-
- if (!state)
- return 0;
-
- std::vector<std::pair<void *, Checker*> >::iterator
- I = state->checker_begin(), E = state->checker_end();
-
- for (; I != E; ++I) {
- state = I->second->EvalAssume(state, Cond, Assumption);
- }
- return state->getTransferFuncs().EvalAssume(state, Cond, Assumption);
+const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc cond,
+ bool assumption) {
+ state = AssumeAux(state, cond, assumption);
+ return SU.ProcessAssume(state, cond, assumption);
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
@@ -130,26 +115,10 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
}
const GRState *SimpleConstraintManager::Assume(const GRState *state,
- NonLoc Cond,
- bool Assumption) {
-
- state = AssumeAux(state, Cond, Assumption);
-
- // EvalAssume is used to call into the GRTransferFunction object to perform
- // any checker-specific update of the state based on this assumption being
- // true or false.
-
- if (!state)
- return 0;
-
- std::vector<std::pair<void *, Checker*> >::iterator
- I = state->checker_begin(), E = state->checker_end();
-
- for (; I != E; ++I) {
- state = I->second->EvalAssume(state, Cond, Assumption);
- }
-
- return state->getTransferFuncs().EvalAssume(state, Cond, Assumption);
+ NonLoc cond,
+ bool assumption) {
+ state = AssumeAux(state, cond, assumption);
+ return SU.ProcessAssume(state, cond, assumption);
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h
index 0c58440..8182398 100644
--- a/lib/Analysis/SimpleConstraintManager.h
+++ b/lib/Analysis/SimpleConstraintManager.h
@@ -20,8 +20,9 @@
namespace clang {
class SimpleConstraintManager : public ConstraintManager {
+ GRSubEngine &SU;
public:
- SimpleConstraintManager() {}
+ SimpleConstraintManager(GRSubEngine &subengine) : SU(subengine) {}
virtual ~SimpleConstraintManager();
//===------------------------------------------------------------------===//
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 2afcd3e..8f2f5a1 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -53,13 +53,13 @@ SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) {
if (isLocType)
return LI->getLoc();
+ // FIXME: Correctly support promotions/truncations.
ASTContext &Ctx = ValMgr.getContext();
-
- // FIXME: Support promotions/truncations.
- if (Ctx.getTypeSize(castTy) == Ctx.getTypeSize(Ctx.VoidPtrTy))
+ unsigned castSize = Ctx.getTypeSize(castTy);
+ if (castSize == LI->getNumBits())
return val;
- return UnknownVal();
+ return ValMgr.makeLocAsInteger(LI->getLoc(), castSize);
}
if (const SymExpr *se = val.getAsSymbolicExpression()) {
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 8d911b8..1724a92 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -13,6 +13,7 @@
#include "clang/Analysis/PathSensitive/Store.h"
#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/AST/CharUnits.h"
using namespace clang;
@@ -77,6 +78,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// Process region cast according to the kind of the region being cast.
switch (R->getKind()) {
+ case MemRegion::CXXThisRegionKind:
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -137,9 +139,9 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (!baseR)
return NULL;
- int64_t off = rawOff.getByteOffset();
+ CharUnits off = CharUnits::fromQuantity(rawOff.getByteOffset());
- if (off == 0) {
+ if (off.isZero()) {
// Edge case: we are at 0 bytes off the beginning of baseR. We
// check to see if type we are casting to is the same as the base
// region. If so, just return the base region.
@@ -167,7 +169,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// We can only compute sizeof(PointeeTy) if it is a complete type.
if (IsCompleteType(Ctx, PointeeTy)) {
// Compute the size in **bytes**.
- int64_t pointeeTySize = (int64_t) (Ctx.getTypeSize(PointeeTy) / 8);
+ CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy);
// Is the offset a multiple of the size? If so, we can layer the
// ElementRegion (with elementType == PointeeTy) directly on top of
@@ -181,7 +183,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (!newSuperR) {
// Create an intermediate ElementRegion to represent the raw byte.
// This will be the super region of the final ElementRegion.
- newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off);
+ newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity());
}
return MakeElementRegion(newSuperR, PointeeTy, newIndex);
@@ -196,23 +198,29 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
-SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
- QualType castTy) {
+SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
+ QualType castTy, bool performTestOnly) {
-#ifndef NDEBUG
if (castTy.isNull())
return V;
ASTContext &Ctx = ValMgr.getContext();
- QualType T = R->getValueType(Ctx);
-
- // Automatically translate references to pointers.
- if (const ReferenceType *RT = T->getAs<ReferenceType>())
- T = Ctx.getPointerType(RT->getPointeeType());
-
- assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
-#endif
+ if (performTestOnly) {
+ // Automatically translate references to pointers.
+ QualType T = R->getValueType(Ctx);
+ if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ T = Ctx.getPointerType(RT->getPointeeType());
+
+ assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
+ return V;
+ }
+
+ if (const Loc *L = dyn_cast<Loc>(&V))
+ return ValMgr.getSValuator().EvalCastL(*L, castTy);
+ else if (const NonLoc *NL = dyn_cast<NonLoc>(&V))
+ return ValMgr.getSValuator().EvalCastNL(*NL, castTy);
+
return V;
}
@@ -240,8 +248,3 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
const LocationContext *LC) {
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
}
-
-Loc StoreManager::getThisObject(QualType T) {
- const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T);
- return loc::MemRegionVal(R);
-}
OpenPOWER on IntegriCloud