summaryrefslogtreecommitdiffstats
path: root/lib/Checker
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-03-03 17:28:16 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-03-03 17:28:16 +0000
commitdf90325d4c0a65ee64d2dae3ed9b5b34f7418533 (patch)
treee1a885aadfd80632f5bd70d4bd2d37e715e35a79 /lib/Checker
parentfd035e6496665b1f1197868e21cb0a4594e8db6e (diff)
downloadFreeBSD-src-df90325d4c0a65ee64d2dae3ed9b5b34f7418533.zip
FreeBSD-src-df90325d4c0a65ee64d2dae3ed9b5b34f7418533.tar.gz
Update clang to 97654.
Diffstat (limited to 'lib/Checker')
-rw-r--r--lib/Checker/BasicStore.cpp52
-rw-r--r--lib/Checker/BuiltinFunctionChecker.cpp1
-rw-r--r--lib/Checker/CFRefCount.cpp40
-rw-r--r--lib/Checker/CMakeLists.txt4
-rw-r--r--lib/Checker/CallInliner.cpp67
-rw-r--r--lib/Checker/CheckDeadStores.cpp3
-rw-r--r--lib/Checker/FlatStore.cpp2
-rw-r--r--lib/Checker/GRCoreEngine.cpp104
-rw-r--r--lib/Checker/GRExprEngine.cpp70
-rw-r--r--lib/Checker/GRExprEngineInternalChecks.h30
-rw-r--r--lib/Checker/MacOSXAPIChecker.cpp141
-rw-r--r--lib/Checker/MemRegion.cpp25
-rw-r--r--lib/Checker/OSAtomicChecker.cpp1
-rw-r--r--lib/Checker/ObjCUnusedIVarsChecker.cpp (renamed from lib/Checker/CheckObjCUnusedIVars.cpp)29
-rw-r--r--lib/Checker/RegionStore.cpp14
-rw-r--r--lib/Checker/SymbolManager.cpp21
-rw-r--r--lib/Checker/UnixAPIChecker.cpp154
-rw-r--r--lib/Checker/ValueManager.cpp12
18 files changed, 597 insertions, 173 deletions
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 6ef2942..d93a665 100644
--- a/lib/Checker/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -95,6 +95,8 @@ public:
const char *sep);
private:
+ SVal LazyRetrieve(Store store, const TypedRegion *R);
+
ASTContext& getContext() { return StateMgr.getContext(); }
};
@@ -126,6 +128,25 @@ static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
}
}
+SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) {
+ const VarRegion *VR = dyn_cast<VarRegion>(R);
+ if (!VR)
+ return UnknownVal();
+
+ const VarDecl *VD = VR->getDecl();
+ QualType T = VD->getType();
+
+ // Only handle simple types that we can symbolicate.
+ if (!SymbolManager::canSymbolicate(T) || !T->isScalarType())
+ return UnknownVal();
+
+ // Globals and parameters start with symbolic values.
+ // Local variables initially are undefined.
+ if (VR->hasGlobalsOrParametersStorage())
+ return ValMgr.getRegionValueSymbolVal(R);
+ return UndefinedVal();
+}
+
SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
if (isa<UnknownVal>(loc))
return UnknownVal();
@@ -142,11 +163,13 @@ SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
BindingsTy B = GetBindings(store);
BindingsTy::data_type *Val = B.lookup(R);
+ const TypedRegion *TR = cast<TypedRegion>(R);
- if (!Val)
- break;
+ if (Val)
+ return CastRetrievedVal(*Val, TR, T);
- return CastRetrievedVal(*Val, cast<TypedRegion>(R), T);
+ SVal V = LazyRetrieve(store, TR);
+ return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T);
}
case loc::ConcreteIntKind:
@@ -319,7 +342,7 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
const Expr *Base = IV->getBase()->IgnoreParenCasts();
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Base)) {
if (DR->getDecl() == SelfDecl) {
- const MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
+ const ObjCIvarRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
SelfRegion);
SVal X = ValMgr.getRegionValueSymbolVal(IVR);
St = Bind(St, ValMgr.makeLoc(IVR), X);
@@ -351,10 +374,10 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
if (MD->getSelfDecl() == PD) {
// FIXME: Add type constraints (when they become available) to
// SelfRegion? (i.e., it implements MD->getClassInterface()).
- const MemRegion *VR = MRMgr.getVarRegion(PD, InitLoc);
+ const VarRegion *VR = MRMgr.getVarRegion(PD, InitLoc);
const MemRegion *SelfRegion =
- ValMgr.getRegionValueSymbolVal(VR).getAsRegion();
- assert(SelfRegion);
+ ValMgr.getRegionValueSymbolVal(VR).getAsRegion();
+ assert(SelfRegion);
St = Bind(St, ValMgr.makeLoc(VR), loc::MemRegionVal(SelfRegion));
// Scan the method for ivar references. While this requires an
// entire AST scan, the cost should not be high in practice.
@@ -362,21 +385,8 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
}
}
}
- else if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
- // Only handle simple types that we can symbolicate.
- if (!SymbolManager::canSymbolicate(VD->getType()))
- continue;
-
- // Initialize globals and parameters to symbolic values.
- // Initialize local variables to undefined.
- const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD, InitLoc);
- SVal X = UndefinedVal();
- if (R->hasGlobalsOrParametersStorage())
- X = ValMgr.getRegionValueSymbolVal(R);
-
- St = Bind(St, ValMgr.makeLoc(R), X);
- }
}
+
return St;
}
diff --git a/lib/Checker/BuiltinFunctionChecker.cpp b/lib/Checker/BuiltinFunctionChecker.cpp
index 8711492..9c8b516 100644
--- a/lib/Checker/BuiltinFunctionChecker.cpp
+++ b/lib/Checker/BuiltinFunctionChecker.cpp
@@ -14,7 +14,6 @@
#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
-#include "llvm/ADT/StringSwitch.h"
using namespace clang;
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 324916a..ecb98a0 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -12,26 +12,26 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
-#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
-#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "clang/Checker/PathSensitive/SymbolManager.h"
-#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Checker/DomainSpecific/CocoaConventions.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/StmtVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableList.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include <stdarg.h>
using namespace clang;
@@ -1222,6 +1222,12 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
else if (FD->getAttr<CFReturnsRetainedAttr>()) {
Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
+ else if (FD->getAttr<NSReturnsNotRetainedAttr>()) {
+ Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
+ }
+ else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
+ Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+ }
}
else if (RetTy->getAs<PointerType>()) {
if (FD->getAttr<CFReturnsRetainedAttr>()) {
@@ -1244,6 +1250,10 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
Summ.setRetEffect(ObjCAllocRetE);
return;
}
+ if (MD->getAttr<NSReturnsNotRetainedAttr>()) {
+ Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
+ return;
+ }
isTrackedLoc = true;
}
@@ -1251,8 +1261,12 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
if (!isTrackedLoc)
isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL;
- if (isTrackedLoc && MD->getAttr<CFReturnsRetainedAttr>())
- Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+ if (isTrackedLoc) {
+ if (MD->getAttr<CFReturnsRetainedAttr>())
+ Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+ else if (MD->getAttr<CFReturnsNotRetainedAttr>())
+ Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+ }
}
RetainSummary*
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
index 7b21d08..c5bd2eb 100644
--- a/lib/Checker/CMakeLists.txt
+++ b/lib/Checker/CMakeLists.txt
@@ -18,7 +18,6 @@ add_clang_library(clangChecker
CheckDeadStores.cpp
CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp
- CheckObjCUnusedIVars.cpp
CheckSecuritySyntaxOnly.cpp
CheckSizeofPointer.cpp
Checker.cpp
@@ -35,6 +34,7 @@ add_clang_library(clangChecker
GRExprEngineExperimentalChecks.cpp
GRState.cpp
LLVMConventionsChecker.cpp
+ MacOSXAPIChecker.cpp
MallocChecker.cpp
ManagerRegistry.cpp
MemRegion.cpp
@@ -42,6 +42,7 @@ add_clang_library(clangChecker
NSErrorChecker.cpp
NoReturnFunctionChecker.cpp
OSAtomicChecker.cpp
+ ObjCUnusedIVarsChecker.cpp
PathDiagnostic.cpp
PointerArithChecker.cpp
PointerSubChecker.cpp
@@ -62,6 +63,7 @@ add_clang_library(clangChecker
UndefResultChecker.cpp
UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
+ UnixAPIChecker.cpp
VLASizeChecker.cpp
ValueManager.cpp
)
diff --git a/lib/Checker/CallInliner.cpp b/lib/Checker/CallInliner.cpp
index d94994b..88e1a05 100644
--- a/lib/Checker/CallInliner.cpp
+++ b/lib/Checker/CallInliner.cpp
@@ -26,7 +26,6 @@ public:
}
virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
- virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng);
};
}
@@ -43,71 +42,13 @@ bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
if (!FD)
return false;
- if (!FD->isThisDeclarationADefinition())
+ if (!FD->getBody(FD))
return false;
- GRStmtNodeBuilder &Builder = C.getNodeBuilder();
- // Make a new LocationContext.
- const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD,
- C.getPredecessor()->getLocationContext(), CE,
- Builder.getBlock(), Builder.getIndex());
-
- CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry());
-
- assert (Entry->empty() && "Entry block must be empty.");
-
- assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
-
- // Get the solitary successor.
- CFGBlock const *SuccB = *(Entry->succ_begin());
-
- // Construct an edge representing the starting location in the function.
- BlockEdge Loc(Entry, SuccB, LocCtx);
-
- state = C.getStoreManager().EnterStackFrame(state, LocCtx);
- // This is a hack. We really should not use the GRStmtNodeBuilder.
- bool isNew;
- GRExprEngine &Eng = C.getEngine();
- ExplodedNode *Pred = C.getPredecessor();
-
-
- ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew);
- SuccN->addPredecessor(Pred, Eng.getGraph());
- C.getNodeBuilder().Deferred.erase(Pred);
-
- if (isNew)
- Builder.getWorkList()->Enqueue(SuccN);
-
- Builder.HasGeneratedNode = true;
+ // Now we have the definition of the callee, create a CallEnter node.
+ CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext());
+ C.addTransition(state, Loc);
return true;
}
-void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
- GRExprEngine &Eng) {
- const GRState *state = B.getState();
- ExplodedNode *Pred = B.getPredecessor();
- const StackFrameContext *LocCtx =
- cast<StackFrameContext>(Pred->getLocationContext());
-
- const Stmt *CE = LocCtx->getCallSite();
-
- // Check if this is the top level stack frame.
- if (!LocCtx->getParent())
- return;
-
- PostStmt NodeLoc(CE, LocCtx->getParent());
-
- bool isNew;
- ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew);
- Succ->addPredecessor(Pred, Eng.getGraph());
-
- // When creating the new work list unit, increment the statement index to
- // point to the statement after the CallExpr.
- if (isNew)
- B.getWorkList().Enqueue(Succ,
- *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
- LocCtx->getIndex() + 1);
-
- B.HasGeneratedNode = true;
-}
diff --git a/lib/Checker/CheckDeadStores.cpp b/lib/Checker/CheckDeadStores.cpp
index 4a7ca70..31f9390 100644
--- a/lib/Checker/CheckDeadStores.cpp
+++ b/lib/Checker/CheckDeadStores.cpp
@@ -142,7 +142,8 @@ public:
if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
// Special case: check for assigning null to a pointer.
// This is a common form of defensive programming.
- if (VD->getType()->isPointerType()) {
+ QualType T = VD->getType();
+ if (T->isPointerType() || T->isObjCObjectPointerType()) {
if (B->getRHS()->isNullPointerConstant(Ctx,
Expr::NPC_ValueDependentIsNull))
return;
diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp
index dac66de..07a54fb 100644
--- a/lib/Checker/FlatStore.cpp
+++ b/lib/Checker/FlatStore.cpp
@@ -97,7 +97,7 @@ SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R,
if (R->hasStackNonParametersStorage())
return UndefinedVal();
else
- return ValMgr.getRegionValueSymbolVal(R, T);
+ return ValMgr.getRegionValueSymbolVal(cast<TypedRegion>(R));
}
Store FlatStoreManager::Bind(Store store, Loc L, SVal val) {
diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index d54b077..a9347d0 100644
--- a/lib/Checker/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -144,6 +144,14 @@ void GRCoreEngine::ProcessSwitch(GRSwitchNodeBuilder& Builder) {
SubEngine.ProcessSwitch(Builder);
}
+void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) {
+ SubEngine.ProcessCallEnter(Builder);
+}
+
+void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) {
+ SubEngine.ProcessCallExit(Builder);
+}
+
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
@@ -196,6 +204,15 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
assert (false && "BlockExit location never occur in forward analysis.");
break;
+ case ProgramPoint::CallEnterKind:
+ HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(),
+ WU.getIndex(), Node);
+ break;
+
+ case ProgramPoint::CallExitKind:
+ HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
+ break;
+
default:
assert(isa<PostStmt>(Node->getLocation()));
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
@@ -207,6 +224,17 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
return WList->hasWork();
}
+void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
+ unsigned Index, ExplodedNode *Pred) {
+ GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(),
+ Block, Index);
+ ProcessCallEnter(Builder);
+}
+
+void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
+ GRCallExitNodeBuilder Builder(*this, Pred);
+ ProcessCallExit(Builder);
+}
void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
@@ -384,11 +412,11 @@ void GRCoreEngine::GenerateNode(const ProgramPoint& Loc,
GRStmtNodeBuilder::GRStmtNodeBuilder(CFGBlock* b, unsigned idx,
ExplodedNode* N, GRCoreEngine* e,
GRStateManager &mgr)
- : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Mgr(mgr), Auditor(0),
+ : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr), Auditor(0),
PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false),
PointKind(ProgramPoint::PostStmtKind), Tag(0) {
Deferred.insert(N);
- CleanedState = getLastNode()->getState();
+ CleanedState = Pred->getState();
}
GRStmtNodeBuilder::~GRStmtNodeBuilder() {
@@ -400,6 +428,14 @@ GRStmtNodeBuilder::~GRStmtNodeBuilder() {
void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
assert (!N->isSink());
+ // Check if this node entered a callee.
+ if (isa<CallEnter>(N->getLocation())) {
+ // Still use the index of the CallExpr. It's needed to create the callee
+ // StackFrameContext.
+ Eng.WList->Enqueue(N, B, Idx);
+ return;
+ }
+
PostStmt Loc(getStmt(), N->getLocationContext());
if (Loc == N->getLocation()) {
@@ -462,11 +498,9 @@ GRStmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
if (IsNew) {
Deferred.insert(N);
- LastNode = N;
return N;
}
- LastNode = NULL;
return NULL;
}
@@ -576,7 +610,13 @@ GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) {
GREndPathNodeBuilder::~GREndPathNodeBuilder() {
// Auto-generate an EOP node if one has not been generated.
- if (!HasGeneratedNode) generateNode(Pred->State);
+ if (!HasGeneratedNode) {
+ // If we are in an inlined call, generate CallExit node.
+ if (Pred->getLocationContext()->getParent())
+ GenerateCallExitNode(Pred->State);
+ else
+ generateNode(Pred->State);
+ }
}
ExplodedNode*
@@ -597,3 +637,57 @@ GREndPathNodeBuilder::generateNode(const GRState* State, const void *tag,
return NULL;
}
+
+void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) {
+ HasGeneratedNode = true;
+ // Create a CallExit node and enqueue it.
+ const StackFrameContext *LocCtx
+ = cast<StackFrameContext>(Pred->getLocationContext());
+ const Stmt *CE = LocCtx->getCallSite();
+
+ // Use the the callee location context.
+ CallExit Loc(CE, LocCtx);
+
+ bool isNew;
+ ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+ Node->addPredecessor(Pred, *Eng.G);
+
+ if (isNew)
+ Eng.WList->Enqueue(Node);
+}
+
+
+void GRCallEnterNodeBuilder::GenerateNode(const GRState *state,
+ const LocationContext *LocCtx) {
+ // Get the callee entry block.
+ const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry());
+ assert(Entry->empty());
+ assert(Entry->succ_size() == 1);
+
+ // Get the solitary successor.
+ const CFGBlock *SuccB = *(Entry->succ_begin());
+
+ // Construct an edge representing the starting location in the callee.
+ BlockEdge Loc(Entry, SuccB, LocCtx);
+
+ bool isNew;
+ ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+ Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
+
+ if (isNew)
+ Eng.WList->Enqueue(Node);
+}
+
+void GRCallExitNodeBuilder::GenerateNode(const GRState *state) {
+ // Get the callee's location context.
+ const StackFrameContext *LocCtx
+ = cast<StackFrameContext>(Pred->getLocationContext());
+
+ PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent());
+ bool isNew;
+ ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+ Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
+ if (isNew)
+ Eng.WList->Enqueue(Node, *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
+ LocCtx->getIndex() + 1);
+}
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index 7f86319..ad229c7 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -37,6 +37,15 @@ using llvm::dyn_cast_or_null;
using llvm::cast;
using llvm::APSInt;
+namespace {
+ // Trait class for recording returned expression in the state.
+ struct ReturnExpr {
+ static int TagInt;
+ typedef const Stmt *data_type;
+ };
+ int ReturnExpr::TagInt;
+}
+
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
@@ -318,6 +327,8 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterNoReturnFunctionChecker(Eng);
RegisterBuiltinFunctionChecker(Eng);
RegisterOSAtomicChecker(Eng);
+ RegisterUnixAPIChecker(Eng);
+ RegisterMacOSXAPIChecker(Eng);
}
GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
@@ -458,7 +469,7 @@ void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
"Error evaluating statement");
Builder = &builder;
- EntryNode = builder.getLastNode();
+ EntryNode = builder.getBasePredecessor();
// Set up our simple checks.
if (BatchAuditor)
@@ -1288,6 +1299,37 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt);
}
+void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) {
+ const FunctionDecl *FD = B.getCallee();
+ const StackFrameContext *LocCtx = AMgr.getStackFrame(FD,
+ B.getLocationContext(),
+ B.getCallExpr(),
+ B.getBlock(),
+ B.getIndex());
+
+ const GRState *state = B.getState();
+ state = getStoreManager().EnterStackFrame(state, LocCtx);
+
+ B.GenerateNode(state, LocCtx);
+}
+
+void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) {
+ const GRState *state = B.getState();
+ const ExplodedNode *Pred = B.getPredecessor();
+ const StackFrameContext *LocCtx =
+ cast<StackFrameContext>(Pred->getLocationContext());
+ const Stmt *CE = LocCtx->getCallSite();
+
+ // If the callee returns an expression, bind its value to CallExpr.
+ const Stmt *ReturnedExpr = state->get<ReturnExpr>();
+ if (ReturnedExpr) {
+ SVal RetVal = state->getSVal(ReturnedExpr);
+ state = state->BindExpr(CE, RetVal);
+ }
+
+ B.GenerateNode(state);
+}
+
//===----------------------------------------------------------------------===//
// Transfer functions: logical operations ('&&', '||').
//===----------------------------------------------------------------------===//
@@ -2316,8 +2358,9 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
- if (InitVal.isUnknown() ||
- !getConstraintManager().canReasonAbout(InitVal)) {
+ if ((InitVal.isUnknown() ||
+ !getConstraintManager().canReasonAbout(InitVal)) &&
+ !VD->getType()->isReferenceType()) {
InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
Builder->getCurrentBlockCount());
}
@@ -2855,10 +2898,19 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
ExplodedNodeSet Src;
if (Expr *RetE = RS->getRetValue()) {
- Visit(RetE, Pred, Src);
+ // Record the returned expression in the state.
+ {
+ static int Tag = 0;
+ SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag);
+ const GRState *state = GetState(Pred);
+ state = state->set<ReturnExpr>(RetE);
+ Pred = Builder->generateNode(RetE, state, Pred);
+ }
+ // We may get a NULL Pred because we generated a cached node.
+ if (Pred)
+ Visit(RetE, Pred, Src);
}
else {
Src.Add(Pred);
@@ -3139,6 +3191,14 @@ struct DOTGraphTraits<ExplodedNode*> :
assert (false);
break;
+ case ProgramPoint::CallEnterKind:
+ Out << "CallEnter";
+ break;
+
+ case ProgramPoint::CallExitKind:
+ Out << "CallExit";
+ break;
+
default: {
if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
const Stmt* S = L->getStmt();
diff --git a/lib/Checker/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h
index 64a930d..d117600 100644
--- a/lib/Checker/GRExprEngineInternalChecks.h
+++ b/lib/Checker/GRExprEngineInternalChecks.h
@@ -19,27 +19,33 @@ namespace clang {
class GRExprEngine;
+// Foundational checks that handle basic semantics.
void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng);
+void RegisterArrayBoundChecker(GRExprEngine &Eng);
void RegisterAttrNonNullChecker(GRExprEngine &Eng);
+void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
+void RegisterCallAndMessageChecker(GRExprEngine &Eng);
+void RegisterCastToStructChecker(GRExprEngine &Eng);
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
+void RegisterFixedAddressChecker(GRExprEngine &Eng);
+void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
+void RegisterPointerArithChecker(GRExprEngine &Eng);
+void RegisterPointerSubChecker(GRExprEngine &Eng);
void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
-void RegisterReturnStackAddressChecker(GRExprEngine &Eng);
+void RegisterReturnStackAddressChecker(GRExprEngine &Eng);
void RegisterReturnUndefChecker(GRExprEngine &Eng);
-void RegisterVLASizeChecker(GRExprEngine &Eng);
-void RegisterPointerSubChecker(GRExprEngine &Eng);
-void RegisterPointerArithChecker(GRExprEngine &Eng);
-void RegisterFixedAddressChecker(GRExprEngine &Eng);
-void RegisterCastToStructChecker(GRExprEngine &Eng);
-void RegisterCallAndMessageChecker(GRExprEngine &Eng);
-void RegisterArrayBoundChecker(GRExprEngine &Eng);
-void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
-void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
void RegisterUndefBranchChecker(GRExprEngine &Eng);
void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng);
void RegisterUndefResultChecker(GRExprEngine &Eng);
-void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
-void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
+void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
+void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
+void RegisterVLASizeChecker(GRExprEngine &Eng);
+
+// API checks.
+void RegisterMacOSXAPIChecker(GRExprEngine &Eng);
void RegisterOSAtomicChecker(GRExprEngine &Eng);
+void RegisterUnixAPIChecker(GRExprEngine &Eng);
+
} // end clang namespace
#endif
diff --git a/lib/Checker/MacOSXAPIChecker.cpp b/lib/Checker/MacOSXAPIChecker.cpp
new file mode 100644
index 0000000..9621e85
--- /dev/null
+++ b/lib/Checker/MacOSXAPIChecker.cpp
@@ -0,0 +1,141 @@
+// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines MacOSXAPIChecker, which is an assortment of checks on calls
+// to various, widely used Mac OS X functions.
+//
+// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
+// to here, using the new Checker interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace {
+class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
+ enum SubChecks {
+ DispatchOnce = 0,
+ DispatchOnceF,
+ NumChecks
+ };
+
+ BugType *BTypes[NumChecks];
+
+public:
+ MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
+ static void *getTag() { static unsigned tag = 0; return &tag; }
+
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} //end anonymous namespace
+
+void clang::RegisterMacOSXAPIChecker(GRExprEngine &Eng) {
+ if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
+ Eng.registerCheck(new MacOSXAPIChecker());
+}
+
+//===----------------------------------------------------------------------===//
+// dispatch_once and dispatch_once_f
+//===----------------------------------------------------------------------===//
+
+static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
+ BugType *&BT, const IdentifierInfo *FI) {
+
+ if (!BT) {
+ llvm::SmallString<128> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Improper use of '" << FI->getName() << '\'';
+ BT = new BugType(os.str(), "Mac OS X API");
+ }
+
+ if (CE->getNumArgs() < 1)
+ return;
+
+ // Check if the first argument is stack allocated. If so, issue a warning
+ // because that's likely to be bad news.
+ const GRState *state = C.getState();
+ const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+ if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+ return;
+
+ ExplodedNode *N = C.GenerateSink(state);
+ if (!N)
+ return;
+
+ llvm::SmallString<256> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Call to '" << FI->getName() << "' uses";
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ os << " the local variable '" << VR->getDecl()->getName() << '\'';
+ else
+ os << " stack allocated memory";
+ os << " for the predicate value. Using such transient memory for "
+ "the predicate is potentially dangerous.";
+ if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
+ os << " Perhaps you intended to declare the variable as 'static'?";
+
+ EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
+// Central dispatch function.
+//===----------------------------------------------------------------------===//
+
+typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
+ const IdentifierInfo *FI);
+namespace {
+ class SubCheck {
+ SubChecker SC;
+ BugType **BT;
+ public:
+ SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
+ SubCheck() : SC(NULL), BT(NULL) {}
+
+ void run(CheckerContext &C, const CallExpr *CE,
+ const IdentifierInfo *FI) const {
+ if (SC)
+ SC(C, CE, *BT, FI);
+ }
+ };
+} // end anonymous namespace
+
+void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+ // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ const FunctionTextRegion *Fn =
+ dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
+
+ if (!Fn)
+ return;
+
+ const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
+ if (!FI)
+ return;
+
+ const SubCheck &SC =
+ llvm::StringSwitch<SubCheck>(FI->getName())
+ .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
+ .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
+ BTypes[DispatchOnceF]))
+ .Default(SubCheck());
+
+ SC.run(C, CE, FI);
+}
diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 194015a..9a26988 100644
--- a/lib/Checker/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -419,20 +419,27 @@ const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
const StackLocalsSpaceRegion*
MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
assert(STC);
- if (STC == cachedStackLocalsFrame)
- return cachedStackLocalsRegion;
- cachedStackLocalsFrame = STC;
- return LazyAllocate(cachedStackLocalsRegion, STC);
+ StackLocalsSpaceRegion *&R = StackLocalsSpaceRegions[STC];
+
+ if (R)
+ return R;
+
+ R = A.Allocate<StackLocalsSpaceRegion>();
+ new (R) StackLocalsSpaceRegion(this, STC);
+ return R;
}
const StackArgumentsSpaceRegion *
MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
assert(STC);
- if (STC == cachedStackArgumentsFrame)
- return cachedStackArgumentsRegion;
-
- cachedStackArgumentsFrame = STC;
- return LazyAllocate(cachedStackArgumentsRegion, STC);
+ StackArgumentsSpaceRegion *&R = StackArgumentsSpaceRegions[STC];
+
+ if (R)
+ return R;
+
+ R = A.Allocate<StackArgumentsSpaceRegion>();
+ new (R) StackArgumentsSpaceRegion(this, STC);
+ return R;
}
const GlobalsSpaceRegion *MemRegionManager::getGlobalsRegion() {
diff --git a/lib/Checker/OSAtomicChecker.cpp b/lib/Checker/OSAtomicChecker.cpp
index 7f4aeca..e743528 100644
--- a/lib/Checker/OSAtomicChecker.cpp
+++ b/lib/Checker/OSAtomicChecker.cpp
@@ -14,7 +14,6 @@
#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
-#include "llvm/ADT/StringSwitch.h"
using namespace clang;
diff --git a/lib/Checker/CheckObjCUnusedIVars.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp
index f2cf581..04d897a 100644
--- a/lib/Checker/CheckObjCUnusedIVars.cpp
+++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp
@@ -1,4 +1,4 @@
-//==- CheckObjCUnusedIVars.cpp - Check for unused ivars ----------*- C++ -*-==//
+//==- ObjCUnusedIVarsChecker.cpp - Check for unused ivars --------*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@@ -68,14 +68,14 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
E = D->instmeth_end(); I!=E; ++I)
Scan(M, (*I)->getBody());
-
- if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
+
+ if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
// Scan for @synthesized property methods that act as setters/getters
// to an ivar.
for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(),
E = ID->propimpl_end(); I!=E; ++I)
Scan(M, *I);
-
+
// Scan the associated categories as well.
for (const ObjCCategoryDecl *CD =
ID->getClassInterface()->getCategoryList(); CD ;
@@ -92,7 +92,7 @@ static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
I!=E; ++I)
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
SourceLocation L = FD->getLocStart();
- if (SM.getFileID(L) == FID)
+ if (SM.getFileID(L) == FID)
Scan(M, FD->getBody());
}
}
@@ -109,12 +109,12 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
const ObjCIvarDecl* ID = *I;
- // Ignore ivars that aren't private.
- if (ID->getAccessControl() != ObjCIvarDecl::Private)
- continue;
-
- // Skip IB Outlets.
- if (ID->getAttr<IBOutletAttr>())
+ // Ignore ivars that...
+ // (a) aren't private
+ // (b) explicitly marked unused
+ // (c) are iboutlets
+ if (ID->getAccessControl() != ObjCIvarDecl::Private ||
+ ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>())
continue;
M[ID] = Unused;
@@ -122,11 +122,10 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
if (M.empty())
return;
-
+
// Now scan the implementation declaration.
Scan(M, D);
-
// Any potentially unused ivars?
bool hasUnused = false;
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
@@ -134,10 +133,10 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
hasUnused = true;
break;
}
-
+
if (!hasUnused)
return;
-
+
// We found some potentially unused ivars. Scan the entire translation unit
// for functions inside the @implementation that reference these ivars.
// FIXME: In the future hopefully we can just use the lexical DeclContext
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index f70105a..fd48f72 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -975,8 +975,10 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
if (isa<AllocaRegion>(MR) || isa<SymbolicRegion>(MR))
MR = GetElementZeroRegion(MR, T);
- if (isa<CodeTextRegion>(MR))
+ if (isa<CodeTextRegion>(MR)) {
+ assert(0 && "Why load from a code text region?");
return UnknownVal();
+ }
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
// instead of 'Loc', and have the other Loc cases handled at a higher level.
@@ -1068,7 +1070,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
}
// All other values are symbolic.
- return ValMgr.getRegionValueSymbolVal(R, RTy);
+ return ValMgr.getRegionValueSymbolVal(R);
}
std::pair<Store, const MemRegion *>
@@ -1229,7 +1231,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
}
// All other values are symbolic.
- return ValMgr.getRegionValueSymbolVal(R, Ty);
+ return ValMgr.getRegionValueSymbolVal(R);
}
SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){
@@ -1269,11 +1271,11 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
if (isa<UnknownSpaceRegion>(MS) ||
isa<StackArgumentsSpaceRegion>(MS))
- return ValMgr.getRegionValueSymbolVal(R, T);
+ return ValMgr.getRegionValueSymbolVal(R);
if (isa<GlobalsSpaceRegion>(MS)) {
if (VD->isFileVarDecl())
- return ValMgr.getRegionValueSymbolVal(R, T);
+ return ValMgr.getRegionValueSymbolVal(R);
if (T->isIntegerType())
return ValMgr.makeIntVal(0, T);
@@ -1291,7 +1293,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
QualType valTy = R->getValueType(getContext());
// All other values are symbolic.
- return ValMgr.getRegionValueSymbolVal(R, valTy);
+ return ValMgr.getRegionValueSymbolVal(R);
}
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
diff --git a/lib/Checker/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp
index 40bdcf6..f2d630c 100644
--- a/lib/Checker/SymbolManager.cpp
+++ b/lib/Checker/SymbolManager.cpp
@@ -14,6 +14,7 @@
#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -78,14 +79,14 @@ void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const {
}
const SymbolRegionValue*
-SymbolManager::getRegionValueSymbol(const MemRegion* R, QualType T) {
+SymbolManager::getRegionValueSymbol(const TypedRegion* R) {
llvm::FoldingSetNodeID profile;
- SymbolRegionValue::Profile(profile, R, T);
+ SymbolRegionValue::Profile(profile, R);
void* InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
- new (SD) SymbolRegionValue(SymbolCounter, R, T);
+ new (SD) SymbolRegionValue(SymbolCounter, R);
DataSet.InsertNode(SD, InsertPos);
++SymbolCounter;
}
@@ -175,13 +176,7 @@ QualType SymbolDerived::getType(ASTContext& Ctx) const {
}
QualType SymbolRegionValue::getType(ASTContext& C) const {
- if (!T.isNull())
- return T;
-
- if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
- return TR->getValueType(C);
-
- return QualType();
+ return R->getValueType(C);
}
SymbolManager::~SymbolManager() {}
@@ -222,7 +217,11 @@ bool SymbolReaper::isLive(SymbolRef 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;
+
+ if (SFC == CurrentStackFrame)
+ return Liveness.isLive(Loc, VR->getDecl());
+ else
+ return SFC->isParentOf(CurrentStackFrame);
}
SymbolVisitor::~SymbolVisitor() {}
diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp
new file mode 100644
index 0000000..7ff817a
--- /dev/null
+++ b/lib/Checker/UnixAPIChecker.cpp
@@ -0,0 +1,154 @@
+//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UnixAPIChecker, which is an assortment of checks on calls
+// to various, widely used UNIX/Posix functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "GRExprEngineInternalChecks.h"
+#include <fcntl.h>
+
+using namespace clang;
+
+namespace {
+class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
+ enum SubChecks {
+ OpenFn = 0,
+ NumChecks
+ };
+
+ BugType *BTypes[NumChecks];
+
+public:
+ UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
+ static void *getTag() { static unsigned tag = 0; return &tag; }
+
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} //end anonymous namespace
+
+void clang::RegisterUnixAPIChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UnixAPIChecker());
+}
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+static inline void LazyInitialize(BugType *&BT, const char *name) {
+ if (BT)
+ return;
+ BT = new BugType(name, "Unix API");
+}
+
+//===----------------------------------------------------------------------===//
+// "open" (man 2 open)
+//===----------------------------------------------------------------------===//
+
+static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
+ LazyInitialize(BT, "Improper use of 'open'");
+
+ // Look at the 'oflags' argument for the O_CREAT flag.
+ const GRState *state = C.getState();
+
+ if (CE->getNumArgs() < 2) {
+ // The frontend should issue a warning for this case, so this is a sanity
+ // check.
+ return;
+ }
+
+ // Now check if oflags has O_CREAT set.
+ const Expr *oflagsEx = CE->getArg(1);
+ const SVal V = state->getSVal(oflagsEx);
+ if (!isa<NonLoc>(V)) {
+ // The case where 'V' can be a location can only be due to a bad header,
+ // so in this case bail out.
+ return;
+ }
+ NonLoc oflags = cast<NonLoc>(V);
+ NonLoc ocreateFlag =
+ cast<NonLoc>(C.getValueManager().makeIntVal((uint64_t) O_CREAT,
+ oflagsEx->getType()));
+ SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And,
+ oflags, ocreateFlag,
+ oflagsEx->getType());
+ if (maskedFlagsUC.isUnknownOrUndef())
+ return;
+ DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);
+
+ // Check if maskedFlags is non-zero.
+ const GRState *trueState, *falseState;
+ llvm::tie(trueState, falseState) = state->Assume(maskedFlags);
+
+ // Only emit an error if the value of 'maskedFlags' is properly
+ // constrained;
+ if (!(trueState && !falseState))
+ return;
+
+ if (CE->getNumArgs() < 3) {
+ ExplodedNode *N = C.GenerateSink(trueState);
+ if (!N)
+ return;
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT,
+ "Call to 'open' requires a third argument when "
+ "the 'O_CREAT' flag is set", N);
+ report->addRange(oflagsEx->getSourceRange());
+ C.EmitReport(report);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Central dispatch function.
+//===----------------------------------------------------------------------===//
+
+typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT);
+namespace {
+ class SubCheck {
+ SubChecker SC;
+ BugType **BT;
+ public:
+ SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
+ SubCheck() : SC(NULL), BT(NULL) {}
+
+ void run(CheckerContext &C, const CallExpr *CE) const {
+ if (SC)
+ SC(C, CE, *BT);
+ }
+ };
+} // end anonymous namespace
+
+void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+ // Get the callee. All the functions we care about are C functions
+ // with simple identifiers.
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ const FunctionTextRegion *Fn =
+ dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
+
+ if (!Fn)
+ return;
+
+ const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
+ if (!FI)
+ return;
+
+ const SubCheck &SC =
+ llvm::StringSwitch<SubCheck>(FI->getName())
+ .Case("open", SubCheck(CheckOpen, BTypes[OpenFn]))
+ .Default(SubCheck());
+
+ SC.run(C, CE);
+}
diff --git a/lib/Checker/ValueManager.cpp b/lib/Checker/ValueManager.cpp
index 5359489..aa0c3c8 100644
--- a/lib/Checker/ValueManager.cpp
+++ b/lib/Checker/ValueManager.cpp
@@ -70,18 +70,14 @@ SVal ValueManager::convertToArrayIndex(SVal V) {
return SVator->EvalCastNL(cast<NonLoc>(V), ArrayIndexTy);
}
-DefinedOrUnknownSVal ValueManager::getRegionValueSymbolVal(const MemRegion* R,
- QualType T) {
-
- if (T.isNull()) {
- const TypedRegion* TR = cast<TypedRegion>(R);
- T = TR->getValueType(SymMgr.getContext());
- }
+DefinedOrUnknownSVal
+ValueManager::getRegionValueSymbolVal(const TypedRegion* R) {
+ QualType T = R->getValueType(SymMgr.getContext());
if (!SymbolManager::canSymbolicate(T))
return UnknownVal();
- SymbolRef sym = SymMgr.getRegionValueSymbol(R, T);
+ SymbolRef sym = SymMgr.getRegionValueSymbol(R);
if (Loc::IsLocType(T))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
OpenPOWER on IntegriCloud