summaryrefslogtreecommitdiffstats
path: root/lib/Analysis
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-11-04 15:04:32 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-11-04 15:04:32 +0000
commitb6d5e15aae202f157c6cd63da8fa4b089e7b31e9 (patch)
tree59e0e47a9831dcf0e21e547927c8ebb7e113bfd1 /lib/Analysis
parent5563df30b9c8d1fe87a54baae0d6bd86642563f4 (diff)
downloadFreeBSD-src-b6d5e15aae202f157c6cd63da8fa4b089e7b31e9.zip
FreeBSD-src-b6d5e15aae202f157c6cd63da8fa4b089e7b31e9.tar.gz
Update clang to r86025.
Diffstat (limited to 'lib/Analysis')
-rw-r--r--lib/Analysis/AttrNonNullChecker.cpp100
-rw-r--r--lib/Analysis/BadCallChecker.cpp44
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp1
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.h1
-rw-r--r--lib/Analysis/BasicStore.cpp26
-rw-r--r--lib/Analysis/CFRefCount.cpp34
-rw-r--r--lib/Analysis/CMakeLists.txt10
-rw-r--r--lib/Analysis/CallGraph.cpp4
-rw-r--r--lib/Analysis/CheckObjCUnusedIVars.cpp35
-rw-r--r--lib/Analysis/DereferenceChecker.cpp112
-rw-r--r--lib/Analysis/DivZeroChecker.cpp70
-rw-r--r--lib/Analysis/GRExprEngine.cpp391
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp390
-rw-r--r--lib/Analysis/NSAutoreleasePoolChecker.cpp84
-rw-r--r--lib/Analysis/NSErrorChecker.cpp (renamed from lib/Analysis/CheckNSError.cpp)31
-rw-r--r--lib/Analysis/RegionStore.cpp39
-rw-r--r--lib/Analysis/UndefinedArgChecker.cpp43
-rw-r--r--lib/Analysis/UndefinedAssignmentChecker.cpp61
-rw-r--r--lib/Analysis/VLASizeChecker.cpp102
19 files changed, 928 insertions, 650 deletions
diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp
new file mode 100644
index 0000000..1cf5d0c
--- /dev/null
+++ b/lib/Analysis/AttrNonNullChecker.cpp
@@ -0,0 +1,100 @@
+//===--- AttrNonNullChecker.h - Undefined arguments checker ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines AttrNonNullChecker, a builtin check in GRExprEngine that
+// performs checks for arguments declared to have nonnull attribute.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *AttrNonNullChecker::getTag() {
+ static int x = 0;
+ return &x;
+}
+
+void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const GRState *originalState = state;
+
+ // Check if the callee has a 'nonnull' attribute.
+ SVal X = state->getSVal(CE->getCallee());
+
+ const FunctionDecl* FD = X.getAsFunctionDecl();
+ if (!FD)
+ return;
+
+ const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
+ if (!Att)
+ return;
+
+ // Iterate through the arguments of CE and check them for null.
+ unsigned idx = 0;
+
+ for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
+ ++I, ++idx) {
+
+ if (!Att->isNonNull(idx))
+ continue;
+
+ const SVal &V = state->getSVal(*I);
+ const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
+
+ if (!DV)
+ continue;
+
+ ConstraintManager &CM = C.getConstraintManager();
+ const GRState *stateNotNull, *stateNull;
+ llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);
+
+ if (stateNull && !stateNotNull) {
+ // Generate an error node. Check for a null node in case
+ // we cache out.
+ if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) {
+
+ // Lazily allocate the BugType object if it hasn't already been
+ // created. Ownership is transferred to the BugReporter object once
+ // the BugReport is passed to 'EmitWarning'.
+ if (!BT)
+ BT = new BugType("Argument with 'nonnull' attribute passed null",
+ "API");
+
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT,
+ "Null pointer passed as an argument to a "
+ "'nonnull' parameter", errorNode);
+
+ // Highlight the range of the argument that was null.
+ const Expr *arg = *I;
+ R->addRange(arg->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);
+
+ // Emit the bug report.
+ C.EmitReport(R);
+ }
+
+ // Always return. Either we cached out or we just emitted an error.
+ return;
+ }
+
+ // If a pointer value passed the check we should assume that it is
+ // indeed not null from this point forward.
+ assert(stateNotNull);
+ state = stateNotNull;
+ }
+
+ // If we reach here all of the arguments passed the nonnull check.
+ // If 'state' has been updated generated a new node.
+ if (state != originalState)
+ C.addTransition(C.GenerateNode(CE, state));
+}
diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp
new file mode 100644
index 0000000..33bb515
--- /dev/null
+++ b/lib/Analysis/BadCallChecker.cpp
@@ -0,0 +1,44 @@
+//===--- BadCallChecker.h - Bad call checker --------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines BadCallChecker, a builtin check in GRExprEngine that performs
+// checks for bad callee at call sites.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *BadCallChecker::getTag() {
+ static int x = 0;
+ return &x;
+}
+
+void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+ const Expr *Callee = CE->getCallee()->IgnoreParens();
+ SVal L = C.getState()->getSVal(Callee);
+
+ if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
+ if (ExplodedNode *N = C.GenerateNode(CE, true)) {
+ if (!BT)
+ BT = new BuiltinBug(0, "Invalid function call",
+ "Called function pointer is a null or undefined pointer value");
+
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
+
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetCalleeExpr(N));
+
+ C.EmitReport(R);
+ }
+ }
+}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index aa2d0ab..4781d5e 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -535,4 +535,5 @@ void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass);
RegisterNSErrorChecks(BR, Eng, D);
+ RegisterNSAutoreleasePoolChecks(Eng);
}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h
index 1271ae4..ea4d3ec 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.h
+++ b/lib/Analysis/BasicObjCFoundationChecks.h
@@ -42,6 +42,7 @@ GRSimpleAPICheck *CreateAuditCFRetainRelease(ASTContext& Ctx,
BugReporter& BR);
void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D);
+void RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng);
} // end clang namespace
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index d81d83c..888af9b 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -92,19 +92,17 @@ public:
void iterBindings(Store store, BindingsHandler& f);
- const GRState *BindDecl(const GRState *state, const VarDecl *VD,
- const LocationContext *LC, SVal InitVal) {
- return state->makeWithStore(BindDeclInternal(state->getStore(),VD, LC,
+ const GRState *BindDecl(const GRState *state, const VarRegion *VR,
+ SVal InitVal) {
+ return state->makeWithStore(BindDeclInternal(state->getStore(), VR,
&InitVal));
}
- const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl *VD,
- const LocationContext *LC) {
- return state->makeWithStore(BindDeclInternal(state->getStore(), VD, LC, 0));
+ const GRState *BindDeclWithNoInit(const GRState *state, const VarRegion *VR) {
+ return state->makeWithStore(BindDeclInternal(state->getStore(), VR, 0));
}
- Store BindDeclInternal(Store store, const VarDecl *VD,
- const LocationContext *LC, SVal *InitVal);
+ Store BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal);
static inline BindingsTy GetBindings(Store store) {
return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
@@ -532,11 +530,11 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
return St;
}
-Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
- const LocationContext *LC,
+Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
SVal* InitVal) {
BasicValueFactory& BasicVals = StateMgr.getBasicVals();
+ const VarDecl *VD = VR->getDecl();
// BasicStore does not model arrays and structs.
if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
@@ -564,16 +562,16 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
if (!InitVal) {
QualType T = VD->getType();
if (Loc::IsLocType(T))
- store = BindInternal(store, getLoc(VD, LC),
+ store = BindInternal(store, loc::MemRegionVal(VR),
loc::ConcreteInt(BasicVals.getValue(0, T)));
else if (T->isIntegerType())
- store = BindInternal(store, getLoc(VD, LC),
+ store = BindInternal(store, loc::MemRegionVal(VR),
nonloc::ConcreteInt(BasicVals.getValue(0, T)));
else {
// assert(0 && "ignore other types of variables");
}
} else {
- store = BindInternal(store, getLoc(VD, LC), *InitVal);
+ store = BindInternal(store, loc::MemRegionVal(VR), *InitVal);
}
}
} else {
@@ -581,7 +579,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
QualType T = VD->getType();
if (ValMgr.getSymbolManager().canSymbolicate(T)) {
SVal V = InitVal ? *InitVal : UndefinedVal();
- store = BindInternal(store, getLoc(VD, LC), V);
+ store = BindInternal(store, loc::MemRegionVal(VR), V);
}
}
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index c629ad1..03614e8 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -193,20 +193,6 @@ public:
} // end anonymous namespace
//===----------------------------------------------------------------------===//
-// Selector creation functions.
-//===----------------------------------------------------------------------===//
-
-static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
- IdentifierInfo* II = &Ctx.Idents.get(name);
- return Ctx.Selectors.getSelector(0, &II);
-}
-
-static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
- IdentifierInfo* II = &Ctx.Idents.get(name);
- return Ctx.Selectors.getSelector(1, &II);
-}
-
-//===----------------------------------------------------------------------===//
// Type querying functions.
//===----------------------------------------------------------------------===//
@@ -1031,11 +1017,25 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// Eventually this can be improved by recognizing that the pixel
// buffer passed to CVPixelBufferCreateWithBytes is released via
// a callback and doing full IPA to make sure this is done correctly.
+ // FIXME: This function has an out parameter that returns an
+ // allocated object.
ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking);
S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
DoNothing);
}
break;
+
+ case 29:
+ if (!memcmp(FName, "CGBitmapContextCreateWithData", 29)) {
+ // FIXES: <rdar://problem/7358899>
+ // Eventually this can be improved by recognizing that 'releaseInfo'
+ // passed to CGBitmapContextCreateWithData is released via
+ // a callback and doing full IPA to make sure this is done correctly.
+ ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
+ DoNothing,DoNothing);
+ }
+ break;
case 32:
if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) {
@@ -1899,7 +1899,7 @@ public:
virtual ~CFRefCount() {}
- void RegisterChecks(BugReporter &BR);
+ void RegisterChecks(GRExprEngine &Eng);
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {
Printers.push_back(new BindingsPrinter());
@@ -2193,7 +2193,9 @@ namespace {
};
} // end anonymous namespace
-void CFRefCount::RegisterChecks(BugReporter& BR) {
+void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
+ BugReporter &BR = Eng.getBugReporter();
+
useAfterRelease = new UseAfterRelease(this);
BR.Register(useAfterRelease);
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 89c1783..cd4697f 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -3,6 +3,8 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangAnalysis
AnalysisContext.cpp
AnalysisManager.cpp
+ AttrNonNullChecker.cpp
+ BadCallChecker.cpp
BasicConstraintManager.cpp
BasicObjCFoundationChecks.cpp
BasicStore.cpp
@@ -14,11 +16,12 @@ add_clang_library(clangAnalysis
CallGraph.cpp
CallInliner.cpp
CheckDeadStores.cpp
- CheckNSError.cpp
CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp
CheckObjCUnusedIVars.cpp
CheckSecuritySyntaxOnly.cpp
+ DereferenceChecker.cpp
+ DivZeroChecker.cpp
Environment.cpp
ExplodedGraph.cpp
GRBlockCounter.cpp
@@ -28,6 +31,8 @@ add_clang_library(clangAnalysis
GRState.cpp
LiveVariables.cpp
MemRegion.cpp
+ NSAutoreleasePoolChecker.cpp
+ NSErrorChecker.cpp
PathDiagnostic.cpp
RangeConstraintManager.cpp
RegionStore.cpp
@@ -37,8 +42,11 @@ add_clang_library(clangAnalysis
SimpleSValuator.cpp
Store.cpp
SymbolManager.cpp
+ UndefinedArgChecker.cpp
+ UndefinedAssignmentChecker.cpp
UninitializedValues.cpp
ValueManager.cpp
+ VLASizeChecker.cpp
)
add_dependencies(clangAnalysis ClangDiagnosticAnalysis)
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index ae8845d..17dc068 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -68,10 +68,8 @@ CallGraph::~CallGraph() {
}
}
-void CallGraph::addTU(ASTUnit &AST) {
- ASTContext &Ctx = AST.getASTContext();
+void CallGraph::addTU(ASTContext& Ctx) {
DeclContext *DC = Ctx.getTranslationUnitDecl();
-
for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
I != E; ++I) {
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp
index 1a900f8..2d9b531 100644
--- a/lib/Analysis/CheckObjCUnusedIVars.cpp
+++ b/lib/Analysis/CheckObjCUnusedIVars.cpp
@@ -62,6 +62,29 @@ static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
I->second = Used;
}
+static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
+ // Scan the methods for accesses.
+ 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)) {
+ // 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 ;
+ CD = CD->getNextClassCategory()) {
+ if (const ObjCCategoryImplDecl *CID = CD->getImplementation())
+ Scan(M, CID);
+ }
+ }
+}
+
void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
BugReporter &BR) {
@@ -88,16 +111,8 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
if (M.empty())
return;
- // Now scan the methods for accesses.
- for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
- E = D->instmeth_end(); I!=E; ++I)
- Scan(M, (*I)->getBody());
-
- // Scan for @synthesized property methods that act as setters/getters
- // to an ivar.
- for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(),
- E = D->propimpl_end(); I!=E; ++I)
- Scan(M, *I);
+ // Now scan the implementation declaration.
+ Scan(M, D);
// Find ivars that are unused.
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp
new file mode 100644
index 0000000..33c85d5
--- /dev/null
+++ b/lib/Analysis/DereferenceChecker.cpp
@@ -0,0 +1,112 @@
+//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NullDerefChecker, a builtin check in GRExprEngine that performs
+// checks for null pointers at loads and stores.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *NullDerefChecker::getTag() {
+ static int x = 0;
+ return &x;
+}
+
+ExplodedNode *NullDerefChecker::CheckLocation(const Stmt *S, ExplodedNode *Pred,
+ const GRState *state, SVal V,
+ GRExprEngine &Eng) {
+ Loc *LV = dyn_cast<Loc>(&V);
+
+ // If the value is not a location, don't touch the node.
+ if (!LV)
+ return Pred;
+
+ const GRState *NotNullState = state->Assume(*LV, true);
+ const GRState *NullState = state->Assume(*LV, false);
+
+ GRStmtNodeBuilder &Builder = Eng.getBuilder();
+ BugReporter &BR = Eng.getBugReporter();
+
+ // The explicit NULL case.
+ if (NullState) {
+ // Use the GDM to mark in the state what lval was null.
+ const SVal *PersistentLV = Eng.getBasicVals().getPersistentSVal(*LV);
+ NullState = NullState->set<GRState::NullDerefTag>(PersistentLV);
+
+ ExplodedNode *N = Builder.generateNode(S, NullState, Pred,
+ ProgramPoint::PostNullCheckFailedKind);
+ if (N) {
+ N->markAsSink();
+
+ if (!NotNullState) { // Explicit null case.
+ if (!BT)
+ BT = new BuiltinBug(NULL, "Null dereference",
+ "Dereference of null pointer");
+
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
+
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDerefExpr(N));
+
+ BR.EmitReport(R);
+
+ return 0;
+ } else // Implicit null case.
+ ImplicitNullDerefNodes.push_back(N);
+ }
+ }
+
+ if (!NotNullState)
+ return 0;
+
+ return Builder.generateNode(S, NotNullState, Pred,
+ ProgramPoint::PostLocationChecksSucceedKind);
+}
+
+
+void *UndefDerefChecker::getTag() {
+ static int x = 0;
+ return &x;
+}
+
+ExplodedNode *UndefDerefChecker::CheckLocation(const Stmt *S,
+ ExplodedNode *Pred,
+ const GRState *state, SVal V,
+ GRExprEngine &Eng) {
+ GRStmtNodeBuilder &Builder = Eng.getBuilder();
+ BugReporter &BR = Eng.getBugReporter();
+
+ if (V.isUndef()) {
+ ExplodedNode *N = Builder.generateNode(S, state, Pred,
+ ProgramPoint::PostUndefLocationCheckFailedKind);
+ if (N) {
+ N->markAsSink();
+
+ if (!BT)
+ BT = new BuiltinBug(0, "Undefined dereference",
+ "Dereference of undefined pointer value");
+
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDerefExpr(N));
+ BR.EmitReport(R);
+ }
+ return 0;
+ }
+
+ return Pred;
+}
+
diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp
new file mode 100644
index 0000000..9c2359f
--- /dev/null
+++ b/lib/Analysis/DivZeroChecker.cpp
@@ -0,0 +1,70 @@
+//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines DivZeroChecker, a builtin check in GRExprEngine that performs
+// checks for division by zeros.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h"
+
+using namespace clang;
+
+void *DivZeroChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ BinaryOperator::Opcode Op = B->getOpcode();
+ if (Op != BinaryOperator::Div &&
+ Op != BinaryOperator::Rem &&
+ Op != BinaryOperator::DivAssign &&
+ Op != BinaryOperator::RemAssign)
+ return;
+
+ if (!B->getRHS()->getType()->isIntegerType() ||
+ !B->getRHS()->getType()->isScalarType())
+ return;
+
+ SVal Denom = C.getState()->getSVal(B->getRHS());
+ const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
+
+ // Divide-by-undefined handled in the generic checking for uses of
+ // undefined values.
+ if (!DV)
+ return;
+
+ // Check for divide by zero.
+ ConstraintManager &CM = C.getConstraintManager();
+ const GRState *stateNotZero, *stateZero;
+ llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV);
+
+ if (stateZero && !stateNotZero) {
+ if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) {
+ if (!BT)
+ BT = new BuiltinBug(0, "Division by zero");
+
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
+
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDenomExpr(N));
+
+ C.EmitReport(R);
+ }
+ return;
+ }
+
+ // If we get here, then the denom should not be zero. We abandon the implicit
+ // zero denom case for now.
+ if (stateNotZero != C.getState())
+ C.addTransition(C.GenerateNode(B, stateNotZero));
+}
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index ea0255d..c71882e 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -25,6 +25,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/StringSwitch.h"
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
@@ -117,17 +118,18 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
- for (std::vector<Checker*>::iterator I = Checkers.begin(), E = Checkers.end();
- I != E; ++I) {
-
- ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+ {
+ ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
: (PrevSet == &Tmp) ? &Src : &Tmp;
+
CurrSet->clear();
- Checker *checker = *I;
+ void *tag = I->first;
+ Checker *checker = I->second;
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
NI != NE; ++NI)
- checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, isPrevisit);
+ checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
// Update which NodeSet is the current one.
PrevSet = CurrSet;
@@ -137,6 +139,41 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
// automatically.
}
+// FIXME: This is largely copy-paste from CheckerVisit(). Need to
+// unify.
+void GRExprEngine::CheckerVisitBind(Stmt *S, ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src,
+ SVal location, SVal val, bool isPrevisit) {
+
+ if (Checkers.empty()) {
+ Dst = Src;
+ return;
+ }
+
+ ExplodedNodeSet Tmp;
+ ExplodedNodeSet *PrevSet = &Src;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+ {
+ ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
+ : (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)
+ checker->GR_VisitBind(*CurrSet, *Builder, *this, S, *NI, tag, location,
+ val, isPrevisit);
+
+ // Update which NodeSet is the current one.
+ PrevSet = CurrSet;
+ }
+
+ // Don't autotransition. The CheckerContext objects should do this
+ // automatically.
+}
//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
@@ -165,9 +202,8 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr)
GRExprEngine::~GRExprEngine() {
BR.FlushReports();
delete [] NSExceptionInstanceRaiseSelectors;
- for (std::vector<Checker*>::iterator I=Checkers.begin(), E=Checkers.end();
- I!=E; ++I)
- delete *I;
+ for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
+ delete I->second;
}
//===----------------------------------------------------------------------===//
@@ -177,7 +213,7 @@ GRExprEngine::~GRExprEngine() {
void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
StateMgr.TF = tf;
- tf->RegisterChecks(getBugReporter());
+ tf->RegisterChecks(*this);
tf->RegisterPrinters(getStateManager().Printers);
}
@@ -369,11 +405,11 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
- VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
+ VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false);
EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
}
else
- VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst, false);
break;
}
@@ -395,7 +431,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
}
case Stmt::CompoundAssignOperatorClass:
- VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst, false);
break;
case Stmt::CompoundLiteralExprClass:
@@ -409,7 +445,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
}
case Stmt::DeclRefExprClass:
- case Stmt::QualifiedDeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false);
break;
@@ -522,7 +557,6 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
return;
case Stmt::DeclRefExprClass:
- case Stmt::QualifiedDeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
return;
@@ -565,6 +599,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
return;
}
+ case Stmt::BinaryOperatorClass:
+ case Stmt::CompoundAssignOperatorClass:
+ VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true);
+ return;
+
default:
// Arbitrary subexpressions can return aggregate temporaries that
// can be used in a lvalue context. We need to enhance our support
@@ -1078,8 +1117,7 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred,
SVal L = state->getLValue(Field, state->getSVal(Base));
if (asLValue)
- MakeNode(Dst, M, *I, state->BindExpr(M, L),
- ProgramPoint::PostLValueKind);
+ MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind);
else
EvalLoad(Dst, M, *I, state, L);
}
@@ -1087,30 +1125,52 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred,
/// EvalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by EvalStore and (soon) VisitDeclStmt, and others.
-void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
- const GRState* state, SVal location, SVal Val) {
+void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred,
+ const GRState* state, SVal location, SVal Val,
+ bool atDeclInit) {
+
+
+ // Do a previsit of the bind.
+ ExplodedNodeSet CheckedSet, Src;
+ Src.Add(Pred);
+ CheckerVisitBind(Ex, CheckedSet, Src, location, Val, true);
+
+ for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+ I!=E; ++I) {
+
+ if (Pred != *I)
+ state = GetState(*I);
+
+ const GRState* newState = 0;
- const GRState* newState = 0;
+ if (atDeclInit) {
+ const VarRegion *VR =
+ cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
- if (location.isUnknown()) {
- // We know that the new state will be the same as the old state since
- // the location of the binding is "unknown". Consequently, there
- // is no reason to just create a new node.
- newState = state;
- }
- else {
- // We are binding to a value other than 'unknown'. Perform the binding
- // using the StoreManager.
- newState = state->bindLoc(cast<Loc>(location), Val);
- }
+ newState = state->bindDecl(VR, Val);
+ }
+ else {
+ if (location.isUnknown()) {
+ // We know that the new state will be the same as the old state since
+ // the location of the binding is "unknown". Consequently, there
+ // is no reason to just create a new node.
+ newState = state;
+ }
+ else {
+ // We are binding to a value other than 'unknown'. Perform the binding
+ // using the StoreManager.
+ newState = state->bindLoc(cast<Loc>(location), Val);
+ }
+ }
- // The next thing to do is check if the GRTransferFuncs object wants to
- // update the state based on the new binding. If the GRTransferFunc object
- // doesn't do anything, just auto-propagate the current state.
- GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, Pred, newState, Ex,
- newState != state);
+ // The next thing to do is check if the GRTransferFuncs object wants to
+ // update the state based on the new binding. If the GRTransferFunc object
+ // doesn't do anything, just auto-propagate the current state.
+ GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, Ex,
+ newState != state);
- getTF().EvalBind(BuilderRef, location, Val);
+ getTF().EvalBind(BuilderRef, location, Val);
+ }
}
/// EvalStore - Handle the semantics of a store via an assignment.
@@ -1189,58 +1249,18 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,
SaveAndRestore<const void*> OldTag(Builder->Tag);
Builder->Tag = tag;
- // Check for loads/stores from/to undefined values.
- if (location.isUndef()) {
- ExplodedNode* N =
- Builder->generateNode(Ex, state, Pred,
- ProgramPoint::PostUndefLocationCheckFailedKind);
-
- if (N) {
- N->markAsSink();
- UndefDeref.insert(N);
- }
-
- return 0;
- }
-
- // Check for loads/stores from/to unknown locations. Treat as No-Ops.
- if (location.isUnknown())
+ if (location.isUnknown() || Checkers.empty())
return Pred;
- // During a load, one of two possible situations arise:
- // (1) A crash, because the location (pointer) was NULL.
- // (2) The location (pointer) is not NULL, and the dereference works.
- //
- // We add these assumptions.
-
- Loc LV = cast<Loc>(location);
-
- // "Assume" that the pointer is not NULL.
- const GRState *StNotNull = state->Assume(LV, true);
-
- // "Assume" that the pointer is NULL.
- const GRState *StNull = state->Assume(LV, false);
-
- if (StNull) {
- // Use the Generic Data Map to mark in the state what lval was null.
- const SVal* PersistentLV = getBasicVals().getPersistentSVal(LV);
- StNull = StNull->set<GRState::NullDerefTag>(PersistentLV);
-
- // We don't use "MakeNode" here because the node will be a sink
- // and we have no intention of processing it later.
- ExplodedNode* NullNode =
- Builder->generateNode(Ex, StNull, Pred,
- ProgramPoint::PostNullCheckFailedKind);
-
- if (NullNode) {
- NullNode->markAsSink();
- if (StNotNull) ImplicitNullDeref.insert(NullNode);
- else ExplicitNullDeref.insert(NullNode);
- }
+
+ for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
+ {
+ Pred = I->second->CheckLocation(Ex, Pred, state, location, *this);
+ if (!Pred)
+ break;
}
-
- if (!StNotNull)
- return NULL;
+
+ return Pred;
// FIXME: Temporarily disable out-of-bounds checking until we make
// the logic reflect recent changes to CastRegion and friends.
@@ -1283,10 +1303,6 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,
}
}
#endif
-
- // Generate a new node indicating the checks succeed.
- return Builder->generateNode(Ex, StNotNull, Pred,
- ProgramPoint::PostLocationChecksSucceedKind);
}
//===----------------------------------------------------------------------===//
@@ -1445,75 +1461,30 @@ static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE,
// 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.
- const char* s = FD->getIdentifier()->getNameStart();
-
- switch (FD->getIdentifier()->getLength()) {
- default:
- break;
-
- case 4:
- if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true;
- break;
-
- case 5:
- if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true;
- else if (!memcmp(s, "error", 5)) {
- if (CE->getNumArgs() > 0) {
- SVal X = state->getSVal(*CE->arg_begin());
- // FIXME: use Assume to inspect the possible symbolic value of
- // X. Also check the specific signature of error().
- nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&X);
- if (CI && CI->getValue() != 0)
- Builder->BuildSinks = true;
- }
- }
- break;
-
- case 6:
- if (!memcmp(s, "Assert", 6)) {
- Builder->BuildSinks = true;
- break;
- }
-
- // FIXME: This is just a wrapper around throwing an exception.
- // Eventually inter-procedural analysis should handle this easily.
- if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true;
-
- break;
-
- case 7:
- if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true;
- break;
-
- case 8:
- if (!memcmp(s ,"db_error", 8) ||
- !memcmp(s, "__assert", 8))
- Builder->BuildSinks = true;
- break;
-
- case 12:
- if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true;
- break;
-
- case 13:
- if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true;
- break;
-
- case 14:
- if (!memcmp(s, "dtrace_assfail", 14) ||
- !memcmp(s, "yy_fatal_error", 14))
- Builder->BuildSinks = true;
- break;
-
- case 26:
- if (!memcmp(s, "_XCAssertionFailureHandler", 26) ||
- !memcmp(s, "_DTAssertionFailureHandler", 26) ||
- !memcmp(s, "_TSAssertionFailureHandler", 26))
- Builder->BuildSinks = true;
-
- break;
- }
-
+ 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;
}
}
@@ -2042,24 +2013,27 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
}
}
+ // Handle previsits checks.
+ ExplodedNodeSet Src, DstTmp;
+ Src.Add(Pred);
+ CheckerVisit(ME, DstTmp, Src, 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.
-
unsigned size = Dst.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
-
- EvalObjCMessageExpr(Dst, ME, Pred);
+
+ for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
+ DI!=DE; ++DI)
+ EvalObjCMessageExpr(Dst, ME, *DI);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
-
if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
MakeNode(Dst, ME, Pred, state);
}
@@ -2141,45 +2115,25 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
Tmp.Add(Pred);
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
- unsigned Count = Builder->getCurrentBlockCount();
-
- // Check if 'VD' is a VLA and if so check if has a non-zero size.
- QualType T = getContext().getCanonicalType(VD->getType());
- if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
- // FIXME: Handle multi-dimensional VLAs.
-
- Expr* SE = VLA->getSizeExpr();
- SVal Size_untested = state->getSVal(SE);
-
- if (Size_untested.isUndef()) {
- if (ExplodedNode* N = Builder->generateNode(DS, state, Pred)) {
- N->markAsSink();
- ExplicitBadSizedVLA.insert(N);
- }
- continue;
- }
-
- DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Size_untested);
- const GRState *zeroState = state->Assume(Size, false);
- state = state->Assume(Size, true);
+ ExplodedNode *N = *I;
+ const GRState *state;
+
+ for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end();
+ CI != CE; ++CI) {
+ state = GetState(N);
+ N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()),
+ N, state, DS, *this);
+ if (!N)
+ break;
+ }
- if (zeroState) {
- if (ExplodedNode* N = Builder->generateNode(DS, zeroState, Pred)) {
- N->markAsSink();
- if (state)
- ImplicitBadSizedVLA.insert(N);
- else
- ExplicitBadSizedVLA.insert(N);
- }
- }
+ if (!N)
+ continue;
- if (!state)
- continue;
- }
+ state = GetState(N);
// Decls without InitExpr are not initialized explicitly.
- const LocationContext *LC = (*I)->getLocationContext();
+ const LocationContext *LC = N->getLocationContext();
if (InitEx) {
SVal InitVal = state->getSVal(InitEx);
@@ -2189,20 +2143,15 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
// UnknownVal.
if (InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Count);
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
+ Builder->getCurrentBlockCount());
}
-
- state = state->bindDecl(VD, LC, InitVal);
-
- // The next thing to do is check if the GRTransferFuncs object wants to
- // update the state based on the new binding. If the GRTransferFunc
- // object doesn't do anything, just auto-propagate the current state.
- GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true);
- getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD, LC)),
- InitVal);
+
+ EvalBind(Dst, DS, *I, state, loc::MemRegionVal(state->getRegion(VD, LC)),
+ InitVal, true);
}
else {
- state = state->bindDeclWithNoInit(VD, LC);
+ state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
MakeNode(Dst, DS, *I, state);
}
}
@@ -2752,7 +2701,7 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt* S, ExplodedNode* Pred,
void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
+ ExplodedNodeSet& Dst, bool asLValue) {
ExplodedNodeSet Tmp1;
Expr* LHS = B->getLHS()->IgnoreParens();
@@ -2798,10 +2747,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
unsigned Count = Builder->getCurrentBlockCount();
RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count);
}
-
+
+ SVal ExprVal = asLValue ? LeftV : RightV;
+
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
- EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV), LeftV, RightV);
+ EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV);
continue;
}
@@ -2930,6 +2881,15 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
}
//===----------------------------------------------------------------------===//
+// Checker registration/lookup.
+//===----------------------------------------------------------------------===//
+
+Checker *GRExprEngine::lookupChecker(void *tag) const {
+ CheckerMap::iterator I = CheckerM.find(tag);
+ return (I == CheckerM.end()) ? NULL : Checkers[I->second].second;
+}
+
+//===----------------------------------------------------------------------===//
// Visualization.
//===----------------------------------------------------------------------===//
@@ -2941,7 +2901,8 @@ namespace llvm {
template<>
struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
public DefaultDOTGraphTraits {
-
+ // FIXME: Since we do not cache error nodes in GRExprEngine now, this does not
+ // work.
static std::string getNodeAttributes(const ExplodedNode* N, void*) {
if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index da24192..695f0b0 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -15,6 +15,13 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Compiler.h"
@@ -40,10 +47,8 @@ ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) {
//===----------------------------------------------------------------------===//
// Bug Descriptions.
//===----------------------------------------------------------------------===//
-
-namespace {
-
-class VISIBILITY_HIDDEN BuiltinBugReport : public RangedBugReport {
+namespace clang {
+class BuiltinBugReport : public RangedBugReport {
public:
BuiltinBugReport(BugType& bt, const char* desc,
ExplodedNode *n)
@@ -57,30 +62,10 @@ public:
const ExplodedNode* N);
};
-class VISIBILITY_HIDDEN BuiltinBug : public BugType {
- GRExprEngine &Eng;
-protected:
- const std::string desc;
-public:
- BuiltinBug(GRExprEngine *eng, const char* n, const char* d)
- : BugType(n, "Logic errors"), Eng(*eng), desc(d) {}
-
- BuiltinBug(GRExprEngine *eng, const char* n)
- : BugType(n, "Logic errors"), Eng(*eng), desc(n) {}
-
- const std::string &getDescription() const { return desc; }
-
- virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {}
-
- void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); }
-
- virtual void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {}
-
- template <typename ITER> void Emit(BugReporter& BR, ITER I, ITER E);
-};
-
+void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode* N) {
+ static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
+}
template <typename ITER>
void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) {
@@ -88,27 +73,6 @@ void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) {
GetNode(I)));
}
-void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N) {
- static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
-}
-
-class VISIBILITY_HIDDEN NullDeref : public BuiltinBug {
-public:
- NullDeref(GRExprEngine* eng)
- : BuiltinBug(eng,"Null dereference", "Dereference of null pointer") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end());
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
- }
-};
-
class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
public:
NilReceiverStructRet(GRExprEngine* eng) :
@@ -175,34 +139,6 @@ public:
}
};
-class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug {
-public:
- UndefinedDeref(GRExprEngine* eng)
- : BuiltinBug(eng,"Dereference of undefined pointer value") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- Emit(BR, Eng.undef_derefs_begin(), Eng.undef_derefs_end());
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
- }
-};
-
-class VISIBILITY_HIDDEN DivZero : public BuiltinBug {
-public:
- DivZero(GRExprEngine* eng = 0)
- : BuiltinBug(eng,"Division by zero") {}
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetDenomExpr(N), N);
- }
-};
-
class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
public:
UndefResult(GRExprEngine* eng)
@@ -279,20 +215,6 @@ public:
}
};
-class VISIBILITY_HIDDEN BadCall : public BuiltinBug {
-public:
- BadCall(GRExprEngine *eng = 0)
- : BuiltinBug(eng, "Invalid function call",
- "Called function pointer is a null or undefined pointer value") {}
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetCalleeExpr(N), N);
- }
-};
-
-
class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport {
const Stmt *Arg;
public:
@@ -528,276 +450,8 @@ public:
}
};
-class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug {
-public:
- BadSizeVLA(GRExprEngine* eng) :
- BuiltinBug(eng, "Bad variable-length array (VLA) size") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::ErrorNodes::iterator
- I = Eng.ExplicitBadSizedVLA.begin(),
- E = Eng.ExplicitBadSizedVLA.end(); I!=E; ++I) {
-
- // Determine whether this was a 'zero-sized' VLA or a VLA with an
- // undefined size.
- ExplodedNode* N = *I;
- PostStmt PS = cast<PostStmt>(N->getLocation());
- const DeclStmt *DS = cast<DeclStmt>(PS.getStmt());
- VarDecl* VD = cast<VarDecl>(*DS->decl_begin());
- QualType T = Eng.getContext().getCanonicalType(VD->getType());
- VariableArrayType* VT = cast<VariableArrayType>(T);
- Expr* SizeExpr = VT->getSizeExpr();
-
- std::string buf;
- llvm::raw_string_ostream os(buf);
- os << "The expression used to specify the number of elements in the "
- "variable-length array (VLA) '"
- << VD->getNameAsString() << "' evaluates to ";
-
- bool isUndefined = N->getState()->getSVal(SizeExpr).isUndef();
-
- if (isUndefined)
- os << "an undefined or garbage value.";
- else
- os << "0. VLAs with no elements have undefined behavior.";
-
- std::string shortBuf;
- llvm::raw_string_ostream os_short(shortBuf);
- os_short << "Variable-length array '" << VD->getNameAsString() << "' "
- << (isUndefined ? "garbage value for array size"
- : "has zero elements (undefined behavior)");
-
- ArgReport *report = new ArgReport(*this, os_short.str().c_str(),
- os.str().c_str(), N, SizeExpr);
-
- report->addRange(SizeExpr->getSourceRange());
- BR.EmitReport(report);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
- N);
- }
-};
-
-//===----------------------------------------------------------------------===//
-// __attribute__(nonnull) checking
-
-class VISIBILITY_HIDDEN CheckAttrNonNull :
- public CheckerVisitor<CheckAttrNonNull> {
-
- BugType *BT;
-
-public:
- CheckAttrNonNull() : BT(0) {}
- ~CheckAttrNonNull() {}
-
- const void *getTag() {
- static int x = 0;
- return &x;
- }
-
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- const GRState *originalState = state;
-
- // Check if the callee has a 'nonnull' attribute.
- SVal X = state->getSVal(CE->getCallee());
-
- const FunctionDecl* FD = X.getAsFunctionDecl();
- if (!FD)
- return;
+} // end clang namespace
- const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
- if (!Att)
- return;
-
- // Iterate through the arguments of CE and check them for null.
- unsigned idx = 0;
-
- for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
- ++I, ++idx) {
-
- if (!Att->isNonNull(idx))
- continue;
-
- const SVal &V = state->getSVal(*I);
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
-
- if (!DV)
- continue;
-
- ConstraintManager &CM = C.getConstraintManager();
- const GRState *stateNotNull, *stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);
-
- if (stateNull && !stateNotNull) {
- // Generate an error node. Check for a null node in case
- // we cache out.
- if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) {
-
- // Lazily allocate the BugType object if it hasn't already been
- // created. Ownership is transferred to the BugReporter object once
- // the BugReport is passed to 'EmitWarning'.
- if (!BT)
- BT = new BugType("Argument with 'nonnull' attribute passed null",
- "API");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT,
- "Null pointer passed as an argument to a "
- "'nonnull' parameter", errorNode);
-
- // Highlight the range of the argument that was null.
- const Expr *arg = *I;
- R->addRange(arg->getSourceRange());
- R->addVisitorCreator(registerTrackNullOrUndefValue, arg);
-
- // Emit the bug report.
- C.EmitReport(R);
- }
-
- // Always return. Either we cached out or we just emitted an error.
- return;
- }
-
- // If a pointer value passed the check we should assume that it is
- // indeed not null from this point forward.
- assert(stateNotNull);
- state = stateNotNull;
- }
-
- // If we reach here all of the arguments passed the nonnull check.
- // If 'state' has been updated generated a new node.
- if (state != originalState)
- C.addTransition(C.GenerateNode(CE, state));
- }
-};
-} // end anonymous namespace
-
-// Undefined arguments checking.
-namespace {
-class VISIBILITY_HIDDEN CheckUndefinedArg
- : public CheckerVisitor<CheckUndefinedArg> {
-
- BadArg *BT;
-
-public:
- CheckUndefinedArg() : BT(0) {}
- ~CheckUndefinedArg() {}
-
- const void *getTag() {
- static int x = 0;
- return &x;
- }
-
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-
-void CheckUndefinedArg::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE){
- for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I) {
- if (C.getState()->getSVal(*I).isUndef()) {
- if (ExplodedNode *ErrorNode = C.GenerateNode(CE, true)) {
- if (!BT)
- BT = new BadArg();
- // Generate a report for this bug.
- ArgReport *Report = new ArgReport(*BT, BT->getDescription().c_str(),
- ErrorNode, *I);
- Report->addRange((*I)->getSourceRange());
- C.EmitReport(Report);
- }
- }
- }
-}
-
-class VISIBILITY_HIDDEN CheckBadCall : public CheckerVisitor<CheckBadCall> {
- BadCall *BT;
-
-public:
- CheckBadCall() : BT(0) {}
- ~CheckBadCall() {}
-
- const void *getTag() {
- static int x = 0;
- return &x;
- }
-
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-
-void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
- const Expr *Callee = CE->getCallee()->IgnoreParens();
- SVal L = C.getState()->getSVal(Callee);
-
- if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
- if (ExplodedNode *N = C.GenerateNode(CE, true)) {
- if (!BT)
- BT = new BadCall();
- C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
- }
- }
-}
-
-class VISIBILITY_HIDDEN CheckDivZero : public CheckerVisitor<CheckDivZero> {
- DivZero *BT;
-public:
- CheckDivZero() : BT(0) {}
- ~CheckDivZero() {}
-
- const void *getTag() {
- static int x;
- return &x;
- }
-
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
-};
-
-void CheckDivZero::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
- BinaryOperator::Opcode Op = B->getOpcode();
- if (Op != BinaryOperator::Div &&
- Op != BinaryOperator::Rem &&
- Op != BinaryOperator::DivAssign &&
- Op != BinaryOperator::RemAssign)
- return;
-
- if (!B->getRHS()->getType()->isIntegerType() ||
- !B->getRHS()->getType()->isScalarType())
- return;
-
- SVal Denom = C.getState()->getSVal(B->getRHS());
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
-
- // Divide-by-undefined handled in the generic checking for uses of
- // undefined values.
- if (!DV)
- return;
-
- // Check for divide by zero.
- ConstraintManager &CM = C.getConstraintManager();
- const GRState *stateNotZero, *stateZero;
- llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV);
-
- if (stateZero && !stateNotZero) {
- if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) {
- if (!BT)
- BT = new DivZero();
-
- C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
- }
- return;
- }
-
- // If we get here, then the denom should not be zero. We abandon the implicit
- // zero denom case for now.
- if (stateNotZero != C.getState())
- C.addTransition(C.GenerateNode(B, stateNotZero));
-}
-}
//===----------------------------------------------------------------------===//
// Check registration.
//===----------------------------------------------------------------------===//
@@ -808,8 +462,6 @@ void GRExprEngine::RegisterInternalChecks() {
// create BugReports on-the-fly but instead wait until GRExprEngine finishes
// analyzing a function. Generation of BugReport objects is done via a call
// to 'FlushReports' from BugReporter.
- BR.Register(new NullDeref(this));
- BR.Register(new UndefinedDeref(this));
BR.Register(new UndefBranch(this));
BR.Register(new UndefResult(this));
BR.Register(new RetStack(this));
@@ -817,7 +469,6 @@ void GRExprEngine::RegisterInternalChecks() {
BR.Register(new BadMsgExprArg(this));
BR.Register(new BadReceiver(this));
BR.Register(new OutOfBoundMemoryAccess(this));
- BR.Register(new BadSizeVLA(this));
BR.Register(new NilReceiverStructRet(this));
BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
@@ -826,8 +477,13 @@ void GRExprEngine::RegisterInternalChecks() {
// their associated BugType will get registered with the BugReporter
// automatically. Note that the check itself is owned by the GRExprEngine
// object.
- registerCheck(new CheckAttrNonNull());
- registerCheck(new CheckUndefinedArg());
- registerCheck(new CheckBadCall());
- registerCheck(new CheckDivZero());
+ registerCheck(new AttrNonNullChecker());
+ registerCheck(new UndefinedArgChecker());
+ registerCheck(new UndefinedAssignmentChecker());
+ registerCheck(new BadCallChecker());
+ registerCheck(new DivZeroChecker());
+ registerCheck(new UndefDerefChecker());
+ registerCheck(new NullDerefChecker());
+ registerCheck(new UndefSizedVLAChecker());
+ registerCheck(new ZeroSizedVLAChecker());
}
diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Analysis/NSAutoreleasePoolChecker.cpp
new file mode 100644
index 0000000..e0a8d0d
--- /dev/null
+++ b/lib/Analysis/NSAutoreleasePoolChecker.cpp
@@ -0,0 +1,84 @@
+//=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a NSAutoreleasePoolChecker, a small checker that warns
+// about subpar uses of NSAutoreleasePool. Note that while the check itself
+// (in it's current form) could be written as a flow-insensitive check, in
+// can be potentially enhanced in the future with flow-sensitive information.
+// It is also a good example of the CheckerVisitor interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "BasicObjCFoundationChecks.h"
+#include "llvm/Support/Compiler.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Decl.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN NSAutoreleasePoolChecker
+ : public CheckerVisitor<NSAutoreleasePoolChecker> {
+
+ Selector releaseS;
+
+public:
+ NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {}
+
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+
+ void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+};
+
+} // end anonymous namespace
+
+
+void clang::RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng) {
+ ASTContext &Ctx = Eng.getContext();
+ if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release",
+ Ctx)));
+ }
+}
+
+void
+NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+ const ObjCMessageExpr *ME) {
+
+ const Expr *receiver = ME->getReceiver();
+ if (!receiver)
+ return;
+
+ // FIXME: Enhance with value-tracking information instead of consulting
+ // the type of the expression.
+ const ObjCObjectPointerType* PT =
+ receiver->getType()->getAs<ObjCObjectPointerType>();
+ const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
+ if (!OD)
+ return;
+ if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
+ return;
+
+ // Sending 'release' message?
+ if (ME->getSelector() != releaseS)
+ return;
+
+ SourceRange R = ME->getSourceRange();
+
+ C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
+ "API Upgrade (Apple)",
+ "Use -drain instead of -release when using NSAutoreleasePool "
+ "and garbage collection", ME->getLocStart(), &R, 1);
+}
diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/NSErrorChecker.cpp
index 8086da5..307686f 100644
--- a/lib/Analysis/CheckNSError.cpp
+++ b/lib/Analysis/NSErrorChecker.cpp
@@ -1,4 +1,4 @@
-//=- CheckNSError.cpp - Coding conventions for uses of NSError ---*- C++ -*-==//
+//=- NSErrorCheckerer.cpp - Coding conventions for uses of NSError -*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@@ -18,6 +18,7 @@
#include "clang/Analysis/LocalCheckers.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
#include "BasicObjCFoundationChecks.h"
#include "llvm/Support/Compiler.h"
#include "clang/AST/DeclObjC.h"
@@ -27,7 +28,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN NSErrorCheck : public BugType {
+class VISIBILITY_HIDDEN NSErrorChecker : public BugType {
const Decl &CodeDecl;
const bool isNSErrorWarning;
IdentifierInfo * const II;
@@ -48,7 +49,7 @@ class VISIBILITY_HIDDEN NSErrorCheck : public BugType {
void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl);
public:
- NSErrorCheck(const Decl &D, bool isNSError, GRExprEngine& eng)
+ NSErrorChecker(const Decl &D, bool isNSError, GRExprEngine& eng)
: BugType(isNSError ? "NSError** null dereference"
: "CFErrorRef* null dereference",
"Coding conventions (Apple)"),
@@ -64,11 +65,11 @@ public:
void clang::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng,
const Decl &D) {
- BR.Register(new NSErrorCheck(D, true, Eng));
- BR.Register(new NSErrorCheck(D, false, Eng));
+ BR.Register(new NSErrorChecker(D, true, Eng));
+ BR.Register(new NSErrorChecker(D, false, Eng));
}
-void NSErrorCheck::FlushReports(BugReporter& BR) {
+void NSErrorChecker::FlushReports(BugReporter& BR) {
// Get the analysis engine and the exploded analysis graph.
ExplodedGraph& G = Eng.getGraph();
@@ -99,7 +100,7 @@ void NSErrorCheck::FlushReports(BugReporter& BR) {
}
}
-void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
+void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
@@ -121,7 +122,7 @@ void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
}
void
-NSErrorCheck::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy,
+NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy,
llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
ResultTy = M.getResultType();
@@ -140,7 +141,7 @@ NSErrorCheck::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy,
}
void
-NSErrorCheck::CheckSignature(const FunctionDecl& F, QualType& ResultTy,
+NSErrorChecker::CheckSignature(const FunctionDecl& F, QualType& ResultTy,
llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
ResultTy = F.getResultType();
@@ -159,7 +160,7 @@ NSErrorCheck::CheckSignature(const FunctionDecl& F, QualType& ResultTy,
}
-bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) {
+bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) {
const PointerType* PPT = ArgTy->getAs<PointerType>();
if (!PPT)
@@ -180,7 +181,7 @@ bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) {
return false;
}
-bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
+bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) {
const PointerType* PPT = ArgTy->getAs<PointerType>();
if (!PPT) return false;
@@ -191,7 +192,7 @@ bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
return TT->getDecl()->getIdentifier() == II;
}
-void NSErrorCheck::CheckParamDeref(const VarDecl *Param,
+void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
const LocationContext *LC,
const GRState *rootState,
BugReporter& BR) {
@@ -208,8 +209,10 @@ void NSErrorCheck::CheckParamDeref(const VarDecl *Param,
return;
// Iterate over the implicit-null dereferences.
- for (GRExprEngine::null_deref_iterator I=Eng.implicit_null_derefs_begin(),
- E=Eng.implicit_null_derefs_end(); I!=E; ++I) {
+ NullDerefChecker *Checker = Eng.getChecker<NullDerefChecker>();
+ assert(Checker && "NullDerefChecker not exist.");
+ for (NullDerefChecker::iterator I = Checker->implicit_nodes_begin(),
+ E = Checker->implicit_nodes_end(); I != E; ++I) {
const GRState *state = (*I)->getState();
const SVal* X = state->get<GRState::NullDerefTag>();
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 780772a..dbf8c42 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -275,11 +275,11 @@ public:
const GRState *BindCompoundLiteral(const GRState *state,
const CompoundLiteralExpr* CL, SVal V);
- const GRState *BindDecl(const GRState *ST, const VarDecl *VD,
- const LocationContext *LC, SVal InitVal);
+ const GRState *BindDecl(const GRState *ST, const VarRegion *VR,
+ SVal InitVal);
- const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl*,
- const LocationContext *) {
+ const GRState *BindDeclWithNoInit(const GRState *state,
+ const VarRegion *) {
return state;
}
@@ -1409,12 +1409,10 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
}
const GRState *RegionStoreManager::BindDecl(const GRState *ST,
- const VarDecl *VD,
- const LocationContext *LC,
+ const VarRegion *VR,
SVal InitVal) {
- QualType T = VD->getType();
- VarRegion* VR = MRMgr.getVarRegion(VD, LC);
+ QualType T = VR->getDecl()->getType();
if (T->isArrayType())
return BindArray(ST, VR, InitVal);
@@ -1630,6 +1628,8 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Process the "intermediate" roots to find if they are referenced by
// real roots.
llvm::SmallVector<RBDNode, 10> WorkList;
+ llvm::SmallVector<RBDNode, 10> Postponed;
+
llvm::DenseSet<const MemRegion*> IntermediateVisited;
while (!IntermediateRoots.empty()) {
@@ -1647,8 +1647,11 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
}
if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
- if (SymReaper.isLive(SR->getSymbol()))
- WorkList.push_back(std::make_pair(&state, SR));
+ llvm::SmallVectorImpl<RBDNode> &Q =
+ SymReaper.isLive(SR->getSymbol()) ? WorkList : Postponed;
+
+ Q.push_back(std::make_pair(&state, SR));
+
continue;
}
@@ -1667,6 +1670,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
llvm::DenseSet<RBDNode> Visited;
+tryAgain:
while (!WorkList.empty()) {
RBDNode N = WorkList.back();
WorkList.pop_back();
@@ -1740,6 +1744,21 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
}
}
+ // See if any postponed SymbolicRegions are actually live now, after
+ // having done a scan.
+ for (llvm::SmallVectorImpl<RBDNode>::iterator I = Postponed.begin(),
+ E = Postponed.end() ; I != E ; ++I) {
+ if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(I->second)) {
+ if (SymReaper.isLive(SR->getSymbol())) {
+ WorkList.push_back(*I);
+ I->second = NULL;
+ }
+ }
+ }
+
+ if (!WorkList.empty())
+ goto tryAgain;
+
// We have now scanned the store, marking reachable regions and symbols
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp
new file mode 100644
index 0000000..a229f55
--- /dev/null
+++ b/lib/Analysis/UndefinedArgChecker.cpp
@@ -0,0 +1,43 @@
+//===--- UndefinedArgChecker.h - Undefined arguments checker ----*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines BadCallChecker, a builtin check in GRExprEngine that performs
+// checks for undefined arguments.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *UndefinedArgChecker::getTag() {
+ static int x = 0;
+ return &x;
+}
+
+void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE){
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I) {
+ if (C.getState()->getSVal(*I).isUndef()) {
+ if (ExplodedNode *N = C.GenerateNode(CE, true)) {
+ if (!BT)
+ BT = new BugType("Pass-by-value argument in function call is "
+ "undefined", "Logic error");
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(),
+ N);
+ R->addRange((*I)->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
+ C.EmitReport(R);
+ }
+ }
+ }
+}
diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp
new file mode 100644
index 0000000..c5b2401
--- /dev/null
+++ b/lib/Analysis/UndefinedAssignmentChecker.cpp
@@ -0,0 +1,61 @@
+//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedAssginmentChecker, a builtin check in GRExprEngine that
+// checks for assigning undefined values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *UndefinedAssignmentChecker::getTag() {
+ static int x = 0;
+ return &x;
+}
+
+void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
+ const Stmt *S,
+ SVal location,
+ SVal val) {
+ if (!val.isUndef())
+ return;
+
+ ExplodedNode *N = C.GenerateNode(S, true);
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BugType("Assigned value is garbage or undefined",
+ "Logic error");
+
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N);
+ const Expr *ex = 0;
+
+ // FIXME: This check needs to be done on the expression doing the
+ // assignment, not the "store" expression.
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
+ ex = B->getRHS();
+ else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+ ex = VD->getInit();
+ }
+
+ if (ex) {
+ R->addRange(ex->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
+ }
+
+ C.EmitReport(R);
+}
+
diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp
new file mode 100644
index 0000000..76e4477
--- /dev/null
+++ b/lib/Analysis/VLASizeChecker.cpp
@@ -0,0 +1,102 @@
+//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines two VLASizeCheckers, a builtin check in GRExprEngine that
+// performs checks for declaration of VLA of undefined or zero size.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *UndefSizedVLAChecker::getTag() {
+ static int x = 0;
+ return &x;
+}
+
+ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
+ const GRState *state,
+ Stmt *S, GRExprEngine &Eng) {
+ GRStmtNodeBuilder &Builder = Eng.getBuilder();
+ BugReporter &BR = Eng.getBugReporter();
+
+ if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
+ // FIXME: Handle multi-dimensional VLAs.
+ Expr* SE = VLA->getSizeExpr();
+ SVal Size_untested = state->getSVal(SE);
+
+ if (Size_untested.isUndef()) {
+ if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) {
+ N->markAsSink();
+ if (!BT)
+ BT = new BugType("Declare variable-length array (VLA) of undefined "
+ "size", "Logic error");
+
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT, BT->getName().c_str(), N);
+ R->addRange(SE->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+ BR.EmitReport(R);
+ }
+ return 0;
+ }
+ }
+ return Pred;
+}
+
+void *ZeroSizedVLAChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
+ const GRState *state, Stmt *S,
+ GRExprEngine &Eng) {
+ GRStmtNodeBuilder &Builder = Eng.getBuilder();
+ BugReporter &BR = Eng.getBugReporter();
+
+ if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
+ // FIXME: Handle multi-dimensional VLAs.
+ Expr* SE = VLA->getSizeExpr();
+ SVal Size_untested = state->getSVal(SE);
+
+ DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested);
+ // Undefined size is checked in another checker.
+ if (!Size)
+ return Pred;
+
+ const GRState *zeroState = state->Assume(*Size, false);
+ state = state->Assume(*Size, true);
+
+ if (zeroState && !state) {
+ if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) {
+ N->markAsSink();
+ if (!BT)
+ BT = new BugType("Declare variable-length array (VLA) of zero size",
+ "Logic error");
+
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT, BT->getName().c_str(), N);
+ R->addRange(SE->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+ BR.EmitReport(R);
+ }
+ }
+ if (!state)
+ return 0;
+
+ return Builder.generateNode(S, state, Pred);
+ }
+ else
+ return Pred;
+}
+
OpenPOWER on IntegriCloud