summaryrefslogtreecommitdiffstats
path: root/lib/Analysis
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-12-15 18:49:47 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-12-15 18:49:47 +0000
commit77212133072dc40f070a280af8217032f55a9eb4 (patch)
tree2fd5819f49caecc5f520219b6b9254fe94ebb138 /lib/Analysis
parent4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa (diff)
downloadFreeBSD-src-77212133072dc40f070a280af8217032f55a9eb4.zip
FreeBSD-src-77212133072dc40f070a280af8217032f55a9eb4.tar.gz
Update clang to 91430.
Diffstat (limited to 'lib/Analysis')
-rw-r--r--lib/Analysis/AnalysisContext.cpp153
-rw-r--r--lib/Analysis/BasicStore.cpp10
-rw-r--r--lib/Analysis/BugReporter.cpp17
-rw-r--r--lib/Analysis/BuiltinFunctionChecker.cpp76
-rw-r--r--lib/Analysis/CFG.cpp12
-rw-r--r--lib/Analysis/CFRefCount.cpp117
-rw-r--r--lib/Analysis/CMakeLists.txt4
-rw-r--r--lib/Analysis/CallAndMessageChecker.cpp27
-rw-r--r--lib/Analysis/CallGraph.cpp150
-rw-r--r--lib/Analysis/CheckDeadStores.cpp7
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp42
-rw-r--r--lib/Analysis/Checker.cpp4
-rw-r--r--lib/Analysis/GRExprEngine.cpp541
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.h3
-rw-r--r--lib/Analysis/GRState.cpp12
-rw-r--r--lib/Analysis/MallocChecker.cpp123
-rw-r--r--lib/Analysis/MemRegion.cpp362
-rw-r--r--lib/Analysis/NoReturnFunctionChecker.cpp80
-rw-r--r--lib/Analysis/OSAtomicChecker.cpp196
-rw-r--r--lib/Analysis/PathDiagnostic.cpp49
-rw-r--r--lib/Analysis/RegionStore.cpp123
-rw-r--r--lib/Analysis/Store.cpp37
-rw-r--r--lib/Analysis/SymbolManager.cpp5
-rw-r--r--lib/Analysis/ValueManager.cpp9
24 files changed, 1341 insertions, 818 deletions
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 339e2c9..05e5196 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h"
@@ -35,8 +36,10 @@ Stmt *AnalysisContext::getBody() {
return FD->getBody();
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getBody();
+ else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
+ return BD->getBody();
- llvm::llvm_unreachable("unknown code decl");
+ llvm_unreachable("unknown code decl");
}
const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
@@ -80,73 +83,113 @@ AnalysisContext *AnalysisContextManager::getContext(const Decl *D) {
return AC;
}
-void LocationContext::Profile(llvm::FoldingSetNodeID &ID, ContextKind k,
- AnalysisContext *ctx,
- const LocationContext *parent) {
- ID.AddInteger(k);
+const BlockDecl *BlockInvocationContext::getBlockDecl() const {
+ return Data.is<const BlockDataRegion*>() ?
+ Data.get<const BlockDataRegion*>()->getDecl()
+ : Data.get<const BlockDecl*>();
+}
+
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling.
+//===----------------------------------------------------------------------===//
+
+void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
+ ContextKind ck,
+ AnalysisContext *ctx,
+ const LocationContext *parent,
+ const void* data) {
+ ID.AddInteger(ck);
ID.AddPointer(ctx);
ID.AddPointer(parent);
+ ID.AddPointer(data);
}
-void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID,AnalysisContext *ctx,
- const LocationContext *parent, const Stmt *s) {
- LocationContext::Profile(ID, StackFrame, ctx, parent);
- ID.AddPointer(s);
+void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getAnalysisContext(), getParent(), CallSite);
}
-void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
- const LocationContext *parent, const Stmt *s) {
- LocationContext::Profile(ID, Scope, ctx, parent);
- ID.AddPointer(s);
+void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getAnalysisContext(), getParent(), Enter);
}
-LocationContextManager::~LocationContextManager() {
- clear();
+void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
+ if (const BlockDataRegion *BR = getBlockRegion())
+ Profile(ID, getAnalysisContext(), getParent(), BR);
+ else
+ Profile(ID, getAnalysisContext(), getParent(),
+ Data.get<const BlockDecl*>());
}
-void LocationContextManager::clear() {
- for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
- E = Contexts.end(); I != E; ) {
- LocationContext *LC = &*I;
- ++I;
- delete LC;
- }
+//===----------------------------------------------------------------------===//
+// LocationContext creation.
+//===----------------------------------------------------------------------===//
+
+template <typename LOC, typename DATA>
+const LOC*
+LocationContextManager::getLocationContext(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const DATA *d) {
+ llvm::FoldingSetNodeID ID;
+ LOC::Profile(ID, ctx, parent, d);
+ void *InsertPos;
- Contexts.clear();
+ LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
+
+ if (!L) {
+ L = new LOC(ctx, parent, d);
+ Contexts.InsertNode(L, InsertPos);
+ }
+ return L;
}
-StackFrameContext*
+const StackFrameContext*
LocationContextManager::getStackFrame(AnalysisContext *ctx,
const LocationContext *parent,
const Stmt *s) {
- llvm::FoldingSetNodeID ID;
- StackFrameContext::Profile(ID, ctx, parent, s);
- void *InsertPos;
+ return getLocationContext<StackFrameContext, Stmt>(ctx, parent, s);
+}
- StackFrameContext *f =
- cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
- if (!f) {
- f = new StackFrameContext(ctx, parent, s);
- Contexts.InsertNode(f, InsertPos);
- }
- return f;
+const ScopeContext *
+LocationContextManager::getScope(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const Stmt *s) {
+ return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
}
-ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx,
- const LocationContext *parent,
- const Stmt *s) {
- llvm::FoldingSetNodeID ID;
- ScopeContext::Profile(ID, ctx, parent, s);
- void *InsertPos;
+const BlockInvocationContext *
+LocationContextManager::getBlockInvocation(AnalysisContext *ctx,
+ const LocationContext *parent,
+ const BlockDataRegion *BR) {
+ return getLocationContext<BlockInvocationContext, BlockDataRegion>(ctx,
+ parent,
+ BR);
+}
- ScopeContext *scope =
- cast_or_null<ScopeContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
+//===----------------------------------------------------------------------===//
+// LocationContext methods.
+//===----------------------------------------------------------------------===//
- if (!scope) {
- scope = new ScopeContext(ctx, parent, s);
- Contexts.InsertNode(scope, InsertPos);
+const StackFrameContext *LocationContext::getCurrentStackFrame() const {
+ const LocationContext *LC = this;
+ while (LC) {
+ if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC))
+ return SFC;
+ LC = LC->getParent();
}
- return scope;
+ return NULL;
+}
+
+const StackFrameContext *
+LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const {
+ const LocationContext *LC = this;
+ while (LC) {
+ if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) {
+ if (cast<DeclContext>(SFC->getDecl()) == DC)
+ return SFC;
+ }
+ LC = LC->getParent();
+ }
+ return NULL;
}
//===----------------------------------------------------------------------===//
@@ -220,3 +263,21 @@ AnalysisContextManager::~AnalysisContextManager() {
for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
delete I->second;
}
+
+LocationContext::~LocationContext() {}
+
+LocationContextManager::~LocationContextManager() {
+ clear();
+}
+
+void LocationContextManager::clear() {
+ for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
+ E = Contexts.end(); I != E; ) {
+ LocationContext *LC = &*I;
+ ++I;
+ delete LC;
+ }
+
+ Contexts.clear();
+}
+
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 45fc11a..a38aaa7 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -68,14 +68,14 @@ public:
}
const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* cl,
+ const CompoundLiteralExpr*,
+ const LocationContext*,
SVal val) {
return state;
}
SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
SVal getLValueString(const StringLiteral *S);
- SVal getLValueCompoundLiteral(const CompoundLiteralExpr *CL);
SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
SVal getLValueField(const FieldDecl *D, SVal Base);
SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
@@ -130,10 +130,6 @@ SVal BasicStoreManager::getLValueString(const StringLiteral* S) {
return ValMgr.makeLoc(MRMgr.getStringRegion(S));
}
-SVal BasicStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL){
- return ValMgr.makeLoc(MRMgr.getCompoundLiteralRegion(CL));
-}
-
SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
if (Base.isUnknownOrUndef())
@@ -368,7 +364,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Iterate over the variable bindings.
for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
if (const VarRegion *VR = dyn_cast<VarRegion>(I.getKey())) {
- if (SymReaper.isLive(Loc, VR->getDecl()))
+ if (SymReaper.isLive(Loc, VR))
RegionRoots.push_back(VR);
else
continue;
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index c26a60a..e648269 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -204,10 +204,19 @@ PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os,
os << "Execution continues on line "
<< getSourceManager().getInstantiationLineNumber(Loc.asLocation())
<< '.';
- else
- os << "Execution jumps to the end of the "
- << (isa<ObjCMethodDecl>(N->getLocationContext()->getDecl()) ?
- "method" : "function") << '.';
+ else {
+ os << "Execution jumps to the end of the ";
+ const Decl *D = N->getLocationContext()->getDecl();
+ if (isa<ObjCMethodDecl>(D))
+ os << "method";
+ else if (isa<FunctionDecl>(D))
+ os << "function";
+ else {
+ assert(isa<BlockDecl>(D));
+ os << "anonymous block";
+ }
+ os << '.';
+ }
return Loc;
}
diff --git a/lib/Analysis/BuiltinFunctionChecker.cpp b/lib/Analysis/BuiltinFunctionChecker.cpp
new file mode 100644
index 0000000..a89ad21
--- /dev/null
+++ b/lib/Analysis/BuiltinFunctionChecker.cpp
@@ -0,0 +1,76 @@
+//=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker evaluates clang builtin functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Basic/Builtins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+
+namespace {
+
+class BuiltinFunctionChecker : public Checker {
+public:
+ static void *getTag() { static int tag = 0; return &tag; }
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void clang::RegisterBuiltinFunctionChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new BuiltinFunctionChecker());
+}
+
+bool BuiltinFunctionChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE){
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+
+ if (!FD)
+ return false;
+
+ unsigned id = FD->getBuiltinID();
+
+ if (!id)
+ return false;
+
+ switch (id) {
+ case Builtin::BI__builtin_expect: {
+ // For __builtin_expect, just return the value of the subexpression.
+ assert (CE->arg_begin() != CE->arg_end());
+ SVal X = state->getSVal(*(CE->arg_begin()));
+ C.GenerateNode(state->BindExpr(CE, X));
+ return true;
+ }
+
+ case Builtin::BI__builtin_alloca: {
+ // FIXME: Refactor into StoreManager itself?
+ MemRegionManager& RM = C.getStoreManager().getRegionManager();
+ const MemRegion* R =
+ RM.getAllocaRegion(CE, C.getNodeBuilder().getCurrentBlockCount(),
+ C.getPredecessor()->getLocationContext());
+
+ // Set the extent of the region in bytes. This enables us to use the
+ // SVal of the argument directly. If we save the extent in bits, we
+ // cannot represent values like symbol*8.
+ SVal Extent = state->getSVal(*(CE->arg_begin()));
+ state = C.getStoreManager().setExtent(state, R, Extent);
+ C.GenerateNode(state->BindExpr(CE, loc::MemRegionVal(R)));
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index c97692f..e1a1e72 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -87,7 +87,6 @@ private:
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd);
CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd);
CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd);
- CFGBlock *VisitBlockDeclRefExpr(BlockDeclRefExpr* E, bool alwaysAdd);
CFGBlock *VisitBreakStmt(BreakStmt *B);
CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd);
CFGBlock *VisitCaseStmt(CaseStmt *C);
@@ -95,7 +94,9 @@ private:
CFGBlock *VisitCompoundStmt(CompoundStmt *C);
CFGBlock *VisitConditionalOperator(ConditionalOperator *C);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
+ CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); }
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
+ CFGBlock *VisitCXXTryStmt(CXXTryStmt *S) { return NYS(); }
CFGBlock *VisitDeclStmt(DeclStmt *DS);
CFGBlock *VisitDeclSubExpr(Decl* D);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
@@ -292,9 +293,6 @@ tryAgain:
case Stmt::BlockExprClass:
return VisitBlockExpr(cast<BlockExpr>(S), alwaysAdd);
- case Stmt::BlockDeclRefExprClass:
- return VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), alwaysAdd);
-
case Stmt::BreakStmtClass:
return VisitBreakStmt(cast<BreakStmt>(S));
@@ -468,12 +466,6 @@ CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) {
return Block;
}
-CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E,
- bool alwaysAdd) {
- // FIXME
- return NYS();
-}
-
CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
// "break" is a control-flow statement. Thus we stop processing the current
// block.
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index b95f981..9639ad9 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -675,11 +675,9 @@ template <> struct DenseMapInfo<ObjCSummaryKey> {
RHS.getSelector());
}
- static bool isPod() {
- return DenseMapInfo<ObjCInterfaceDecl*>::isPod() &&
- DenseMapInfo<Selector>::isPod();
- }
};
+template <>
+struct isPodLike<ObjCSummaryKey> { static const bool value = true; };
} // end llvm namespace
namespace {
@@ -1984,8 +1982,9 @@ public:
Expr* Ex,
Expr* Receiver,
const RetainSummary& Summ,
+ const MemRegion *Callee,
ExprIterator arg_beg, ExprIterator arg_end,
- ExplodedNode* Pred);
+ ExplodedNode* Pred, const GRState *state);
virtual void EvalCall(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
@@ -1998,7 +1997,8 @@ public:
GRExprEngine& Engine,
GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
- ExplodedNode* Pred);
+ ExplodedNode* Pred,
+ const GRState *state);
bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
@@ -2776,11 +2776,9 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
Expr* Ex,
Expr* Receiver,
const RetainSummary& Summ,
+ const MemRegion *Callee,
ExprIterator arg_beg, ExprIterator arg_end,
- ExplodedNode* Pred) {
-
- // Get the state.
- const GRState *state = Builder.GetState(Pred);
+ ExplodedNode* Pred, const GRState *state) {
// Evaluate the effect of the arguments.
RefVal::Kind hasErr = (RefVal::Kind) 0;
@@ -2788,6 +2786,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
Expr* ErrorExpr = NULL;
SymbolRef ErrorSym = 0;
+ llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate;
+
for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
SVal V = state->getSValAsScalarOrLoc(*I);
SymbolRef Sym = V.getAsLocSymbol();
@@ -2810,16 +2810,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
continue;
// 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
- // to identify conjured symbols by an expression pair: the enclosing
- // expression (the context) and the expression itself. This should
- // disambiguate conjured symbols.
- unsigned Count = Builder.getCurrentBlockCount();
- StoreManager& StoreMgr = Eng.getStateManager().getStoreManager();
-
const MemRegion *R = MR->getRegion();
+
// Are we dealing with an ElementRegion? If the element type is
// a basic integer type (e.g., char, int) and the underying region
// is a variable region then strip off the ElementRegion.
@@ -2843,14 +2835,11 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
}
// FIXME: What about layers of ElementRegions?
}
-
- StoreManager::InvalidatedSymbols IS;
- state = StoreMgr.InvalidateRegion(state, R, *I, Count, &IS);
- for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
- E = IS.end(); I!=E; ++I) {
- // Remove any existing reference-count binding.
- state = state->remove<RefBindings>(*I);
- }
+
+ // Mark this region for invalidation. We batch invalidate regions
+ // below for efficiency.
+ RegionsToInvalidate.push_back(R);
+ continue;
}
else {
// Nuke all other arguments passed by reference.
@@ -2866,6 +2855,36 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
goto tryAgain;
}
}
+
+ // Block calls result in all captured values passed-via-reference to be
+ // invalidated.
+ if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) {
+ RegionsToInvalidate.push_back(BR);
+ }
+
+ // Invalidate regions we designed for invalidation use the batch invalidation
+ // API.
+ if (!RegionsToInvalidate.empty()) {
+ // FIXME: We can have collisions on the conjured symbol if the
+ // expression *I also creates conjured symbols. We probably want
+ // to identify conjured symbols by an expression pair: the enclosing
+ // expression (the context) and the expression itself. This should
+ // disambiguate conjured symbols.
+ unsigned Count = Builder.getCurrentBlockCount();
+ StoreManager& StoreMgr = Eng.getStateManager().getStoreManager();
+
+
+ StoreManager::InvalidatedSymbols IS;
+ state = StoreMgr.InvalidateRegions(state, RegionsToInvalidate.data(),
+ RegionsToInvalidate.data() +
+ RegionsToInvalidate.size(),
+ Ex, Count, &IS);
+ for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
+ E = IS.end(); I!=E; ++I) {
+ // Remove any existing reference-count binding.
+ state = state->remove<RefBindings>(*I);
+ }
+ }
// Evaluate the effect on the message receiver.
if (!ErrorExpr && Receiver) {
@@ -3012,35 +3031,24 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst,
}
assert(Summ);
- EvalSummary(Dst, Eng, Builder, CE, 0, *Summ,
- CE->arg_begin(), CE->arg_end(), Pred);
+ EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(),
+ CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
}
void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
- ExplodedNode* Pred) {
- // FIXME: Since we moved the nil check into a checker, we could get nil
- // receiver here. Need a better way to check such case.
- if (Expr* Receiver = ME->getReceiver()) {
- const GRState *state = Pred->getState();
- DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
- if (!state->Assume(L, true)) {
- Dst.Add(Pred);
- return;
- }
- }
-
+ ExplodedNode* Pred,
+ const GRState *state) {
RetainSummary *Summ =
ME->getReceiver()
- ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred),
- Pred->getLocationContext())
+ ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
: Summaries.getClassMethodSummary(ME);
assert(Summ && "RetainSummary is null");
- EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
- ME->arg_begin(), ME->arg_end(), Pred);
+ EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
+ ME->arg_begin(), ME->arg_end(), Pred, state);
}
namespace {
@@ -3671,7 +3679,24 @@ void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C,
if (I == E)
return;
- state = state->scanReachableSymbols<StopTrackingCallback>(I, E).getState();
+ // FIXME: For now we invalidate the tracking of all symbols passed to blocks
+ // via captured variables, even though captured variables result in a copy
+ // and in implicit increment/decrement of a retain count.
+ llvm::SmallVector<const MemRegion*, 10> Regions;
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ MemRegionManager &MemMgr = C.getValueManager().getRegionManager();
+
+ for ( ; I != E; ++I) {
+ const VarRegion *VR = *I;
+ if (VR->getSuperRegion() == R) {
+ VR = MemMgr.getVarRegion(VR->getDecl(), LC);
+ }
+ Regions.push_back(VR);
+ }
+
+ state =
+ state->scanReachableSymbols<StopTrackingCallback>(Regions.data(),
+ Regions.data() + Regions.size()).getState();
C.addTransition(state);
}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 409292d..521f1be 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -10,10 +10,10 @@ add_clang_library(clangAnalysis
BasicValueFactory.cpp
BugReporter.cpp
BugReporterVisitors.cpp
+ BuiltinFunctionChecker.cpp
CFG.cpp
CFRefCount.cpp
CallAndMessageChecker.cpp
- CallGraph.cpp
CallInliner.cpp
CastToStructChecker.cpp
CheckDeadStores.cpp
@@ -37,8 +37,10 @@ add_clang_library(clangAnalysis
MallocChecker.cpp
ManagerRegistry.cpp
MemRegion.cpp
+ NoReturnFunctionChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
+ OSAtomicChecker.cpp
PathDiagnostic.cpp
PointerArithChecker.cpp
PointerSubChecker.cpp
diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp
index d8dd16c..c287354 100644
--- a/lib/Analysis/CallAndMessageChecker.cpp
+++ b/lib/Analysis/CallAndMessageChecker.cpp
@@ -41,6 +41,7 @@ public:
void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+ bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
private:
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
@@ -148,28 +149,12 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
}
}
}
+}
- // Check if the receiver was nil and then returns a value that may
- // be garbage.
- if (const Expr *Receiver = ME->getReceiver()) {
- DefinedOrUnknownSVal receiverVal =
- cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
-
- const GRState *notNullState, *nullState;
- llvm::tie(notNullState, nullState) = state->Assume(receiverVal);
-
- if (nullState && !notNullState) {
- HandleNilReceiver(C, nullState, ME);
- C.setDoneEvaluating(); // FIXME: eventually remove.
- return;
- }
-
- assert(notNullState);
- state = notNullState;
- }
-
- // Add a state transition if the state has changed.
- C.addTransition(state);
+bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
+ const ObjCMessageExpr *ME) {
+ HandleNilReceiver(C, C.getState(), ME);
+ return true; // Nil receiver is not handled elsewhere.
}
void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
deleted file mode 100644
index c1040f0..0000000
--- a/lib/Analysis/CallGraph.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-//== CallGraph.cpp - Call graph building ------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defined the CallGraph and CGBuilder classes.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/CallGraph.h"
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/StmtVisitor.h"
-
-#include "llvm/Support/GraphWriter.h"
-
-using namespace clang;
-using namespace idx;
-
-namespace {
-class CGBuilder : public StmtVisitor<CGBuilder> {
-
- CallGraph &G;
- FunctionDecl *FD;
-
- Entity CallerEnt;
-
- CallGraphNode *CallerNode;
-
-public:
- CGBuilder(CallGraph &g, FunctionDecl *fd, Entity E, CallGraphNode *N)
- : G(g), FD(fd), CallerEnt(E), CallerNode(N) {}
-
- void VisitStmt(Stmt *S) { VisitChildren(S); }
-
- void VisitCallExpr(CallExpr *CE);
-
- void VisitChildren(Stmt *S) {
- for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
- if (*I)
- static_cast<CGBuilder*>(this)->Visit(*I);
- }
-};
-}
-
-void CGBuilder::VisitCallExpr(CallExpr *CE) {
- if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) {
- Entity Ent = Entity::get(CalleeDecl, G.getProgram());
- CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent);
- CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode);
- }
-}
-
-CallGraph::CallGraph() : Root(0) {
- ExternalCallingNode = getOrInsertFunction(Entity());
-}
-
-CallGraph::~CallGraph() {
- if (!FunctionMap.empty()) {
- for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
- I != E; ++I)
- delete I->second;
- FunctionMap.clear();
- }
-}
-
-void CallGraph::addTU(ASTContext& Ctx) {
- DeclContext *DC = Ctx.getTranslationUnitDecl();
- for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
- I != E; ++I) {
-
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
- if (FD->isThisDeclarationADefinition()) {
- // Set caller's ASTContext.
- Entity Ent = Entity::get(FD, Prog);
- CallGraphNode *Node = getOrInsertFunction(Ent);
- CallerCtx[Node] = &Ctx;
-
- // If this function has external linkage, anything could call it.
- if (FD->isGlobal())
- ExternalCallingNode->addCallee(idx::ASTLocation(), Node);
-
- // Set root node to 'main' function.
- if (FD->getNameAsString() == "main")
- Root = Node;
-
- CGBuilder builder(*this, FD, Ent, Node);
- builder.Visit(FD->getBody());
- }
- }
- }
-}
-
-CallGraphNode *CallGraph::getOrInsertFunction(Entity F) {
- CallGraphNode *&Node = FunctionMap[F];
- if (Node)
- return Node;
-
- return Node = new CallGraphNode(F);
-}
-
-Decl *CallGraph::getDecl(CallGraphNode *Node) {
- // Get the function's context.
- ASTContext *Ctx = CallerCtx[Node];
-
- return Node->getDecl(*Ctx);
-}
-
-void CallGraph::print(llvm::raw_ostream &os) {
- for (iterator I = begin(), E = end(); I != E; ++I) {
- if (I->second->hasCallee()) {
- os << "function: " << I->first.getPrintableName()
- << " calls:\n";
- for (CallGraphNode::iterator CI = I->second->begin(),
- CE = I->second->end(); CI != CE; ++CI) {
- os << " " << CI->second->getName();
- }
- os << '\n';
- }
- }
-}
-
-void CallGraph::dump() {
- print(llvm::errs());
-}
-
-void CallGraph::ViewCallGraph() const {
- llvm::ViewGraph(*this, "CallGraph");
-}
-
-namespace llvm {
-
-template <>
-struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits {
-
- DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
-
- static std::string getNodeLabel(const CallGraphNode *Node,
- const CallGraph &CG) {
- return Node->getName();
-
- }
-
-};
-
-}
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp
index ad63eb4..db9016f 100644
--- a/lib/Analysis/CheckDeadStores.cpp
+++ b/lib/Analysis/CheckDeadStores.cpp
@@ -84,7 +84,8 @@ public:
const LiveVariables::AnalysisDataTy& AD,
const LiveVariables::ValTy& Live) {
- if (VD->hasLocalStorage() && !Live(VD, AD) && !VD->getAttr<UnusedAttr>())
+ if (VD->hasLocalStorage() && !Live(VD, AD) &&
+ !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
Report(VD, dsk, Ex->getSourceRange().getBegin(),
Val->getSourceRange());
}
@@ -185,6 +186,10 @@ public:
if (V->hasLocalStorage())
if (Expr* E = V->getInit()) {
+ // Don't warn on C++ objects (yet) until we can show that their
+ // constructors/destructors don't have side effects.
+ if (isa<CXXConstructExpr>(E))
+ return;
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
// marked 'unused'.
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index e6ab17a..3214101 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -23,6 +23,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
IdentifierInfo *II_gets;
IdentifierInfo *II_getpw;
+ IdentifierInfo *II_mktemp;
enum { num_rands = 9 };
IdentifierInfo *II_rand[num_rands];
IdentifierInfo *II_random;
@@ -31,7 +32,8 @@ class WalkAST : public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br) : BR(br),
- II_gets(0), II_getpw(0), II_rand(), II_random(0), II_setid() {}
+ II_gets(0), II_getpw(0), II_mktemp(0),
+ II_rand(), II_random(0), II_setid() {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -48,6 +50,7 @@ public:
void CheckLoopConditionForFloat(const ForStmt *FS);
void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
+ void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
void CheckUncheckedReturnValue(CallExpr *CE);
@@ -79,6 +82,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (const FunctionDecl *FD = CE->getDirectCallee()) {
CheckCall_gets(CE, FD);
CheckCall_getpw(CE, FD);
+ CheckCall_mktemp(CE, FD);
CheckCall_rand(CE, FD);
CheckCall_random(CE, FD);
}
@@ -288,6 +292,42 @@ void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
}
//===----------------------------------------------------------------------===//
+// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
+// CWE-377: Insecure Temporary File
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
+ if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp"))
+ return;
+
+ const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
+ if(!FPT)
+ return;
+
+ // Verify that the funcion takes a single argument.
+ if (FPT->getNumArgs() != 1)
+ return;
+
+ // Verify that the argument is Pointer Type.
+ const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
+ if (!PT)
+ return;
+
+ // Verify that the argument is a 'char*'.
+ if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+ return;
+
+ // Issue a waring.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
+ "Security",
+ "Call to function 'mktemp' is insecure as it always "
+ "creates or uses insecure temporary file",
+ CE->getLocStart(), &R, 1);
+}
+
+
+//===----------------------------------------------------------------------===//
// Check: Linear congruent random number generators should not be used
// Originally: <rdar://problem/63371000>
// CWE-338: Use of cryptographically weak prng
diff --git a/lib/Analysis/Checker.cpp b/lib/Analysis/Checker.cpp
index 0d907e5..fb9d04d 100644
--- a/lib/Analysis/Checker.cpp
+++ b/lib/Analysis/Checker.cpp
@@ -24,10 +24,10 @@ CheckerContext::~CheckerContext() {
// if we are building sinks or we generated a node and decided to not
// add it as a transition.
if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) {
- if (state && state != B.GetState(Pred)) {
+ if (ST && ST != B.GetState(Pred)) {
static int autoTransitionTag = 0;
B.Tag = &autoTransitionTag;
- addTransition(state);
+ addTransition(ST);
}
else
Dst.Add(Pred);
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 20820d4..51e6a54 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -116,53 +116,91 @@ public:
// Checker worklist routines.
//===----------------------------------------------------------------------===//
-bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
+void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
ExplodedNodeSet &Src, bool isPrevisit) {
if (Checkers.empty()) {
Dst.insert(Src);
- return false;
+ return;
}
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
- bool stopProcessingAfterCurrentChecker = false;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
- {
- ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
- : (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ }
void *tag = I->first;
Checker *checker = I->second;
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI) {
- // FIXME: Halting evaluation of the checkers is something we may
- // not support later. The design is still evolving.
- if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI,
- tag, isPrevisit)) {
- if (CurrSet != &Dst)
- Dst.insert(*CurrSet);
-
- stopProcessingAfterCurrentChecker = true;
- continue;
- }
- assert(stopProcessingAfterCurrentChecker == false &&
- "Inconsistent setting of 'stopProcessingAfterCurrentChecker'");
- }
-
- if (stopProcessingAfterCurrentChecker)
- return true;
-
- // Continue on to the next checker. Update the current NodeSet.
+ NI != NE; ++NI)
+ checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
PrevSet = CurrSet;
}
// Don't autotransition. The CheckerContext objects should do this
// automatically.
- return false;
+}
+
+void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
+ ExplodedNodeSet &Dst,
+ const GRState *state,
+ ExplodedNode *Pred) {
+ bool Evaluated = false;
+ ExplodedNodeSet DstTmp;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ if (checker->GR_EvalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state,
+ tag)) {
+ Evaluated = true;
+ break;
+ } else
+ // The checker didn't evaluate the expr. Restore the Dst.
+ DstTmp.clear();
+ }
+
+ if (Evaluated)
+ Dst.insert(DstTmp);
+ else
+ Dst.insert(Pred);
+}
+
+// CheckerEvalCall returns true if one of the checkers processed the node.
+// This may return void when all call evaluation logic goes to some checker
+// in the future.
+bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred) {
+ bool Evaluated = false;
+ ExplodedNodeSet DstTmp;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ if (checker->GR_EvalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) {
+ Evaluated = true;
+ break;
+ } else
+ // The checker didn't evaluate the expr. Restore the DstTmp set.
+ DstTmp.clear();
+ }
+
+ if (Evaluated)
+ Dst.insert(DstTmp);
+ else
+ Dst.insert(Pred);
+
+ return Evaluated;
}
// FIXME: This is largely copy-paste from CheckerVisit(). Need to
@@ -173,7 +211,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
SVal location, SVal val, bool isPrevisit) {
if (Checkers.empty()) {
- Dst = Src;
+ Dst.insert(Src);
return;
}
@@ -182,10 +220,14 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
- ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
- : (PrevSet == &Tmp) ? &Src : &Tmp;
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ }
- CurrSet->clear();
void *tag = I->first;
Checker *checker = I->second;
@@ -227,6 +269,11 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterUndefinedAssignmentChecker(Eng);
RegisterUndefBranchChecker(Eng);
RegisterUndefResultChecker(Eng);
+
+ // This is not a checker yet.
+ RegisterNoReturnFunctionChecker(Eng);
+ RegisterBuiltinFunctionChecker(Eng);
+ RegisterOSAtomicChecker(Eng);
}
GRExprEngine::GRExprEngine(AnalysisManager &mgr)
@@ -347,8 +394,9 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
Builder->setAuditor(BatchAuditor.get());
// Create the cleaned state.
- SymbolReaper SymReaper(Builder->getBasePredecessor()->getLiveVariables(),
- SymMgr);
+ const ExplodedNode *BasePred = Builder->getBasePredecessor();
+ SymbolReaper SymReaper(BasePred->getLiveVariables(), SymMgr,
+ BasePred->getLocationContext()->getCurrentStackFrame());
CleanedState = AMgr.shouldPurgeDead()
? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper)
: EntryNode->getState();
@@ -371,16 +419,20 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
CleanedState, SymReaper);
if (Checkers.empty())
- Tmp = Tmp2;
+ Tmp.insert(Tmp2);
else {
ExplodedNodeSet Tmp3;
ExplodedNodeSet *SrcSet = &Tmp2;
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
I != E; ++I) {
- ExplodedNodeSet *DstSet = (I+1 == E) ? &Tmp
- : (SrcSet == &Tmp2) ? &Tmp3
- : &Tmp2;
- DstSet->clear();
+ ExplodedNodeSet *DstSet = 0;
+ if (I+1 == E)
+ DstSet = &Tmp;
+ else {
+ DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
+ DstSet->clear();
+ }
+
void *tag = I->first;
Checker *checker = I->second;
for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
@@ -441,6 +493,41 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
}
switch (S->getStmtClass()) {
+ // C++ stuff we don't support yet.
+ case Stmt::CXXMemberCallExprClass:
+ case Stmt::CXXNamedCastExprClass:
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::CXXDynamicCastExprClass:
+ case Stmt::CXXReinterpretCastExprClass:
+ case Stmt::CXXConstCastExprClass:
+ case Stmt::CXXFunctionalCastExprClass:
+ case Stmt::CXXTypeidExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::CXXThisExprClass:
+ case Stmt::CXXThrowExprClass:
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXZeroInitValueExprClass:
+ case Stmt::CXXNewExprClass:
+ case Stmt::CXXDeleteExprClass:
+ case Stmt::CXXPseudoDestructorExprClass:
+ case Stmt::UnresolvedLookupExprClass:
+ case Stmt::UnaryTypeTraitExprClass:
+ case Stmt::DependentScopeDeclRefExprClass:
+ case Stmt::CXXConstructExprClass:
+ case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXExprWithTemporariesClass:
+ case Stmt::CXXTemporaryObjectExprClass:
+ case Stmt::CXXUnresolvedConstructExprClass:
+ case Stmt::CXXDependentScopeMemberExprClass:
+ case Stmt::UnresolvedMemberExprClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::CXXTryStmtClass: {
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ Builder->BuildSinks = true;
+ MakeNode(Dst, S, Pred, GetState(Pred));
+ break;
+ }
default:
// Cases we intentionally have "default" handle:
@@ -456,6 +543,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::AsmStmtClass:
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
break;
+
+ case Stmt::BlockDeclRefExprClass:
+ VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), Pred, Dst, false);
+ break;
case Stmt::BlockExprClass:
VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
@@ -627,6 +718,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
return;
+ case Stmt::BlockDeclRefExprClass:
+ VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
+ return;
+
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
return;
@@ -1118,9 +1213,20 @@ void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred,
void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst, bool asLValue) {
+ VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue);
+}
+
+void GRExprEngine::VisitBlockDeclRefExpr(BlockDeclRefExpr *Ex,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst, bool asLValue) {
+ VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue);
+}
+
+void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst, bool asLValue) {
const GRState *state = GetState(Pred);
- const NamedDecl *D = Ex->getDecl();
if (const VarDecl* VD = dyn_cast<VarDecl>(D)) {
@@ -1354,10 +1460,14 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
- ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
- : (PrevSet == &Tmp) ? &Src : &Tmp;
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ }
- CurrSet->clear();
void *tag = I->first;
Checker *checker = I->second;
@@ -1376,232 +1486,8 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
}
//===----------------------------------------------------------------------===//
-// Transfer function: OSAtomics.
-//
-// FIXME: Eventually refactor into a more "plugin" infrastructure.
-//===----------------------------------------------------------------------===//
-
-// Mac OS X:
-// http://developer.apple.com/documentation/Darwin/Reference/Manpages/man3
-// atomic.3.html
-//
-static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst,
- GRExprEngine& Engine,
- GRStmtNodeBuilder& Builder,
- CallExpr* CE, ExplodedNode* Pred) {
-
- // Not enough arguments to match OSAtomicCompareAndSwap?
- if (CE->getNumArgs() != 3)
- return false;
-
- ASTContext &C = Engine.getContext();
- Expr *oldValueExpr = CE->getArg(0);
- QualType oldValueType = C.getCanonicalType(oldValueExpr->getType());
-
- Expr *newValueExpr = CE->getArg(1);
- QualType newValueType = C.getCanonicalType(newValueExpr->getType());
-
- // Do the types of 'oldValue' and 'newValue' match?
- if (oldValueType != newValueType)
- return false;
-
- Expr *theValueExpr = CE->getArg(2);
- const PointerType *theValueType =
- theValueExpr->getType()->getAs<PointerType>();
-
- // theValueType not a pointer?
- if (!theValueType)
- return false;
-
- QualType theValueTypePointee =
- C.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
-
- // The pointee must match newValueType and oldValueType.
- if (theValueTypePointee != newValueType)
- return false;
-
- static unsigned magic_load = 0;
- static unsigned magic_store = 0;
-
- const void *OSAtomicLoadTag = &magic_load;
- const void *OSAtomicStoreTag = &magic_store;
-
- // Load 'theValue'.
- const GRState *state = Pred->getState();
- ExplodedNodeSet Tmp;
- SVal location = state->getSVal(theValueExpr);
- // Here we should use the value type of the region as the load type.
- const MemRegion *R = location.getAsRegion();
- QualType LoadTy;
- if (R)
- LoadTy = cast<TypedRegion>(R)->getValueType(C);
- Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag,
- LoadTy);
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
- I != E; ++I) {
-
- ExplodedNode *N = *I;
- const GRState *stateLoad = N->getState();
- SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
- SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
-
- // FIXME: Issue an error.
- if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
- return false;
- }
-
- DefinedOrUnknownSVal theValueVal =
- cast<DefinedOrUnknownSVal>(theValueVal_untested);
- DefinedOrUnknownSVal oldValueVal =
- cast<DefinedOrUnknownSVal>(oldValueVal_untested);
-
- SValuator &SVator = Engine.getSValuator();
-
- // Perform the comparison.
- DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad, theValueVal,
- oldValueVal);
-
- const GRState *stateEqual = stateLoad->Assume(Cmp, true);
-
- // Were they equal?
- if (stateEqual) {
- // Perform the store.
- ExplodedNodeSet TmpStore;
- SVal val = stateEqual->getSVal(newValueExpr);
-
- // Handle implicit value casts.
- if (const TypedRegion *R =
- dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
- llvm::tie(state, val) = SVator.EvalCast(val, state, R->getValueType(C),
- newValueExpr->getType());
- }
-
- Engine.EvalStore(TmpStore, NULL, theValueExpr, N, stateEqual, location,
- val, OSAtomicStoreTag);
-
- // Now bind the result of the comparison.
- for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
- E2 = TmpStore.end(); I2 != E2; ++I2) {
- ExplodedNode *predNew = *I2;
- const GRState *stateNew = predNew->getState();
- SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
- Engine.MakeNode(Dst, CE, predNew, stateNew->BindExpr(CE, Res));
- }
- }
-
- // Were they not equal?
- if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
- SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
- Engine.MakeNode(Dst, CE, N, stateNotEqual->BindExpr(CE, Res));
- }
- }
-
- return true;
-}
-
-static bool EvalOSAtomic(ExplodedNodeSet& Dst,
- GRExprEngine& Engine,
- GRStmtNodeBuilder& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode* Pred) {
- const FunctionDecl* FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- const char *FName = FD->getNameAsCString();
-
- // Check for compare and swap.
- if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 ||
- strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0)
- return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, Pred);
-
- // FIXME: Other atomics.
- return false;
-}
-
-//===----------------------------------------------------------------------===//
// Transfer function: Function calls.
//===----------------------------------------------------------------------===//
-static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE,
- const GRState *state,
- GRStmtNodeBuilder *Builder) {
- if (!FD)
- return;
-
- if (FD->getAttr<NoReturnAttr>() ||
- FD->getAttr<AnalyzerNoReturnAttr>())
- Builder->BuildSinks = true;
- else {
- // HACK: Some functions are not marked noreturn, and don't return.
- // Here are a few hardwired ones. If this takes too long, we can
- // potentially cache these results.
- using llvm::StringRef;
- bool BuildSinks
- = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName()))
- .Case("exit", true)
- .Case("panic", true)
- .Case("error", true)
- .Case("Assert", true)
- // FIXME: This is just a wrapper around throwing an exception.
- // Eventually inter-procedural analysis should handle this easily.
- .Case("ziperr", true)
- .Case("assfail", true)
- .Case("db_error", true)
- .Case("__assert", true)
- .Case("__assert_rtn", true)
- .Case("__assert_fail", true)
- .Case("dtrace_assfail", true)
- .Case("yy_fatal_error", true)
- .Case("_XCAssertionFailureHandler", true)
- .Case("_DTAssertionFailureHandler", true)
- .Case("_TSAssertionFailureHandler", true)
- .Default(false);
-
- if (BuildSinks)
- Builder->BuildSinks = true;
- }
-}
-
-bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- if (!FD)
- return false;
-
- unsigned id = FD->getBuiltinID();
- if (!id)
- return false;
-
- const GRState *state = Pred->getState();
-
- switch (id) {
- case Builtin::BI__builtin_expect: {
- // For __builtin_expect, just return the value of the subexpression.
- assert (CE->arg_begin() != CE->arg_end());
- SVal X = state->getSVal(*(CE->arg_begin()));
- MakeNode(Dst, CE, Pred, state->BindExpr(CE, X));
- return true;
- }
-
- case Builtin::BI__builtin_alloca: {
- // FIXME: Refactor into StoreManager itself?
- MemRegionManager& RM = getStateManager().getRegionManager();
- const MemRegion* R =
- RM.getAllocaRegion(CE, Builder->getCurrentBlockCount());
-
- // Set the extent of the region in bytes. This enables us to use the
- // SVal of the argument directly. If we save the extent in bits, we
- // cannot represent values like symbol*8.
- SVal Extent = state->getSVal(*(CE->arg_begin()));
- state = getStoreManager().setExtent(state, R, Extent);
- MakeNode(Dst, CE, Pred, state->BindExpr(CE, loc::MemRegionVal(R)));
- return true;
- }
- }
-
- return false;
-}
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
@@ -1659,6 +1545,8 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
}
// Finally, evaluate the function call.
+ ExplodedNodeSet DstTmp3;
+
for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
DI != DE; ++DI) {
@@ -1667,39 +1555,39 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
-
- // Check for the "noreturn" attribute.
-
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- const FunctionDecl* FD = L.getAsFunctionDecl();
-
- MarkNoReturnFunction(FD, CE, state, Builder);
-
- // Evaluate the call.
- if (EvalBuiltinFunction(FD, CE, *DI, Dst))
- continue;
-
- // Dispatch to the plug-in transfer function.
- SaveOr OldHasGen(Builder->HasGeneratedNode);
- Pred = *DI;
+ ExplodedNodeSet DstChecker;
- // Dispatch to transfer function logic to handle the call itself.
- // FIXME: Allow us to chain together transfer functions.
- assert(Builder && "GRStmtNodeBuilder must be defined.");
- ExplodedNodeSet DstTmp;
+ // If the callee is processed by a checker, skip the rest logic.
+ if (CheckerEvalCall(CE, DstChecker, *DI))
+ DstTmp3.insert(DstChecker);
+ else {
+ for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
+ DE_Checker = DstChecker.end();
+ DI_Checker != DE_Checker; ++DI_Checker) {
+
+ // Dispatch to the plug-in transfer function.
+ unsigned OldSize = DstTmp3.size();
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ Pred = *DI_Checker;
+
+ // Dispatch to transfer function logic to handle the call itself.
+ // FIXME: Allow us to chain together transfer functions.
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
- if (!EvalOSAtomic(DstTmp, *this, *Builder, CE, L, Pred))
- getTF().EvalCall(DstTmp, *this, *Builder, CE, L, Pred);
+ getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred);
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder->BuildSinks && DstTmp.empty() &&
- !Builder->HasGeneratedNode)
- MakeNode(DstTmp, CE, Pred, state);
-
- // Perform the post-condition check of the CallExpr.
- CheckerVisit(CE, Dst, DstTmp, false);
+ // Handle the case where no nodes where generated. Auto-generate that
+ // contains the updated state if we aren't generating sinks.
+ if (!Builder->BuildSinks && DstTmp3.size() == OldSize &&
+ !Builder->HasGeneratedNode)
+ MakeNode(DstTmp3, CE, Pred, state);
+ }
+ }
}
+
+ // Perform the post-condition check of the CallExpr.
+ CheckerVisit(CE, Dst, DstTmp3, false);
}
//===----------------------------------------------------------------------===//
@@ -1922,10 +1810,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
ExplodedNodeSet Src, DstTmp;
Src.Add(Pred);
- if (CheckerVisit(ME, DstTmp, Src, true)) {
- Dst.insert(DstTmp);
- return;
- }
+ CheckerVisit(ME, DstTmp, Src, true);
unsigned size = Dst.size();
@@ -1934,10 +1819,38 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
Pred = *DI;
bool RaisesException = false;
- if (ME->getReceiver()) {
+ if (const Expr *Receiver = ME->getReceiver()) {
+ const GRState *state = Pred->getState();
+
+ // Bifurcate the state into nil and non-nil ones.
+ DefinedOrUnknownSVal receiverVal =
+ cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
+
+ const GRState *notNilState, *nilState;
+ llvm::tie(notNilState, nilState) = state->Assume(receiverVal);
+
+ // There are three cases: can be nil or non-nil, must be nil, must be
+ // non-nil. We handle must be nil, and merge the rest two into non-nil.
+ if (nilState && !notNilState) {
+ CheckerEvalNilReceiver(ME, Dst, nilState, Pred);
+ return;
+ }
+
+ assert(notNilState);
+
// Check if the "raise" message was sent.
if (ME->getSelector() == RaiseSel)
RaisesException = true;
+
+ // Check if we raise an exception. For now treat these as sinks.
+ // Eventually we will want to handle exceptions properly.
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ if (RaisesException)
+ Builder->BuildSinks = true;
+
+ // Dispatch to plug-in transfer function.
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ EvalObjCMessageExpr(Dst, ME, Pred, notNilState);
}
else {
@@ -1984,17 +1897,17 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
RaisesException = true; break;
}
}
- }
- // Check if we raise an exception. For now treat these as sinks. Eventually
- // we will want to handle exceptions properly.
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- if (RaisesException)
- Builder->BuildSinks = true;
+ // Check if we raise an exception. For now treat these as sinks.
+ // Eventually we will want to handle exceptions properly.
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ if (RaisesException)
+ Builder->BuildSinks = true;
- // Dispatch to plug-in transfer function.
- SaveOr OldHasGen(Builder->HasGeneratedNode);
- EvalObjCMessageExpr(Dst, ME, Pred);
+ // Dispatch to plug-in transfer function.
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred));
+ }
}
// Handle the case where no nodes where generated. Auto-generate that
@@ -2052,10 +1965,12 @@ void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL,
for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
const GRState* state = GetState(*I);
SVal ILV = state->getSVal(ILE);
- state = state->bindCompoundLiteral(CL, ILV);
+ const LocationContext *LC = (*I)->getLocationContext();
+ state = state->bindCompoundLiteral(CL, LC, ILV);
- if (asLValue)
- MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL)));
+ if (asLValue) {
+ MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC)));
+ }
else
MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV));
}
diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h
index 5b7a757..e2354ed 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.h
+++ b/lib/Analysis/GRExprEngineInternalChecks.h
@@ -37,5 +37,8 @@ void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
void RegisterUndefBranchChecker(GRExprEngine &Eng);
void RegisterUndefResultChecker(GRExprEngine &Eng);
+void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
+void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
+void RegisterOSAtomicChecker(GRExprEngine &Eng);
} // end clang namespace
#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index a56859d..7415fa5 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -312,10 +312,10 @@ bool GRState::scanReachableSymbols(const SVal *I, const SVal *E,
SymbolVisitor &visitor) const {
ScanReachableSymbols S(this, visitor);
for ( ; I != E; ++I) {
- if (S.scan(*I))
- return true;
+ if (!S.scan(*I))
+ return false;
}
- return false;
+ return true;
}
bool GRState::scanReachableSymbols(const MemRegion * const *I,
@@ -323,10 +323,10 @@ bool GRState::scanReachableSymbols(const MemRegion * const *I,
SymbolVisitor &visitor) const {
ScanReachableSymbols S(this, visitor);
for ( ; I != E; ++I) {
- if (S.scan(*I))
- return true;
+ if (!S.scan(*I))
+ return false;
}
- return false;
+ return true;
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
index 204c7b3..2ed070a 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Analysis/MallocChecker.cpp
@@ -22,10 +22,11 @@ using namespace clang;
namespace {
-struct RefState {
+class RefState {
enum Kind { Allocated, Released, Escaped } K;
const Stmt *S;
+public:
RefState(Kind k, const Stmt *s) : K(k), S(s) {}
bool isAllocated() const { return K == Allocated; }
@@ -51,19 +52,25 @@ class RegionState {};
class MallocChecker : public CheckerVisitor<MallocChecker> {
BuiltinBug *BT_DoubleFree;
BuiltinBug *BT_Leak;
- IdentifierInfo *II_malloc;
- IdentifierInfo *II_free;
+ IdentifierInfo *II_malloc, *II_free, *II_realloc;
public:
- MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {}
+ MallocChecker()
+ : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0), II_realloc(0) {}
static void *getTag();
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
private:
void MallocMem(CheckerContext &C, const CallExpr *CE);
+ const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+ const GRState *state);
void FreeMem(CheckerContext &C, const CallExpr *CE);
+ const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
+ const GRState *state);
+
+ void ReallocMem(CheckerContext &C, const CallExpr *CE);
};
} // end anonymous namespace
@@ -84,39 +91,71 @@ void *MallocChecker::getTag() {
return &x;
}
-void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
- const FunctionDecl *FD = CE->getDirectCallee();
+bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+
+ const FunctionDecl *FD = L.getAsFunctionDecl();
if (!FD)
- return;
+ return false;
ASTContext &Ctx = C.getASTContext();
if (!II_malloc)
II_malloc = &Ctx.Idents.get("malloc");
if (!II_free)
II_free = &Ctx.Idents.get("free");
+ if (!II_realloc)
+ II_realloc = &Ctx.Idents.get("realloc");
if (FD->getIdentifier() == II_malloc) {
MallocMem(C, CE);
- return;
+ return true;
}
if (FD->getIdentifier() == II_free) {
FreeMem(C, CE);
- return;
+ return true;
+ }
+
+ if (FD->getIdentifier() == II_realloc) {
+ ReallocMem(C, CE);
+ return true;
}
+
+ return false;
}
void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- SVal CallVal = state->getSVal(CE);
- SymbolRef Sym = CallVal.getAsLocSymbol();
+ const GRState *state = MallocMemAux(C, CE, C.getState());
+ C.addTransition(state);
+}
+
+const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
+ const CallExpr *CE,
+ const GRState *state) {
+ unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ ValueManager &ValMgr = C.getValueManager();
+
+ SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
+
+ state = state->BindExpr(CE, RetVal);
+
+ SymbolRef Sym = RetVal.getAsLocSymbol();
assert(Sym);
// Set the symbol's state to Allocated.
- C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE)));
+ return state->set<RegionState>(Sym, RefState::getAllocated(CE));
}
void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
+ const GRState *state = FreeMemAux(C, CE, C.getState());
+
+ if (state)
+ C.addTransition(state);
+}
+
+const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
+ const GRState *state) {
SVal ArgVal = state->getSVal(CE->getArg(0));
SymbolRef Sym = ArgVal.getAsLocSymbol();
assert(Sym);
@@ -136,13 +175,59 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
BT_DoubleFree->getDescription(), N);
C.EmitReport(R);
}
- return;
+ return NULL;
}
// Normal free.
- const GRState *FreedState
- = state->set<RegionState>(Sym, RefState::getReleased(CE));
- C.addTransition(FreedState);
+ return state->set<RegionState>(Sym, RefState::getReleased(CE));
+}
+
+void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Arg0 = CE->getArg(0);
+ DefinedOrUnknownSVal Arg0Val=cast<DefinedOrUnknownSVal>(state->getSVal(Arg0));
+
+ ValueManager &ValMgr = C.getValueManager();
+ SValuator &SVator = C.getSValuator();
+
+ DefinedOrUnknownSVal PtrEQ = SVator.EvalEQ(state, Arg0Val, ValMgr.makeNull());
+
+ // If the ptr is NULL, the call is equivalent to malloc(size).
+ if (const GRState *stateEqual = state->Assume(PtrEQ, true)) {
+ // Hack: set the NULL symbolic region to released to suppress false warning.
+ // In the future we should add more states for allocated regions, e.g.,
+ // CheckedNull, CheckedNonNull.
+
+ SymbolRef Sym = Arg0Val.getAsLocSymbol();
+ if (Sym)
+ stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
+
+ const GRState *stateMalloc = MallocMemAux(C, CE, stateEqual);
+ C.addTransition(stateMalloc);
+ }
+
+ if (const GRState *stateNotEqual = state->Assume(PtrEQ, false)) {
+ const Expr *Arg1 = CE->getArg(1);
+ DefinedOrUnknownSVal Arg1Val =
+ cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
+ DefinedOrUnknownSVal SizeZero = SVator.EvalEQ(stateNotEqual, Arg1Val,
+ ValMgr.makeIntValWithPtrWidth(0, false));
+
+ if (const GRState *stateSizeZero = stateNotEqual->Assume(SizeZero, true)) {
+ const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero);
+ if (stateFree)
+ C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+ }
+
+ if (const GRState *stateSizeNotZero=stateNotEqual->Assume(SizeZero,false)) {
+ const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero);
+ if (stateFree) {
+ // FIXME: We should copy the content of the original buffer.
+ const GRState *stateRealloc = MallocMemAux(C, CE, stateFree);
+ C.addTransition(stateRealloc);
+ }
+ }
+ }
}
void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index af8bd16..bc3a5b7 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -22,6 +22,110 @@
using namespace clang;
//===----------------------------------------------------------------------===//
+// MemRegion Construction.
+//===----------------------------------------------------------------------===//
+
+template<typename RegionTy> struct MemRegionManagerTrait;
+
+template <typename RegionTy, typename A1>
+RegionTy* MemRegionManager::getRegion(const A1 a1) {
+
+ const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
+ MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1);
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename A1>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1,
+ const MemRegion *superRegion) {
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename A1, typename A2>
+RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) {
+
+ const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
+ MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2);
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, a2, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename A1, typename A2>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2,
+ const MemRegion *superRegion) {
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, a2, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename A1, typename A2, typename A3>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3,
+ const MemRegion *superRegion) {
+
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion);
+ void* InsertPos;
+ RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, a2, a3, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+//===----------------------------------------------------------------------===//
// Object destruction.
//===----------------------------------------------------------------------===//
@@ -61,10 +165,24 @@ MemRegionManager* SubRegion::getMemRegionManager() const {
} while (1);
}
+const StackFrameContext *VarRegion::getStackFrame() const {
+ const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
+ return SSR ? SSR->getStackFrame() : NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling.
+//===----------------------------------------------------------------------===//
+
void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned)getKind());
}
+void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger((unsigned)getKind());
+ ID.AddPointer(getStackFrame());
+}
+
void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const StringLiteral* Str,
const MemRegion* superRegion) {
@@ -109,7 +227,7 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- VarRegion::ProfileRegion(ID, getDecl(), LC, superRegion);
+ VarRegion::ProfileRegion(ID, getDecl(), superRegion);
}
void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
@@ -148,27 +266,29 @@ void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const BlockDecl *BD, CanQualType,
- const MemRegion*) {
+ const BlockDecl *BD, CanQualType,
+ const AnalysisContext *AC,
+ const MemRegion*) {
ID.AddInteger(MemRegion::BlockTextRegionKind);
ID.AddPointer(BD);
}
void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion);
+ BlockTextRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
}
void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const BlockTextRegion *BC,
const LocationContext *LC,
- const MemRegion *) {
+ const MemRegion *sReg) {
ID.AddInteger(MemRegion::BlockDataRegionKind);
ID.AddPointer(BC);
ID.AddPointer(LC);
+ ID.AddPointer(sReg);
}
void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockDataRegion::ProfileRegion(ID, BC, LC, NULL);
+ BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion());
}
//===----------------------------------------------------------------------===//
@@ -249,36 +369,58 @@ void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const {
// MemRegionManager methods.
//===----------------------------------------------------------------------===//
-MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
+template <typename REG>
+const REG *MemRegionManager::LazyAllocate(REG*& region) {
if (!region) {
- region = (MemSpaceRegion*) A.Allocate<MemSpaceRegion>();
- new (region) MemSpaceRegion(this);
+ region = (REG*) A.Allocate<REG>();
+ new (region) REG(this);
}
return region;
}
-MemSpaceRegion* MemRegionManager::getStackRegion() {
- return LazyAllocate(stack);
+template <typename REG, typename ARG>
+const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
+ if (!region) {
+ region = (REG*) A.Allocate<REG>();
+ new (region) REG(this, a);
+ }
+
+ return region;
}
-MemSpaceRegion* MemRegionManager::getStackArgumentsRegion() {
- return LazyAllocate(stackArguments);
+const StackLocalsSpaceRegion*
+MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
+ assert(STC);
+ if (STC == cachedStackLocalsFrame)
+ return cachedStackLocalsRegion;
+ cachedStackLocalsFrame = STC;
+ return LazyAllocate(cachedStackLocalsRegion, STC);
}
-MemSpaceRegion* MemRegionManager::getGlobalsRegion() {
+const StackArgumentsSpaceRegion *
+MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
+ assert(STC);
+ if (STC == cachedStackArgumentsFrame)
+ return cachedStackArgumentsRegion;
+
+ cachedStackArgumentsFrame = STC;
+ return LazyAllocate(cachedStackArgumentsRegion, STC);
+}
+
+const GlobalsSpaceRegion *MemRegionManager::getGlobalsRegion() {
return LazyAllocate(globals);
}
-MemSpaceRegion* MemRegionManager::getHeapRegion() {
+const HeapSpaceRegion *MemRegionManager::getHeapRegion() {
return LazyAllocate(heap);
}
-MemSpaceRegion* MemRegionManager::getUnknownRegion() {
+const MemSpaceRegion *MemRegionManager::getUnknownRegion() {
return LazyAllocate(unknown);
}
-MemSpaceRegion* MemRegionManager::getCodeRegion() {
+const MemSpaceRegion *MemRegionManager::getCodeRegion() {
return LazyAllocate(code);
}
@@ -286,40 +428,79 @@ MemSpaceRegion* MemRegionManager::getCodeRegion() {
// Constructing regions.
//===----------------------------------------------------------------------===//
-StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
- return getRegion<StringRegion>(Str);
+const StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
+ return getSubRegion<StringRegion>(Str, getGlobalsRegion());
}
-VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
- const LocationContext *LC) {
+const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
+ const LocationContext *LC) {
+ const MemRegion *sReg = 0;
- // FIXME: Once we implement scope handling, we will need to properly lookup
- // 'D' to the proper LocationContext. For now, just strip down to the
- // StackFrame.
- while (!isa<StackFrameContext>(LC))
- LC = LC->getParent();
+ if (D->hasLocalStorage()) {
+ // FIXME: Once we implement scope handling, we will need to properly lookup
+ // 'D' to the proper LocationContext.
+ const DeclContext *DC = D->getDeclContext();
+ const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC);
- return getRegion<VarRegion>(D, LC);
+ if (!STC)
+ sReg = getUnknownRegion();
+ else {
+ sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)
+ ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC))
+ : static_cast<const MemRegion*>(getStackLocalsRegion(STC));
+ }
+ }
+ else {
+ sReg = getGlobalsRegion();
+ }
+
+ return getSubRegion<VarRegion>(D, sReg);
}
-BlockDataRegion *MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
- const LocationContext *LC)
-{
- // FIXME: Once we implement scope handling, we will need to properly lookup
- // 'D' to the proper LocationContext. For now, just strip down to the
- // StackFrame.
- while (!isa<StackFrameContext>(LC))
- LC = LC->getParent();
+const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
+ const MemRegion *superR) {
+ return getSubRegion<VarRegion>(D, superR);
+}
+
+const BlockDataRegion *
+MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
+ const LocationContext *LC) {
+ const MemRegion *sReg = 0;
- return getSubRegion<BlockDataRegion>(BC, LC, getStackRegion());
+ if (LC) {
+ // FIXME: Once we implement scope handling, we want the parent region
+ // to be the scope.
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ sReg = getStackLocalsRegion(STC);
+ }
+ else {
+ // We allow 'LC' to be NULL for cases where want BlockDataRegions
+ // without context-sensitivity.
+ sReg = getUnknownRegion();
+ }
+
+ return getSubRegion<BlockDataRegion>(BC, LC, sReg);
}
-CompoundLiteralRegion*
-MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
- return getRegion<CompoundLiteralRegion>(CL);
+const CompoundLiteralRegion*
+MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
+ const LocationContext *LC) {
+
+ const MemRegion *sReg = 0;
+
+ if (CL->isFileScope())
+ sReg = getGlobalsRegion();
+ else {
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ sReg = getStackLocalsRegion(STC);
+ }
+
+ return getSubRegion<CompoundLiteralRegion>(CL, sReg);
}
-ElementRegion*
+const ElementRegion*
MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
const MemRegion* superRegion,
ASTContext& Ctx){
@@ -342,41 +523,47 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
return R;
}
-FunctionTextRegion *
+const FunctionTextRegion *
MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
- return getRegion<FunctionTextRegion>(FD);
+ return getSubRegion<FunctionTextRegion>(FD, getCodeRegion());
}
-BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD,
- CanQualType locTy) {
- return getRegion<BlockTextRegion>(BD, locTy);
+const BlockTextRegion *
+MemRegionManager::getBlockTextRegion(const BlockDecl *BD, CanQualType locTy,
+ AnalysisContext *AC) {
+ return getSubRegion<BlockTextRegion>(BD, locTy, AC, getCodeRegion());
}
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
-SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
- return getRegion<SymbolicRegion>(sym);
+const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
+ return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
}
-FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
- const MemRegion* superRegion) {
+const FieldRegion *
+MemRegionManager::getFieldRegion(const FieldDecl* d,
+ const MemRegion* superRegion){
return getSubRegion<FieldRegion>(d, superRegion);
}
-ObjCIvarRegion*
+const ObjCIvarRegion*
MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
const MemRegion* superRegion) {
return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
-ObjCObjectRegion*
+const ObjCObjectRegion*
MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d,
const MemRegion* superRegion) {
return getSubRegion<ObjCObjectRegion>(d, superRegion);
}
-AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) {
- return getRegion<AllocaRegion>(E, cnt);
+const AllocaRegion*
+MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt,
+ const LocationContext *LC) {
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
}
const MemSpaceRegion *MemRegion::getMemorySpace() const {
@@ -392,52 +579,30 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const {
}
bool MemRegion::hasStackStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace()) {
- MemRegionManager *Mgr = getMemRegionManager();
- return MS == Mgr->getStackRegion() || MS == Mgr->getStackArgumentsRegion();
- }
-
- return false;
+ return isa<StackSpaceRegion>(getMemorySpace());
}
bool MemRegion::hasHeapStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace())
- return MS == getMemRegionManager()->getHeapRegion();
-
- return false;
+ return isa<HeapSpaceRegion>(getMemorySpace());
}
bool MemRegion::hasHeapOrStackStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace()) {
- MemRegionManager *Mgr = getMemRegionManager();
- return MS == Mgr->getHeapRegion()
- || MS == Mgr->getStackRegion()
- || MS == Mgr->getStackArgumentsRegion();
- }
- return false;
+ const MemSpaceRegion *MS = getMemorySpace();
+ return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS);
}
bool MemRegion::hasGlobalsStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace())
- return MS == getMemRegionManager()->getGlobalsRegion();
-
- return false;
+ return isa<GlobalsSpaceRegion>(getMemorySpace());
}
bool MemRegion::hasParametersStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace())
- return MS == getMemRegionManager()->getStackArgumentsRegion();
-
- return false;
+ return isa<StackArgumentsSpaceRegion>(getMemorySpace());
}
bool MemRegion::hasGlobalsOrParametersStorage() const {
- if (const MemSpaceRegion *MS = getMemorySpace()) {
- MemRegionManager *Mgr = getMemRegionManager();
- return MS == Mgr->getGlobalsRegion()
- || MS == Mgr->getStackArgumentsRegion();
- }
- return false;
+ const MemSpaceRegion *MS = getMemorySpace();
+ return isa<StackArgumentsSpaceRegion>(MS) ||
+ isa<GlobalsSpaceRegion>(MS);
}
// getBaseRegion strips away all elements and fields, and get the base region
@@ -543,7 +708,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
if (ReferencedVars)
return;
- AnalysisContext *AC = LC->getAnalysisContext();
+ AnalysisContext *AC = getCodeRegion()->getAnalysisContext();
AnalysisContext::referenced_decls_iterator I, E;
llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl());
@@ -558,10 +723,25 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
typedef BumpVector<const MemRegion*> VarVec;
VarVec *BV = (VarVec*) A.Allocate<VarVec>();
- new (BV) VarVec(BC, (E - I) / sizeof(*I));
+ new (BV) VarVec(BC, E - I);
- for ( ; I != E; ++I)
- BV->push_back(MemMgr.getVarRegion(*I, LC), BC);
+ for ( ; I != E; ++I) {
+ const VarDecl *VD = *I;
+ const VarRegion *VR = 0;
+
+ if (!VD->getAttr<BlocksAttr>())
+ VR = MemMgr.getVarRegion(VD, this);
+ else {
+ if (LC)
+ VR = MemMgr.getVarRegion(VD, LC);
+ else {
+ VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+ }
+ }
+
+ assert(VR);
+ BV->push_back(VR, BC);
+ }
ReferencedVars = BV;
}
@@ -573,7 +753,8 @@ BlockDataRegion::referenced_vars_begin() const {
BumpVector<const MemRegion*> *Vec =
static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
- return Vec == (void*) 0x1 ? NULL : Vec->begin();
+ return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ?
+ NULL : Vec->begin());
}
BlockDataRegion::referenced_vars_iterator
@@ -583,5 +764,6 @@ BlockDataRegion::referenced_vars_end() const {
BumpVector<const MemRegion*> *Vec =
static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
- return Vec == (void*) 0x1 ? NULL : Vec->end();
+ return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ?
+ NULL : Vec->end());
}
diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Analysis/NoReturnFunctionChecker.cpp
new file mode 100644
index 0000000..6806273
--- /dev/null
+++ b/lib/Analysis/NoReturnFunctionChecker.cpp
@@ -0,0 +1,80 @@
+//=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NoReturnFunctionChecker, which evaluates functions that do not
+// return to the caller.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+
+namespace {
+
+class NoReturnFunctionChecker : public Checker {
+public:
+ static void *getTag() { static int tag = 0; return &tag; }
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new NoReturnFunctionChecker());
+}
+
+bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ bool BuildSinks = false;
+
+ if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>())
+ BuildSinks = true;
+ else {
+ // HACK: Some functions are not marked noreturn, and don't return.
+ // Here are a few hardwired ones. If this takes too long, we can
+ // potentially cache these results.
+ using llvm::StringRef;
+ BuildSinks
+ = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName()))
+ .Case("exit", true)
+ .Case("panic", true)
+ .Case("error", true)
+ .Case("Assert", true)
+ // FIXME: This is just a wrapper around throwing an exception.
+ // Eventually inter-procedural analysis should handle this easily.
+ .Case("ziperr", true)
+ .Case("assfail", true)
+ .Case("db_error", true)
+ .Case("__assert", true)
+ .Case("__assert_rtn", true)
+ .Case("__assert_fail", true)
+ .Case("dtrace_assfail", true)
+ .Case("yy_fatal_error", true)
+ .Case("_XCAssertionFailureHandler", true)
+ .Case("_DTAssertionFailureHandler", true)
+ .Case("_TSAssertionFailureHandler", true)
+ .Default(false);
+ }
+
+ if (!BuildSinks)
+ return false;
+
+ C.GenerateSink(CE);
+ return true;
+}
diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp
new file mode 100644
index 0000000..5a89345
--- /dev/null
+++ b/lib/Analysis/OSAtomicChecker.cpp
@@ -0,0 +1,196 @@
+//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker evaluates OSAtomic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Basic/Builtins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+
+namespace {
+
+class OSAtomicChecker : public Checker {
+public:
+ static void *getTag() { static int tag = 0; return &tag; }
+ virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+
+private:
+ bool EvalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void clang::RegisterOSAtomicChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new OSAtomicChecker());
+}
+
+bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+
+ const FunctionDecl* FD = L.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ const char *FName = FD->getNameAsCString();
+
+ // Check for compare and swap.
+ if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 ||
+ strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0)
+ return EvalOSAtomicCompareAndSwap(C, CE);
+
+ // FIXME: Other atomics.
+ return false;
+}
+
+bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
+ const CallExpr *CE) {
+ // Not enough arguments to match OSAtomicCompareAndSwap?
+ if (CE->getNumArgs() != 3)
+ return false;
+
+ ASTContext &Ctx = C.getASTContext();
+ const Expr *oldValueExpr = CE->getArg(0);
+ QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
+
+ const Expr *newValueExpr = CE->getArg(1);
+ QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
+
+ // Do the types of 'oldValue' and 'newValue' match?
+ if (oldValueType != newValueType)
+ return false;
+
+ const Expr *theValueExpr = CE->getArg(2);
+ const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
+
+ // theValueType not a pointer?
+ if (!theValueType)
+ return false;
+
+ QualType theValueTypePointee =
+ Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
+
+ // The pointee must match newValueType and oldValueType.
+ if (theValueTypePointee != newValueType)
+ return false;
+
+ static unsigned magic_load = 0;
+ static unsigned magic_store = 0;
+
+ const void *OSAtomicLoadTag = &magic_load;
+ const void *OSAtomicStoreTag = &magic_store;
+
+ // Load 'theValue'.
+ GRExprEngine &Engine = C.getEngine();
+ const GRState *state = C.getState();
+ ExplodedNodeSet Tmp;
+ 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);
+ }
+ }
+ Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(),
+ state, location, OSAtomicLoadTag, LoadTy);
+
+ if (Tmp.empty()) {
+ // If no nodes were generated, other checkers must generated sinks. But
+ // since the builder state was restored, we set it manually to prevent
+ // auto transition.
+ // FIXME: there should be a better approach.
+ C.getNodeBuilder().BuildSinks = true;
+ return true;
+ }
+
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
+ I != E; ++I) {
+
+ ExplodedNode *N = *I;
+ const GRState *stateLoad = N->getState();
+ SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
+ SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
+
+ // FIXME: Issue an error.
+ if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
+ return false;
+ }
+
+ DefinedOrUnknownSVal theValueVal =
+ cast<DefinedOrUnknownSVal>(theValueVal_untested);
+ DefinedOrUnknownSVal oldValueVal =
+ cast<DefinedOrUnknownSVal>(oldValueVal_untested);
+
+ SValuator &SVator = Engine.getSValuator();
+
+ // Perform the comparison.
+ DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad,theValueVal,oldValueVal);
+
+ const GRState *stateEqual = stateLoad->Assume(Cmp, true);
+
+ // Were they equal?
+ if (stateEqual) {
+ // Perform the store.
+ ExplodedNodeSet TmpStore;
+ SVal val = stateEqual->getSVal(newValueExpr);
+
+ // Handle implicit value casts.
+ if (const TypedRegion *R =
+ dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ llvm::tie(state, val) = SVator.EvalCast(val, state,R->getValueType(Ctx),
+ newValueExpr->getType());
+ }
+
+ Engine.EvalStore(TmpStore, NULL, const_cast<Expr *>(theValueExpr), N,
+ stateEqual, location, val, OSAtomicStoreTag);
+
+ if (TmpStore.empty()) {
+ // If no nodes were generated, other checkers must generated sinks. But
+ // since the builder state was restored, we set it manually to prevent
+ // auto transition.
+ // FIXME: there should be a better approach.
+ C.getNodeBuilder().BuildSinks = true;
+ return true;
+ }
+
+ // Now bind the result of the comparison.
+ for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
+ E2 = TmpStore.end(); I2 != E2; ++I2) {
+ ExplodedNode *predNew = *I2;
+ const GRState *stateNew = predNew->getState();
+ SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
+ 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());
+ C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N);
+ }
+ }
+
+ return true;
+}
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
index 800496a..734570a 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -36,30 +36,16 @@ bool PathDiagnosticMacroPiece::containsEvent() const {
return false;
}
-static size_t GetNumCharsToLastNonPeriod(const char *s) {
- const char *start = s;
- const char *lastNonPeriod = 0;
-
- for ( ; *s != '\0' ; ++s)
- if (*s != '.') lastNonPeriod = s;
-
- if (!lastNonPeriod)
- return 0;
-
- return (lastNonPeriod - start) + 1;
-}
-
-static inline size_t GetNumCharsToLastNonPeriod(const std::string &s) {
- return s.empty () ? 0 : GetNumCharsToLastNonPeriod(&s[0]);
+static llvm::StringRef StripTrailingDots(llvm::StringRef s) {
+ for (llvm::StringRef::size_type i = s.size(); i != 0; --i)
+ if (s[i - 1] != '.')
+ return s.substr(0, i);
+ return "";
}
-PathDiagnosticPiece::PathDiagnosticPiece(const std::string& s,
+PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s,
Kind k, DisplayHint hint)
- : str(s, 0, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
-
-PathDiagnosticPiece::PathDiagnosticPiece(const char* s, Kind k,
- DisplayHint hint)
- : str(s, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
+ : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
: kind(k), Hint(hint) {}
@@ -89,20 +75,12 @@ void PathDiagnostic::resetPath(bool deletePieces) {
}
-PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc,
- const char* category)
- : Size(0),
- BugType(bugtype, GetNumCharsToLastNonPeriod(bugtype)),
- Desc(desc, GetNumCharsToLastNonPeriod(desc)),
- Category(category, GetNumCharsToLastNonPeriod(category)) {}
-
-PathDiagnostic::PathDiagnostic(const std::string& bugtype,
- const std::string& desc,
- const std::string& category)
+PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
+ llvm::StringRef category)
: Size(0),
- BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)),
- Desc(desc, 0, GetNumCharsToLastNonPeriod(desc)),
- Category(category, 0, GetNumCharsToLastNonPeriod(category)) {}
+ BugType(StripTrailingDots(bugtype)),
+ Desc(StripTrailingDots(desc)),
+ Category(StripTrailingDots(category)) {}
void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) {
@@ -126,8 +104,7 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
Info.FormatDiagnostic(StrC);
PathDiagnosticPiece *P =
- new PathDiagnosticEventPiece(Info.getLocation(),
- std::string(StrC.begin(), StrC.end()));
+ new PathDiagnosticEventPiece(Info.getLocation(), StrC.str());
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
P->addRange(Info.getRange(i));
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index e645172..b5eeb1e 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -269,7 +269,15 @@ public:
const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
const Expr *E, unsigned Count,
- InvalidatedSymbols *IS);
+ InvalidatedSymbols *IS) {
+ return RegionStoreManager::InvalidateRegions(state, &R, &R+1, E, Count, IS);
+ }
+
+ const GRState *InvalidateRegions(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS);
private:
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
@@ -279,7 +287,9 @@ public:
const GRState *Bind(const GRState *state, Loc LV, SVal V);
const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL, SVal V);
+ const CompoundLiteralExpr* CL,
+ const LocationContext *LC,
+ SVal V);
const GRState *BindDecl(const GRState *ST, const VarRegion *VR,
SVal InitVal);
@@ -460,16 +470,14 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
B = RBFactory.Remove(B, R);
}
-const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
- const MemRegion *R,
- const Expr *Ex,
- unsigned Count,
- InvalidatedSymbols *IS) {
+const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
+ const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex,
+ unsigned Count,
+ InvalidatedSymbols *IS) {
ASTContext& Ctx = StateMgr.getContext();
- // Strip away casts.
- R = R->StripCasts();
-
// Get the mapping of regions -> subregions.
llvm::OwningPtr<RegionStoreSubRegionMap>
SubRegions(getRegionStoreSubRegionMap(state->getStore()));
@@ -478,10 +486,14 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
llvm::DenseMap<const MemRegion *, unsigned> Visited;
llvm::SmallVector<const MemRegion *, 10> WorkList;
- WorkList.push_back(R);
+
+ for ( ; I != E; ++I) {
+ // Strip away casts.
+ WorkList.push_back((*I)->StripCasts());
+ }
while (!WorkList.empty()) {
- R = WorkList.back();
+ const MemRegion *R = WorkList.back();
WorkList.pop_back();
// Have we visited this region before?
@@ -512,6 +524,19 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
IS->insert(SR->getSymbol());
}
+
+ // BlockDataRegion? If so, invalidate captured variables that are passed
+ // by reference.
+ if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+ for (BlockDataRegion::referenced_vars_iterator
+ I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ;
+ I != E; ++I) {
+ const VarRegion *VR = *I;
+ if (VR->getDecl()->getAttr<BlocksAttr>())
+ WorkList.push_back(VR);
+ }
+ continue;
+ }
// Handle the region itself.
if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
@@ -592,15 +617,6 @@ SVal RegionStoreManager::getLValueVar(const VarDecl *VD,
return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC));
}
-/// getLValueCompoundLiteral - Returns an SVal representing the lvalue
-/// of a compound literal. Within RegionStore a compound literal
-/// has an associated region, and the lvalue of the compound literal
-/// is the lvalue of that region.
-SVal
-RegionStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL) {
- return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL));
-}
-
SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
return getLValueFieldOrIvar(D, Base);
}
@@ -707,7 +723,12 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
const MemRegion *R) {
switch (R->getKind()) {
- case MemRegion::MemSpaceRegionKind:
+ case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::StackLocalsSpaceRegionKind:
+ case MemRegion::StackArgumentsSpaceRegionKind:
+ case MemRegion::HeapSpaceRegionKind:
+ case MemRegion::GlobalsSpaceRegionKind:
+ case MemRegion::UnknownSpaceRegionKind:
assert(0 && "Cannot index into a MemSpace");
return UnknownVal();
@@ -752,13 +773,6 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
// essentially are arrays of size 1.
return ValMgr.makeIntVal(1, false);
}
-
- case MemRegion::BEG_DECL_REGIONS:
- case MemRegion::END_DECL_REGIONS:
- case MemRegion::BEG_TYPED_REGIONS:
- case MemRegion::END_TYPED_REGIONS:
- assert(0 && "Infeasible region");
- return UnknownVal();
}
assert(0 && "Unreachable");
@@ -797,9 +811,8 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
T = AT->getElementType();
SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
- ElementRegion* ER = MRMgr.getElementRegion(T, ZeroIdx, ArrayR, getContext());
-
- return loc::MemRegionVal(ER);
+ return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR,
+ getContext()));
}
//===----------------------------------------------------------------------===//
@@ -864,16 +877,14 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
// Technically this can happen if people do funny things with casts.
return UnknownVal();
- case MemRegion::MemSpaceRegionKind:
+ case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::StackLocalsSpaceRegionKind:
+ case MemRegion::StackArgumentsSpaceRegionKind:
+ case MemRegion::HeapSpaceRegionKind:
+ case MemRegion::GlobalsSpaceRegionKind:
+ case MemRegion::UnknownSpaceRegionKind:
assert(0 && "Cannot perform pointer arithmetic on a MemSpace");
return UnknownVal();
-
- case MemRegion::BEG_DECL_REGIONS:
- case MemRegion::END_DECL_REGIONS:
- case MemRegion::BEG_TYPED_REGIONS:
- case MemRegion::END_TYPED_REGIONS:
- assert(0 && "Infeasible region");
- return UnknownVal();
}
SVal Idx = ER->getIndex();
@@ -1283,7 +1294,8 @@ SVal RegionStoreManager::RetrieveVar(const GRState *state,
// Lazily derive a value for the VarRegion.
const VarDecl *VD = R->getDecl();
- if (R->hasGlobalsOrParametersStorage())
+ if (R->hasGlobalsOrParametersStorage() ||
+ isa<UnknownSpaceRegion>(R->getMemorySpace()))
return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType());
return UndefinedVal();
@@ -1440,11 +1452,11 @@ const GRState *RegionStoreManager::BindDecl(const GRState *ST,
// FIXME: this method should be merged into Bind().
const GRState *
RegionStoreManager::BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL,
+ const CompoundLiteralExpr *CL,
+ const LocationContext *LC,
SVal V) {
-
- CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL);
- return Bind(state, loc::MemRegionVal(R), V);
+ return Bind(state, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
+ V);
}
const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
@@ -1497,8 +1509,8 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
break;
SVal Idx = ValMgr.makeArrayIndex(i);
- ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R,
- getContext());
+ const ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R,
+ getContext());
SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true);
state = Bind(state, loc::MemRegionVal(ER), V);
@@ -1526,7 +1538,7 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
break;
SVal Idx = ValMgr.makeArrayIndex(i);
- ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
+ const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
if (CAT->getElementType()->isStructureType())
state = BindStruct(state, ER, *VI);
@@ -1677,7 +1689,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
IntermediateVisited.insert(R);
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
- if (SymReaper.isLive(Loc, VR->getDecl()))
+ if (SymReaper.isLive(Loc, VR))
WorkList.push_back(std::make_pair(&state, VR));
continue;
}
@@ -1753,14 +1765,16 @@ tryAgain:
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.markLive(SymR->getSymbol());
- // For BlockDataRegions, enqueue all VarRegions for that are referenced
+ // For BlockDataRegions, enqueue the VarRegions for variables marked
+ // with __block (passed-by-reference).
// via BlockDeclRefExprs.
if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
for (BlockDataRegion::referenced_vars_iterator
RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
- RI != RE; ++RI)
- WorkList.push_back(std::make_pair(state_N, *RI));
-
+ RI != RE; ++RI) {
+ if ((*RI)->getDecl()->getAttr<BlocksAttr>())
+ WorkList.push_back(std::make_pair(state_N, *RI));
+ }
// No possible data bindings on a BlockDataRegion. Continue to the
// next region in the worklist.
continue;
@@ -1846,8 +1860,7 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
// Copy the arg expression value to the arg variables.
for (; AI != AE; ++AI, ++PI) {
SVal ArgVal = state->getSVal(*AI);
- MemRegion *R = MRMgr.getVarRegion(*PI, frame);
- state = Bind(state, ValMgr.makeLoc(R), ArgVal);
+ state = Bind(state, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
}
return state;
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 2fd573c..e6ff6e5 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -77,11 +77,12 @@ 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::BEG_TYPED_REGIONS:
- case MemRegion::MemSpaceRegionKind:
- case MemRegion::BEG_DECL_REGIONS:
- case MemRegion::END_DECL_REGIONS:
- case MemRegion::END_TYPED_REGIONS: {
+ case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::StackLocalsSpaceRegionKind:
+ case MemRegion::StackArgumentsSpaceRegionKind:
+ case MemRegion::HeapSpaceRegionKind:
+ case MemRegion::UnknownSpaceRegionKind:
+ case MemRegion::GlobalsSpaceRegionKind: {
assert(0 && "Invalid region cast");
break;
}
@@ -199,9 +200,33 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
QualType castTy) {
if (castTy.isNull())
return V;
-
+
assert(ValMgr.getContext().hasSameUnqualifiedType(castTy,
R->getValueType(ValMgr.getContext())));
return V;
}
+const GRState *StoreManager::InvalidateRegions(const GRState *state,
+ const MemRegion * const *I,
+ const MemRegion * const *End,
+ const Expr *E,
+ unsigned Count,
+ InvalidatedSymbols *IS) {
+ for ( ; I != End ; ++I)
+ state = InvalidateRegion(state, *I, E, Count, IS);
+
+ return state;
+}
+
+//===----------------------------------------------------------------------===//
+// Common getLValueXXX methods.
+//===----------------------------------------------------------------------===//
+
+/// getLValueCompoundLiteral - Returns an SVal representing the lvalue
+/// of a compound literal. Within RegionStore a compound literal
+/// has an associated region, and the lvalue of the compound literal
+/// is the lvalue of that region.
+SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
+ const LocationContext *LC) {
+ return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
+}
diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp
index 22e1101..3fe36b0 100644
--- a/lib/Analysis/SymbolManager.cpp
+++ b/lib/Analysis/SymbolManager.cpp
@@ -220,4 +220,9 @@ bool SymbolReaper::isLive(SymbolRef sym) {
return isa<SymbolRegionValue>(sym);
}
+bool SymbolReaper::isLive(const Stmt *Loc, const VarRegion *VR) const {
+ const StackFrameContext *SFC = VR->getStackFrame();
+ return SFC == CurrentStackFrame ? Liveness.isLive(Loc, VR->getDecl()) : true;
+}
+
SymbolVisitor::~SymbolVisitor() {}
diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp
index 22a8211..d091373 100644
--- a/lib/Analysis/ValueManager.cpp
+++ b/lib/Analysis/ValueManager.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/ValueManager.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
using namespace clang;
using namespace llvm;
@@ -138,15 +139,15 @@ ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
}
DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
- CodeTextRegion *R = MemMgr.getFunctionTextRegion(FD);
- return loc::MemRegionVal(R);
+ return loc::MemRegionVal(MemMgr.getFunctionTextRegion(FD));
}
DefinedSVal ValueManager::getBlockPointer(const BlockDecl *D,
CanQualType locTy,
const LocationContext *LC) {
- BlockTextRegion *BC = MemMgr.getBlockTextRegion(D, locTy);
- BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
+ const BlockTextRegion *BC =
+ MemMgr.getBlockTextRegion(D, locTy, LC->getAnalysisContext());
+ const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
return loc::MemRegionVal(BD);
}
OpenPOWER on IntegriCloud