summaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2011-02-26 22:09:03 +0000
committerDimitry Andric <dim@FreeBSD.org>2011-02-26 22:09:03 +0000
commitc3b054d250cdca485c71845089c316e10610ebad (patch)
treeabae0246ec9156cc1a7cbb947b2b0dfe95fa3189 /lib/StaticAnalyzer/Checkers
parentbca07a4524feb4edec581062d631a13116320a24 (diff)
Notes
Diffstat (limited to 'lib/StaticAnalyzer/Checkers')
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp32
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp116
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt14
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp261
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp32
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td32
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp43
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp56
-rw-r--r--lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprEngine.cpp105
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp148
-rw-r--r--lib/StaticAnalyzer/Checkers/InternalChecks.h3
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp43
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp123
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp39
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp (renamed from lib/StaticAnalyzer/Checkers/StackAddrLeakChecker.cpp)63
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp148
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp50
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp58
27 files changed, 801 insertions, 813 deletions
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 9194791fc075..25e224e50c68 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -12,9 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -22,21 +24,15 @@ using namespace ento;
namespace {
class ArrayBoundChecker :
- public CheckerVisitor<ArrayBoundChecker> {
- BuiltinBug *BT;
+ public CheckerV2<check::Location> {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- ArrayBoundChecker() : BT(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad);
+ void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
};
}
-void ento::RegisterArrayBoundChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ArrayBoundChecker());
-}
-
-void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
- bool isLoad) {
+void ArrayBoundChecker::checkLocation(SVal l, bool isLoad,
+ CheckerContext &C) const {
// Check for out of bound array element access.
const MemRegion *R = l.getAsRegion();
if (!R)
@@ -69,8 +65,8 @@ void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
return;
if (!BT)
- BT = new BuiltinBug("Out-of-bound array access",
- "Access out-of-bound array element (buffer overflow)");
+ BT.reset(new BuiltinBug("Out-of-bound array access",
+ "Access out-of-bound array element (buffer overflow)"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
@@ -80,7 +76,7 @@ void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
RangedBugReport *report =
new RangedBugReport(*BT, BT->getDescription(), N);
- report->addRange(S->getSourceRange());
+ report->addRange(C.getStmt()->getSourceRange());
C.EmitReport(report);
return;
}
@@ -90,3 +86,7 @@ void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
assert(StInBound);
C.addTransition(StInBound);
}
+
+void ento::registerArrayBoundChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ArrayBoundChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 1b6c528c2f16..7aff2010d84d 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -16,14 +16,14 @@
#include "BasicObjCFoundationChecks.h"
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -69,22 +69,23 @@ static inline bool isNil(SVal X) {
//===----------------------------------------------------------------------===//
namespace {
- class NilArgChecker : public CheckerVisitor<NilArgChecker> {
- APIMisuse *BT;
- void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg);
+ class NilArgChecker : public CheckerV2<check::PreObjCMessage> {
+ mutable llvm::OwningPtr<APIMisuse> BT;
+
+ void WarnNilArg(CheckerContext &C,
+ const ObjCMessage &msg, unsigned Arg) const;
+
public:
- NilArgChecker() : BT(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
};
}
void NilArgChecker::WarnNilArg(CheckerContext &C,
const ObjCMessage &msg,
- unsigned int Arg)
+ unsigned int Arg) const
{
if (!BT)
- BT = new APIMisuse("nil argument");
+ BT.reset(new APIMisuse("nil argument"));
if (ExplodedNode *N = C.generateSink()) {
llvm::SmallString<128> sbuf;
@@ -98,9 +99,8 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
}
}
-void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg)
-{
+void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
if (!ReceiverType)
return;
@@ -140,14 +140,14 @@ void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
//===----------------------------------------------------------------------===//
namespace {
-class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
- APIMisuse* BT;
- IdentifierInfo* II;
+class CFNumberCreateChecker : public CheckerV2< check::PreStmt<CallExpr> > {
+ mutable llvm::OwningPtr<APIMisuse> BT;
+ mutable IdentifierInfo* II;
public:
- CFNumberCreateChecker() : BT(0), II(0) {}
- ~CFNumberCreateChecker() {}
- static void *getTag() { static int x = 0; return &x; }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ CFNumberCreateChecker() : II(0) {}
+
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+
private:
void EmitError(const TypedRegion* R, const Expr* Ex,
uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
@@ -247,9 +247,8 @@ static const char* GetCFNumberTypeStr(uint64_t i) {
}
#endif
-void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
- const CallExpr *CE)
-{
+void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const Expr* Callee = CE->getCallee();
const GRState *state = C.getState();
SVal CallV = state->getSVal(Callee);
@@ -335,7 +334,7 @@ void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
<< " bits of the input integer will be lost.";
if (!BT)
- BT = new APIMisuse("Bad use of CFNumberCreate");
+ BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
report->addRange(CE->getArg(2)->getSourceRange());
@@ -348,19 +347,18 @@ void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
//===----------------------------------------------------------------------===//
namespace {
-class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
- APIMisuse *BT;
- IdentifierInfo *Retain, *Release;
+class CFRetainReleaseChecker : public CheckerV2< check::PreStmt<CallExpr> > {
+ mutable llvm::OwningPtr<APIMisuse> BT;
+ mutable IdentifierInfo *Retain, *Release;
public:
- CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
+ CFRetainReleaseChecker(): Retain(0), Release(0) {}
+ void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
};
} // end anonymous namespace
-void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
- const CallExpr* CE) {
+void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
+ CheckerContext& C) const {
// If the CallExpr doesn't have exactly 1 argument just give up checking.
if (CE->getNumArgs() != 1)
return;
@@ -377,7 +375,7 @@ void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
ASTContext &Ctx = C.getASTContext();
Retain = &Ctx.Idents.get("CFRetain");
Release = &Ctx.Idents.get("CFRelease");
- BT = new APIMisuse("null passed to CFRetain/CFRelease");
+ BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
}
// Check if we called CFRetain/CFRelease.
@@ -431,28 +429,24 @@ void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
//===----------------------------------------------------------------------===//
namespace {
-class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
- Selector releaseS;
- Selector retainS;
- Selector autoreleaseS;
- Selector drainS;
- BugType *BT;
-public:
- ClassReleaseChecker()
- : BT(0) {}
+class ClassReleaseChecker : public CheckerV2<check::PreObjCMessage> {
+ mutable Selector releaseS;
+ mutable Selector retainS;
+ mutable Selector autoreleaseS;
+ mutable Selector drainS;
+ mutable llvm::OwningPtr<BugType> BT;
- static void *getTag() { static int x = 0; return &x; }
-
- void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+public:
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
};
}
-void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg) {
+void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
if (!BT) {
- BT = new APIMisuse("message incorrectly sent to class instead of class "
- "instance");
+ BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
+ "instance"));
ASTContext &Ctx = C.getASTContext();
releaseS = GetNullarySelector("release", Ctx);
@@ -488,34 +482,18 @@ void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
// Check registration.
//===----------------------------------------------------------------------===//
-static void RegisterNilArgChecker(ExprEngine& Eng) {
- Eng.registerCheck(new NilArgChecker());
-}
-
void ento::registerNilArgChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterNilArgChecker);
-}
-
-static void RegisterCFNumberCreateChecker(ExprEngine& Eng) {
- Eng.registerCheck(new CFNumberCreateChecker());
+ mgr.registerChecker<NilArgChecker>();
}
void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterCFNumberCreateChecker);
-}
-
-static void RegisterCFRetainReleaseChecker(ExprEngine& Eng) {
- Eng.registerCheck(new CFRetainReleaseChecker());
+ mgr.registerChecker<CFNumberCreateChecker>();
}
void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterCFRetainReleaseChecker);
-}
-
-static void RegisterClassReleaseChecker(ExprEngine& Eng) {
- Eng.registerCheck(new ClassReleaseChecker());
+ mgr.registerChecker<CFRetainReleaseChecker>();
}
void ento::registerClassReleaseChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterClassReleaseChecker);
+ mgr.registerChecker<ClassReleaseChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index e172a529d768..e3083967e01d 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -1,9 +1,7 @@
-set(LLVM_TARGET_DEFINITIONS Checkers.td)
-tablegen(Checkers.inc
- -gen-clang-sa-checkers
- -I ${CMAKE_CURRENT_SOURCE_DIR}/../../../include)
-add_custom_target(ClangSACheckers
- DEPENDS Checkers.inc)
+clang_tablegen(Checkers.inc -gen-clang-sa-checkers
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../../include
+ SOURCE Checkers.td
+ TARGET ClangSACheckers)
set(LLVM_USED_LIBS clangBasic clangAST)
@@ -29,8 +27,8 @@ add_clang_library(clangStaticAnalyzerCheckers
DebugCheckers.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
- ExprEngine.cpp
ExperimentalChecks.cpp
+ ExprEngine.cpp
FixedAddressChecker.cpp
IdempotentOperationChecker.cpp
LLVMConventionsChecker.cpp
@@ -48,7 +46,7 @@ add_clang_library(clangStaticAnalyzerCheckers
PthreadLockChecker.cpp
ReturnPointerRangeChecker.cpp
ReturnUndefChecker.cpp
- StackAddrLeakChecker.cpp
+ StackAddrEscapeChecker.cpp
StreamChecker.cpp
UndefBranchChecker.cpp
UndefCapturedBlockVarChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 03f9047e960c..2566e3cbb430 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -13,9 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "llvm/ADT/StringSwitch.h"
@@ -23,75 +24,86 @@ using namespace clang;
using namespace ento;
namespace {
-class CStringChecker : public CheckerVisitor<CStringChecker> {
- BugType *BT_Null, *BT_Bounds, *BT_BoundsWrite, *BT_Overlap, *BT_NotCString;
+class CStringChecker : public CheckerV2< eval::Call,
+ check::PreStmt<DeclStmt>,
+ check::LiveSymbols,
+ check::DeadSymbols,
+ check::RegionChanges
+ > {
+ mutable llvm::OwningPtr<BugType> BT_Null, BT_Bounds, BT_BoundsWrite,
+ BT_Overlap, BT_NotCString;
public:
- CStringChecker()
- : BT_Null(0), BT_Bounds(0), BT_BoundsWrite(0), BT_Overlap(0), BT_NotCString(0)
- {}
static void *getTag() { static int tag; return &tag; }
- bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
- void MarkLiveSymbols(const GRState *state, SymbolReaper &SR);
- void evalDeadSymbols(CheckerContext &C, SymbolReaper &SR);
- bool wantsRegionChangeUpdate(const GRState *state);
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
+ void checkLiveSymbols(const GRState *state, SymbolReaper &SR) const;
+ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+ bool wantsRegionChangeUpdate(const GRState *state) const;
- const GRState *EvalRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- bool*);
+ const GRState *checkRegionChanges(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) const;
- typedef void (CStringChecker::*FnCheck)(CheckerContext &, const CallExpr *);
+ typedef void (CStringChecker::*FnCheck)(CheckerContext &,
+ const CallExpr *) const;
- void evalMemcpy(CheckerContext &C, const CallExpr *CE);
- void evalMemmove(CheckerContext &C, const CallExpr *CE);
- void evalBcopy(CheckerContext &C, const CallExpr *CE);
+ void evalMemcpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
+ void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const GRState *state,
const Expr *Size, const Expr *Source, const Expr *Dest,
- bool Restricted = false);
+ bool Restricted = false) const;
- void evalMemcmp(CheckerContext &C, const CallExpr *CE);
+ void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
- void evalstrLength(CheckerContext &C, const CallExpr *CE);
+ void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
+ void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
+ void evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
+ bool IsStrnlen = false) const;
- void evalStrcpy(CheckerContext &C, const CallExpr *CE);
- void evalStpcpy(CheckerContext &C, const CallExpr *CE);
- void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd);
+ void evalStrcpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrncpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalStpcpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd,
+ bool isStrncpy) const;
// Utility methods
std::pair<const GRState*, const GRState*>
- assumeZero(CheckerContext &C, const GRState *state, SVal V, QualType Ty);
-
- const GRState *setCStringLength(const GRState *state, const MemRegion *MR,
- SVal strLength);
- SVal getCStringLengthForRegion(CheckerContext &C, const GRState *&state,
- const Expr *Ex, const MemRegion *MR);
+ static assumeZero(CheckerContext &C,
+ const GRState *state, SVal V, QualType Ty);
+
+ static const GRState *setCStringLength(const GRState *state,
+ const MemRegion *MR, SVal strLength);
+ static SVal getCStringLengthForRegion(CheckerContext &C,
+ const GRState *&state,
+ const Expr *Ex, const MemRegion *MR);
SVal getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf);
+ const Expr *Ex, SVal Buf) const;
- const GRState *InvalidateBuffer(CheckerContext &C, const GRState *state,
- const Expr *Ex, SVal V);
+ static const GRState *InvalidateBuffer(CheckerContext &C,
+ const GRState *state,
+ const Expr *Ex, SVal V);
- bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
- const MemRegion *MR);
+ static bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
+ const MemRegion *MR);
// Re-usable checks
const GRState *checkNonNull(CheckerContext &C, const GRState *state,
- const Expr *S, SVal l);
+ const Expr *S, SVal l) const;
const GRState *CheckLocation(CheckerContext &C, const GRState *state,
const Expr *S, SVal l,
- bool IsDestination = false);
+ bool IsDestination = false) const;
const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf = NULL,
- bool FirstIsDestination = false);
+ bool FirstIsDestination = false) const;
const GRState *CheckOverlap(CheckerContext &C, const GRState *state,
const Expr *Size, const Expr *First,
- const Expr *Second);
+ const Expr *Second) const;
void emitOverlapBug(CheckerContext &C, const GRState *state,
- const Stmt *First, const Stmt *Second);
+ const Stmt *First, const Stmt *Second) const;
};
class CStringLength {
@@ -110,14 +122,6 @@ namespace ento {
}
}
-static void RegisterCStringChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CStringChecker());
-}
-
-void ento::registerCStringChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterCStringChecker);
-}
-
//===----------------------------------------------------------------------===//
// Individual checks and utility methods.
//===----------------------------------------------------------------------===//
@@ -136,7 +140,7 @@ CStringChecker::assumeZero(CheckerContext &C, const GRState *state, SVal V,
const GRState *CStringChecker::checkNonNull(CheckerContext &C,
const GRState *state,
- const Expr *S, SVal l) {
+ const Expr *S, SVal l) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
@@ -150,11 +154,11 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
return NULL;
if (!BT_Null)
- BT_Null = new BuiltinBug("API",
- "Null pointer argument in call to byte string function");
+ BT_Null.reset(new BuiltinBug("API",
+ "Null pointer argument in call to byte string function"));
// Generate a report for this bug.
- BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null);
+ BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null.get());
EnhancedBugReport *report = new EnhancedBugReport(*BT,
BT->getDescription(), N);
@@ -173,7 +177,7 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
const GRState *CStringChecker::CheckLocation(CheckerContext &C,
const GRState *state,
const Expr *S, SVal l,
- bool IsDestination) {
+ bool IsDestination) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
@@ -209,16 +213,16 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
BuiltinBug *BT;
if (IsDestination) {
if (!BT_BoundsWrite) {
- BT_BoundsWrite = new BuiltinBug("Out-of-bound array access",
- "Byte string function overflows destination buffer");
+ BT_BoundsWrite.reset(new BuiltinBug("Out-of-bound array access",
+ "Byte string function overflows destination buffer"));
}
- BT = static_cast<BuiltinBug*>(BT_BoundsWrite);
+ BT = static_cast<BuiltinBug*>(BT_BoundsWrite.get());
} else {
if (!BT_Bounds) {
- BT_Bounds = new BuiltinBug("Out-of-bound array access",
- "Byte string function accesses out-of-bound array element");
+ BT_Bounds.reset(new BuiltinBug("Out-of-bound array access",
+ "Byte string function accesses out-of-bound array element"));
}
- BT = static_cast<BuiltinBug*>(BT_Bounds);
+ BT = static_cast<BuiltinBug*>(BT_Bounds.get());
}
// FIXME: It would be nice to eventually make this diagnostic more clear,
@@ -243,7 +247,7 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf,
- bool FirstIsDestination) {
+ bool FirstIsDestination) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
@@ -306,7 +310,7 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
const GRState *state,
const Expr *Size,
const Expr *First,
- const Expr *Second) {
+ const Expr *Second) const {
// Do a simple check for overlap: if the two arguments are from the same
// buffer, see if the end of the first is greater than the start of the second
// or vice versa.
@@ -413,13 +417,13 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
}
void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
- const Stmt *First, const Stmt *Second) {
+ const Stmt *First, const Stmt *Second) const {
ExplodedNode *N = C.generateSink(state);
if (!N)
return;
if (!BT_Overlap)
- BT_Overlap = new BugType("Unix API", "Improper arguments");
+ BT_Overlap.reset(new BugType("Unix API", "Improper arguments"));
// Generate a report for this bug.
RangedBugReport *report =
@@ -480,13 +484,14 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
QualType sizeTy = svalBuilder.getContext().getSizeType();
- SVal strLength = svalBuilder.getMetadataSymbolVal(getTag(), MR, Ex, sizeTy, Count);
+ SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
+ MR, Ex, sizeTy, Count);
state = state->set<CStringLength>(MR, strLength);
return strLength;
}
SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf) {
+ const Expr *Ex, SVal Buf) const {
const MemRegion *MR = Buf.getAsRegion();
if (!MR) {
// If we can't get a region, see if it's something we /know/ isn't a
@@ -495,8 +500,8 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&Buf)) {
if (ExplodedNode *N = C.generateNode(state)) {
if (!BT_NotCString)
- BT_NotCString = new BuiltinBug("API",
- "Argument is not a null-terminated string.");
+ BT_NotCString.reset(new BuiltinBug("API",
+ "Argument is not a null-terminated string."));
llvm::SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
@@ -551,8 +556,8 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
// The caller should always be prepared to handle this case.
if (ExplodedNode *N = C.generateNode(state)) {
if (!BT_NotCString)
- BT_NotCString = new BuiltinBug("API",
- "Argument is not a null-terminated string.");
+ BT_NotCString.reset(new BuiltinBug("API",
+ "Argument is not a null-terminated string."));
llvm::SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
@@ -652,7 +657,7 @@ bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
const Expr *Size, const Expr *Dest,
- const Expr *Source, bool Restricted) {
+ const Expr *Source, bool Restricted) const {
// See if the size argument is zero.
SVal sizeVal = state->getSVal(Size);
QualType sizeTy = Size->getType();
@@ -685,7 +690,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
}
-void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
@@ -694,7 +699,7 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) {
evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1), true);
}
-void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
// void *memmove(void *dst, const void *src, size_t n);
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
@@ -703,12 +708,12 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) {
evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1));
}
-void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
// void bcopy(const void *src, void *dst, size_t n);
evalCopyCommon(C, C.getState(), CE->getArg(2), CE->getArg(1), CE->getArg(0));
}
-void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// int memcmp(const void *s1, const void *s2, size_t n);
const Expr *Left = CE->getArg(0);
const Expr *Right = CE->getArg(1);
@@ -774,8 +779,20 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) {
}
}
-void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalstrLength(CheckerContext &C,
+ const CallExpr *CE) const {
// size_t strlen(const char *s);
+ evalstrLengthCommon(C, CE, /* IsStrnlen = */ false);
+}
+
+void CStringChecker::evalstrnLength(CheckerContext &C,
+ const CallExpr *CE) const {
+ // size_t strnlen(const char *s, size_t maxlen);
+ evalstrLengthCommon(C, CE, /* IsStrnlen = */ true);
+}
+
+void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
+ bool IsStrnlen) const {
const GRState *state = C.getState();
const Expr *Arg = CE->getArg(0);
SVal ArgVal = state->getSVal(Arg);
@@ -791,6 +808,32 @@ void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
if (strLength.isUndef())
return;
+ // If the check is for strnlen() then bind the return value to no more than
+ // the maxlen value.
+ if (IsStrnlen) {
+ const Expr *maxlenExpr = CE->getArg(1);
+ SVal maxlenVal = state->getSVal(maxlenExpr);
+
+ NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
+ NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
+
+ QualType cmpTy = C.getSValBuilder().getContext().IntTy;
+ const GRState *stateTrue, *stateFalse;
+
+ // Check if the strLength is greater than or equal to the maxlen
+ llvm::tie(stateTrue, stateFalse) =
+ state->assume(cast<DefinedOrUnknownSVal>
+ (C.getSValBuilder().evalBinOpNN(state, BO_GE,
+ *strLengthNL, *maxlenValNL,
+ cmpTy)));
+
+ // If the strLength is greater than or equal to the maxlen, set strLength
+ // to maxlen
+ if (stateTrue && !stateFalse) {
+ strLength = maxlenVal;
+ }
+ }
+
// If getCStringLength couldn't figure out the length, conjure a return
// value, so it can be used in constraints, at least.
if (strLength.isUnknown()) {
@@ -804,18 +847,23 @@ void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
}
}
-void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
+ // char *strcpy(char *restrict dst, const char *restrict src);
+ evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ false);
+}
+
+void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
// char *strcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ false);
+ evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ true);
}
-void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
// char *stpcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ true);
+ evalStrcpyCommon(C, CE, /* returnEnd = */ true, /* isStrncpy = */ false);
}
void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
- bool returnEnd) {
+ bool returnEnd, bool isStrncpy) const {
const GRState *state = C.getState();
// Check that the destination is non-null
@@ -840,6 +888,31 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (strLength.isUndef())
return;
+ if (isStrncpy) {
+ // Get the max number of characters to copy
+ const Expr *lenExpr = CE->getArg(2);
+ SVal lenVal = state->getSVal(lenExpr);
+
+ NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
+ NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal);
+
+ QualType cmpTy = C.getSValBuilder().getContext().IntTy;
+ const GRState *stateTrue, *stateFalse;
+
+ // Check if the max number to copy is less than the length of the src
+ llvm::tie(stateTrue, stateFalse) =
+ state->assume(cast<DefinedOrUnknownSVal>
+ (C.getSValBuilder().evalBinOpNN(state, BO_GT,
+ *strLengthNL, *lenValNL,
+ cmpTy)));
+
+ if (stateTrue) {
+ // Max number to copy is less than the length of the src, so the actual
+ // strLength copied is the max number arg.
+ strLength = lenVal;
+ }
+ }
+
SVal Result = (returnEnd ? UnknownVal() : DstVal);
// If the destination is a MemRegion, try to check for a buffer overflow and
@@ -889,7 +962,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// The driver method, and other Checker callbacks.
//===----------------------------------------------------------------------===//
-bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
const GRState *state = C.getState();
@@ -912,8 +985,10 @@ bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
.Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
.Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
.Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
+ .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
.Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
.Case("strlen", &CStringChecker::evalstrLength)
+ .Case("strnlen", &CStringChecker::evalstrnLength)
.Case("bcopy", &CStringChecker::evalBcopy)
.Default(NULL);
@@ -926,7 +1001,7 @@ bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
return true;
}
-void CStringChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
+void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Record string length for char a[] = "abc";
const GRState *state = C.getState();
@@ -962,15 +1037,15 @@ void CStringChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
C.addTransition(state);
}
-bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) {
+bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
return !Entries.isEmpty();
}
-const GRState *CStringChecker::EvalRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- bool *) {
+const GRState *
+CStringChecker::checkRegionChanges(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return state;
@@ -1017,7 +1092,8 @@ const GRState *CStringChecker::EvalRegionChanges(const GRState *state,
return state->set<CStringLength>(Entries);
}
-void CStringChecker::MarkLiveSymbols(const GRState *state, SymbolReaper &SR) {
+void CStringChecker::checkLiveSymbols(const GRState *state,
+ SymbolReaper &SR) const {
// Mark all symbols in our string length map as valid.
CStringLength::EntryMap Entries = state->get<CStringLength>();
@@ -1029,7 +1105,8 @@ void CStringChecker::MarkLiveSymbols(const GRState *state, SymbolReaper &SR) {
}
}
-void CStringChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SR) {
+void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
+ CheckerContext &C) const {
if (!SR.hasDeadSymbols())
return;
@@ -1051,3 +1128,7 @@ void CStringChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SR) {
state = state->set<CStringLength>(Entries);
C.generateNode(state);
}
+
+void ento::registerCStringChecker(CheckerManager &mgr) {
+ mgr.registerChecker<CStringChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 518cf963bef4..6a4506bcf844 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -11,30 +11,25 @@
// whether the size of the symbolic region is a multiple of the size of T.
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/CharUnits.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
-#include "InternalChecks.h"
+#include "clang/AST/CharUnits.h"
using namespace clang;
using namespace ento;
namespace {
-class CastSizeChecker : public CheckerVisitor<CastSizeChecker> {
- BuiltinBug *BT;
+class CastSizeChecker : public CheckerV2< check::PreStmt<CastExpr> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- CastSizeChecker() : BT(0) {}
- static void *getTag();
- void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+ void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
};
}
-void *CastSizeChecker::getTag() {
- static int x;
- return &x;
-}
-
-void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
+void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
const Expr *E = CE->getSubExpr();
ASTContext &Ctx = C.getASTContext();
QualType ToTy = Ctx.getCanonicalType(CE->getType());
@@ -74,9 +69,9 @@ void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
if (regionSize % typeSize != 0) {
if (ExplodedNode *errorNode = C.generateSink()) {
if (!BT)
- BT = new BuiltinBug("Cast region with wrong size.",
+ BT.reset(new BuiltinBug("Cast region with wrong size.",
"Cast a region whose size is not a multiple of the"
- " destination type size.");
+ " destination type size."));
RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(),
errorNode);
R->addRange(CE->getSourceRange());
@@ -86,6 +81,6 @@ void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
}
-void ento::RegisterCastSizeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CastSizeChecker());
+void ento::registerCastSizeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<CastSizeChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 8ec226abf6a9..04cc253fc609 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -14,31 +14,25 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
-class CastToStructChecker
- : public CheckerVisitor<CastToStructChecker> {
- BuiltinBug *BT;
+class CastToStructChecker : public CheckerV2< check::PreStmt<CastExpr> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+
public:
- CastToStructChecker() : BT(0) {}
- static void *getTag();
- void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+ void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
};
}
-void *CastToStructChecker::getTag() {
- static int x;
- return &x;
-}
-
-void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
- const CastExpr *CE) {
+void CastToStructChecker::checkPreStmt(const CastExpr *CE,
+ CheckerContext &C) const {
const Expr *E = CE->getSubExpr();
ASTContext &Ctx = C.getASTContext();
QualType OrigTy = Ctx.getCanonicalType(E->getType());
@@ -64,10 +58,10 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
if (!OrigPointeeTy->isRecordType()) {
if (ExplodedNode *N = C.generateNode()) {
if (!BT)
- BT = new BuiltinBug("Cast from non-struct type to struct type",
+ BT.reset(new BuiltinBug("Cast from non-struct type to struct type",
"Casting a non-structure type to a structure type "
"and accessing a field can lead to memory access "
- "errors or data corruption.");
+ "errors or data corruption."));
RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
R->addRange(CE->getSourceRange());
C.EmitReport(R);
@@ -75,10 +69,6 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
}
}
-static void RegisterCastToStructChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CastToStructChecker());
-}
-
void ento::registerCastToStructChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterCastToStructChecker);
+ mgr.registerChecker<CastToStructChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 1dc748666441..894b961f7d1e 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -71,16 +71,16 @@ def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">,
HelpText<"Warn about private ivars that are never used">,
DescFile<"ObjCUnusedIVarsChecker.cpp">;
-}
+} // end "cocoa"
-def StackAddrLeakChecker : Checker<"StackAddrLeak">,
+def StackAddrEscapeChecker : Checker<"StackAddrEscape">,
InPackage<Core>,
- HelpText<"Check that addresses to stack memory are not leaked outside the function">,
- DescFile<"StackAddrLeakChecker.cpp">;
+ HelpText<"Check that addresses to stack memory do not escape the function">,
+ DescFile<"StackAddrEscapeChecker.cpp">;
def DeadStoresChecker : Checker<"DeadStores">,
InPackage<Core>,
- HelpText<"Check for stores to dead variables">,
+ HelpText<"Check for values stored to a variables that are never read afterwards">,
DescFile<"DeadStoresChecker.cpp">;
def UnixAPIChecker : Checker<"API">,
@@ -90,12 +90,12 @@ def UnixAPIChecker : Checker<"API">,
def MacOSXAPIChecker : Checker<"API">,
InPackage<MacOSX>,
- HelpText<"Check calls to various MacOSXAPIChecker">,
+ HelpText<"Check for proper uses of various Mac OS X APIs">,
DescFile<"MacOSXAPIChecker.cpp">;
def CFNumberCreateChecker : Checker<"CFNumber">,
InPackage<MacOSX>,
- HelpText<"Check for CFNumberCreate">,
+ HelpText<"Check for proper uses of CFNumberCreate">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
@@ -137,7 +137,8 @@ def CStringChecker : Checker<"CString">,
def UnreachableCodeChecker : Checker<"UnreachableCode">,
InPackage<CoreExperimental>,
HelpText<"Check unreachable code">,
- DescFile<"UnreachableCodeChecker.cpp">;
+ DescFile<"UnreachableCodeChecker.cpp">,
+ Hidden; // Must be specified explicitly in order to run.
def IdempotentOperationChecker : Checker<"IdempotentOps">,
InPackage<CoreExperimental>,
@@ -174,6 +175,21 @@ def SecuritySyntaxChecker : Checker<"SecuritySyntactic">,
HelpText<"Perform quick security checks that require no data flow">,
DescFile<"CheckSecuritySyntaxOnly.cpp">;
+def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">,
+ InPackage<CoreExperimental>,
+ HelpText<"Check for an out-of-bound pointer being returned to callers">,
+ DescFile<"ReturnPointerRangeChecker.cpp">;
+
+def ArrayBoundChecker : Checker<"ArrayBound">,
+ InPackage<CoreExperimental>,
+ HelpText<"Check for an out-of-bound pointer being returned to callers">,
+ DescFile<"ArrayBoundChecker.cpp">;
+
+def CastSizeChecker : Checker<"CastSize">,
+ InPackage<CoreExperimental>,
+ HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">,
+ DescFile<"CastSizeChecker.cpp">;
+
def ObjCDeallocChecker : Checker<"Dealloc">,
InPackage<CocoaExperimental>,
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 36e76d0d3ce2..b6eef6d150d4 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -12,9 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -37,38 +38,30 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
// ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
// | |
// bug<--foo()-- JAIL_ENTERED<--foo()--
-class ChrootChecker : public CheckerVisitor<ChrootChecker> {
- IdentifierInfo *II_chroot, *II_chdir;
+class ChrootChecker : public CheckerV2<eval::Call, check::PreStmt<CallExpr> > {
+ mutable IdentifierInfo *II_chroot, *II_chdir;
// This bug refers to possibly break out of a chroot() jail.
- BuiltinBug *BT_BreakJail;
+ mutable llvm::OwningPtr<BuiltinBug> BT_BreakJail;
public:
- ChrootChecker() : II_chroot(0), II_chdir(0), BT_BreakJail(0) {}
+ ChrootChecker() : II_chroot(0), II_chdir(0) {}
static void *getTag() {
static int x;
return &x;
}
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- virtual void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
private:
- void Chroot(CheckerContext &C, const CallExpr *CE);
- void Chdir(CheckerContext &C, const CallExpr *CE);
+ void Chroot(CheckerContext &C, const CallExpr *CE) const;
+ void Chdir(CheckerContext &C, const CallExpr *CE) const;
};
} // end anonymous namespace
-static void RegisterChrootChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ChrootChecker());
-}
-
-void ento::registerChrootChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterChrootChecker);
-}
-
-bool ChrootChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -94,7 +87,7 @@ bool ChrootChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
return false;
}
-void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) {
+void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
GRStateManager &Mgr = state->getStateManager();
@@ -104,7 +97,7 @@ void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) {
C.addTransition(state);
}
-void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) {
+void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
GRStateManager &Mgr = state->getStateManager();
@@ -131,7 +124,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) {
}
// Check the jail state before any function call except chroot and chdir().
-void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -155,9 +148,9 @@ void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
if (isRootChanged((intptr_t) *k))
if (ExplodedNode *N = C.generateNode()) {
if (!BT_BreakJail)
- BT_BreakJail = new BuiltinBug("Break out of jail",
+ BT_BreakJail.reset(new BuiltinBug("Break out of jail",
"No call of chdir(\"/\") immediately "
- "after chroot");
+ "after chroot"));
BugReport *R = new BugReport(*BT_BreakJail,
BT_BreakJail->getDescription(), N);
C.EmitReport(R);
@@ -165,3 +158,7 @@ void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
return;
}
+
+void ento::registerChrootChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ChrootChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
index 94f200f3e892..5c0c9504db03 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
@@ -16,7 +16,9 @@
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseSet.h"
+#include "map"
using namespace clang;
using namespace ento;
@@ -28,6 +30,7 @@ class ClangSACheckerProvider : public CheckerProvider {
public:
virtual void registerCheckers(CheckerManager &checkerMgr,
CheckerOptInfo *checkOpts, unsigned numCheckOpts);
+ virtual void printHelp(llvm::raw_ostream &OS);
};
}
@@ -41,6 +44,7 @@ namespace {
struct StaticCheckerInfoRec {
const char *FullName;
void (*RegFunc)(CheckerManager &mgr);
+ const char *HelpText;
bool Hidden;
};
@@ -49,13 +53,16 @@ struct StaticCheckerInfoRec {
static const StaticCheckerInfoRec StaticCheckerInfo[] = {
#define GET_CHECKERS
#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,HIDDEN) \
- { FULLNAME, register##CLASS, HIDDEN },
+ { FULLNAME, register##CLASS, HELPTEXT, HIDDEN },
#include "Checkers.inc"
- { 0, 0, 0}
+ { 0, 0, 0, 0}
#undef CHECKER
#undef GET_CHECKERS
};
+static const unsigned NumCheckers = sizeof(StaticCheckerInfo)
+ / sizeof(StaticCheckerInfoRec) - 1;
+
namespace {
struct CheckNameOption {
@@ -104,9 +111,10 @@ static void collectCheckers(const CheckNameOption *checkName,
// Enable/disable all subgroups along with this one.
if (const short *subGroups = checkName->SubGroups) {
- for (; *subGroups != -1; ++subGroups)
- collectCheckers(&CheckNameTable[*subGroups], enable, checkers,
- collectHidden && checkName->Hidden);
+ for (; *subGroups != -1; ++subGroups) {
+ const CheckNameOption *sub = &CheckNameTable[*subGroups];
+ collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden);
+ }
}
}
@@ -135,3 +143,41 @@ void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
(*I)->RegFunc(checkerMgr);
}
}
+
+typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
+
+static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
+ // Find the maximum option length.
+ unsigned OptionFieldWidth = 0;
+ for (SortedCheckers::iterator
+ I = checkers.begin(), E = checkers.end(); I != E; ++I) {
+ // Limit the amount of padding we are willing to give up for alignment.
+ unsigned Length = strlen(I->second->FullName);
+ if (Length <= 30)
+ OptionFieldWidth = std::max(OptionFieldWidth, Length);
+ }
+
+ const unsigned InitialPad = 2;
+ for (SortedCheckers::iterator
+ I = checkers.begin(), E = checkers.end(); I != E; ++I) {
+ const std::string &Option = I->first;
+ int Pad = OptionFieldWidth - int(Option.size());
+ OS.indent(InitialPad) << Option;
+
+ // Break on long option names.
+ if (Pad < 0) {
+ OS << "\n";
+ Pad = OptionFieldWidth + InitialPad;
+ }
+ OS.indent(Pad + 1) << I->second->HelpText << '\n';
+ }
+}
+
+void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) {
+ // Sort checkers according to their full name.
+ SortedCheckers checkers;
+ for (unsigned i = 0; i != NumCheckers; ++i)
+ checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i];
+
+ printCheckerOption(OS, checkers);
+}
diff --git a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp b/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp
index d9bb4801c381..990ba1c02b94 100644
--- a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp
@@ -24,14 +24,3 @@ void ento::RegisterExperimentalChecks(ExprEngine &Eng) {
// within ExprEngine.
RegisterMallocChecker(Eng); // ArrayBoundChecker depends on this.
}
-
-void ento::RegisterExperimentalInternalChecks(ExprEngine &Eng) {
- // These are internal checks that should eventually migrate to
- // RegisterInternalChecks() once they have been further tested.
-
- // Note that this must be registered after ReturnStackAddresEngsChecker.
- RegisterReturnPointerRangeChecker(Eng);
-
- RegisterArrayBoundChecker(Eng);
- RegisterCastSizeChecker(Eng);
-}
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index ab8d56471c55..c1b1e656989b 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -92,12 +92,13 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
}
if (CO->empty()) {
- // If there are no checkers, return early without doing any
- // more work.
- Dst.insert(Src);
+ // If there are no checkers, just delegate to the checker manager.
+ getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
+ Dst, Src, S, *this);
return;
}
+ ExplodedNodeSet CheckersV1Dst;
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
unsigned checkersEvaluated = 0;
@@ -108,7 +109,7 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
break;
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -144,6 +145,9 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
// Don't autotransition. The CheckerContext objects should do this
// automatically.
+
+ getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
+ Dst, CheckersV1Dst, S, *this);
}
void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
@@ -152,10 +156,12 @@ void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
bool isPrevisit) {
if (Checkers.empty()) {
- Dst.insert(Src);
+ getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, Src, msg,
+ *this);
return;
}
+ ExplodedNodeSet CheckersV1Dst;
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
@@ -163,7 +169,7 @@ void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
{
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -181,8 +187,8 @@ void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
PrevSet = CurrSet;
}
- // Don't autotransition. The CheckerContext objects should do this
- // automatically.
+ getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, CheckersV1Dst,
+ msg, *this);
}
void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg,
@@ -232,11 +238,25 @@ bool ExprEngine::CheckerEvalCall(const CallExpr *CE,
DstTmp.clear();
}
- if (evaluated)
+ if (evaluated) {
Dst.insert(DstTmp);
- else
- Dst.insert(Pred);
+ return evaluated;
+ }
+
+ class DefaultEval : public GraphExpander {
+ bool &Evaluated;
+ public:
+ DefaultEval(bool &evaluated) : Evaluated(evaluated) { }
+ virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ Evaluated = false;
+ Dst.insert(Pred);
+ }
+ };
+ evaluated = true;
+ DefaultEval defaultEval(evaluated);
+ getCheckerManager().runCheckersForEvalCall(Dst, Pred, CE, *this,
+ &defaultEval);
return evaluated;
}
@@ -335,8 +355,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
// FIXME: Eventually remove the TF object entirely.
TF->RegisterChecks(*this);
TF->RegisterPrinters(getStateManager().Printers);
-
- mgr.getCheckerManager()->registerCheckersToEngine(*this);
if (mgr.shouldEagerlyTrimExplodedGraph()) {
// Enable eager node reclaimation when constructing the ExplodedGraph.
@@ -495,7 +513,7 @@ bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) {
return true;
}
- return false;
+ return getCheckerManager().wantsRegionChangeUpdate(state);
}
const GRState *
@@ -523,9 +541,9 @@ ExprEngine::processRegionChanges(const GRState *state,
CO = CO_Ref;
}
- // If there are no checkers, just return the state as is.
+ // If there are no checkers, just delegate to the checker manager.
if (CO->empty())
- return state;
+ return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
// If any checker declares the state infeasible (or if it starts that way),
@@ -548,7 +566,7 @@ ExprEngine::processRegionChanges(const GRState *state,
if (NewCO.get())
CO_Ref = NewCO.take();
- return state;
+ return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
}
void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
@@ -556,6 +574,7 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
I != E; ++I) {
I->second->VisitEndAnalysis(G, BR, *this);
}
+ getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
}
void ExprEngine::processCFGElement(const CFGElement E,
@@ -603,6 +622,8 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
checker->MarkLiveSymbols(St, SymReaper);
}
+ getCheckerManager().runCheckersForLiveSymbols(St, SymReaper);
+
const StackFrameContext *SFC = LC->getCurrentStackFrame();
CleanedState = StateMgr.removeDeadBindings(St, SFC, SymReaper);
} else {
@@ -626,8 +647,9 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
CleanedState, SymReaper);
+ ExplodedNodeSet checkersV1Tmp;
if (Checkers.empty())
- Tmp.insert(Tmp2);
+ checkersV1Tmp.insert(Tmp2);
else {
ExplodedNodeSet Tmp3;
ExplodedNodeSet *SrcSet = &Tmp2;
@@ -635,7 +657,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
I != E; ++I) {
ExplodedNodeSet *DstSet = 0;
if (I+1 == E)
- DstSet = &Tmp;
+ DstSet = &checkersV1Tmp;
else {
DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
DstSet->clear();
@@ -651,6 +673,9 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
}
}
+ getCheckerManager().runCheckersForDeadSymbols(Tmp, checkersV1Tmp,
+ SymReaper, currentStmt, *this);
+
if (!Builder->BuildSinks && !Builder->hasGeneratedNode)
Tmp.Add(EntryNode);
}
@@ -1419,8 +1444,10 @@ void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) {
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
void *tag = I->first;
Checker *checker = I->second;
- checker->evalEndPath(builder, tag, *this);
+ EndOfFunctionNodeBuilder B = builder.withCheckerTag(tag);
+ checker->evalEndPath(B, tag, *this);
}
+ getCheckerManager().runCheckersForEndPath(builder, *this);
}
/// ProcessSwitch - Called by CoreEngine. Used to generate successor
@@ -1923,20 +1950,35 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
const GRState* state, SVal location,
const void *tag, bool isLoad) {
// Early checks for performance reason.
- if (location.isUnknown() || Checkers.empty()) {
+ if (location.isUnknown()) {
Dst.Add(Pred);
return;
}
- ExplodedNodeSet Src, Tmp;
+ if (Checkers.empty()) {
+ ExplodedNodeSet Src;
+ if (Builder->GetState(Pred) == state) {
+ Src.Add(Pred);
+ } else {
+ // Associate this new state with an ExplodedNode.
+ Src.Add(Builder->generateNode(S, state, Pred));
+ }
+ getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
+ *this);
+ return;
+ }
+
+ ExplodedNodeSet Src;
Src.Add(Pred);
+ ExplodedNodeSet CheckersV1Dst;
+ ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -1957,6 +1999,9 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
+
+ getCheckerManager().runCheckersForLocation(Dst, CheckersV1Dst, location,
+ isLoad, S, *this);
}
bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
@@ -3613,14 +3658,12 @@ void ExprEngine::ViewGraph(bool trim) {
const_cast<BugType*>(*I)->FlushReports(BR);
// Iterate through the reports and get their nodes.
- for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) {
- for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end();
- I2!=E2; ++I2) {
- const BugReportEquivClass& EQ = *I2;
- const BugReport &R = **EQ.begin();
- ExplodedNode *N = const_cast<ExplodedNode*>(R.getErrorNode());
- if (N) Src.push_back(N);
- }
+ for (BugReporter::EQClasses_iterator
+ EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) {
+ BugReportEquivClass& EQ = *EI;
+ const BugReport &R = **EQ.begin();
+ ExplodedNode *N = const_cast<ExplodedNode*>(R.getErrorNode());
+ if (N) Src.push_back(N);
}
ViewGraph(&Src[0], &Src[0]+Src.size());
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index fe628a2512b2..d7b27b563784 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -14,31 +14,26 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class FixedAddressChecker
- : public CheckerVisitor<FixedAddressChecker> {
- BuiltinBug *BT;
+ : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+
public:
- FixedAddressChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
};
}
-void *FixedAddressChecker::getTag() {
- static int x;
- return &x;
-}
-
-void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
// Using a fixed address is not portable because that address will probably
// not be valid in all environments or platforms.
@@ -58,20 +53,16 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
if (ExplodedNode *N = C.generateNode()) {
if (!BT)
- BT = new BuiltinBug("Use fixed address",
+ BT.reset(new BuiltinBug("Use fixed address",
"Using a fixed address is not portable because that "
"address will probably not be valid in all "
- "environments or platforms.");
+ "environments or platforms."));
RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
R->addRange(B->getRHS()->getSourceRange());
C.EmitReport(R);
}
}
-static void RegisterFixedAddressChecker(ExprEngine &Eng) {
- Eng.registerCheck(new FixedAddressChecker());
-}
-
void ento::registerFixedAddressChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterFixedAddressChecker);
+ mgr.registerChecker<FixedAddressChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index f49b125a60a2..83d9668c48fa 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -45,11 +45,13 @@
#include "ClangSACheckers.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
+#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/AST/Stmt.h"
@@ -64,29 +66,29 @@ using namespace ento;
namespace {
class IdempotentOperationChecker
- : public CheckerVisitor<IdempotentOperationChecker> {
+ : public CheckerV2<check::PreStmt<BinaryOperator>,
+ check::PostStmt<BinaryOperator>,
+ check::EndAnalysis> {
public:
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
- void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
- void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
+ void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
+ void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
private:
// Our assumption about a particular operation.
enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0,
RHSis0 };
- void UpdateAssumption(Assumption &A, const Assumption &New);
+ static void UpdateAssumption(Assumption &A, const Assumption &New);
// False positive reduction methods
static bool isSelfAssign(const Expr *LHS, const Expr *RHS);
static bool isUnused(const Expr *E, AnalysisContext *AC);
static bool isTruncationExtensionAssignment(const Expr *LHS,
const Expr *RHS);
- bool pathWasCompletelyAnalyzed(const CFG *cfg,
- const CFGBlock *CB,
- const CFGStmtMap *CBM,
- const CoreEngine &CE);
+ static bool pathWasCompletelyAnalyzed(AnalysisContext *AC,
+ const CFGBlock *CB,
+ const CoreEngine &CE);
static bool CanVary(const Expr *Ex,
AnalysisContext *AC);
static bool isConstantOrPseudoConstant(const DeclRefExpr *DR,
@@ -104,46 +106,12 @@ private:
};
typedef llvm::DenseMap<const BinaryOperator *, BinaryOperatorData>
AssumptionMap;
- AssumptionMap hash;
-
- // A class that performs reachability queries for CFGBlocks. Several internal
- // checks in this checker require reachability information. The requests all
- // tend to have a common destination, so we lazily do a predecessor search
- // from the destination node and cache the results to prevent work
- // duplication.
- class CFGReachabilityAnalysis {
- typedef llvm::BitVector ReachableSet;
- typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap;
- ReachableSet analyzed;
- ReachableMap reachable;
- public:
- CFGReachabilityAnalysis(const CFG &cfg)
- : analyzed(cfg.getNumBlockIDs(), false) {}
-
- inline bool isReachable(const CFGBlock *Src, const CFGBlock *Dst);
- private:
- void MapReachability(const CFGBlock *Dst);
- };
- llvm::OwningPtr<CFGReachabilityAnalysis> CRA;
+ mutable AssumptionMap hash;
};
}
-void *IdempotentOperationChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-static void RegisterIdempotentOperationChecker(ExprEngine &Eng) {
- Eng.registerCheck(new IdempotentOperationChecker());
-}
-
-void ento::registerIdempotentOperationChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterIdempotentOperationChecker);
-}
-
-void IdempotentOperationChecker::PreVisitBinaryOperator(
- CheckerContext &C,
- const BinaryOperator *B) {
+void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
// Find or create an entry in the hash for this BinaryOperator instance.
// If we haven't done a lookup before, it will get default initialized to
// 'Possible'. At this stage we do not store the ExplodedNode, as it has not
@@ -359,9 +327,8 @@ void IdempotentOperationChecker::PreVisitBinaryOperator(
// At the post visit stage, the predecessor ExplodedNode will be the
// BinaryOperator that was just created. We use this hook to collect the
// ExplodedNode.
-void IdempotentOperationChecker::PostVisitBinaryOperator(
- CheckerContext &C,
- const BinaryOperator *B) {
+void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
// Add the ExplodedNode we just visited
BinaryOperatorData &Data = hash[B];
@@ -376,9 +343,9 @@ void IdempotentOperationChecker::PostVisitBinaryOperator(
Data.explodedNodes.Add(C.getPredecessor());
}
-void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
+void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &BR,
- ExprEngine &Eng) {
+ ExprEngine &Eng) const {
BugType *BT = new BugType("Idempotent operation", "Dead code");
// Iterate over the hash to see if we have any paths with definite
// idempotent operations.
@@ -397,16 +364,11 @@ void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
// If the analyzer did not finish, check to see if we can still emit this
// warning
if (Eng.hasWorkRemaining()) {
- const CFGStmtMap *CBM = CFGStmtMap::Build(AC->getCFG(),
- &AC->getParentMap());
-
// If we can trace back
- if (!pathWasCompletelyAnalyzed(AC->getCFG(),
- CBM->getBlock(B), CBM,
+ if (!pathWasCompletelyAnalyzed(AC,
+ AC->getCFGStmtMap()->getBlock(B),
Eng.getCoreEngine()))
continue;
-
- delete CBM;
}
// Select the error message and SourceRanges to report.
@@ -464,6 +426,8 @@ void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
BR.EmitReport(report);
}
}
+
+ hash.clear();
}
// Updates the current assumption given the new assumption
@@ -564,13 +528,11 @@ bool IdempotentOperationChecker::isTruncationExtensionAssignment(
// Returns false if a path to this block was not completely analyzed, or true
// otherwise.
bool
-IdempotentOperationChecker::pathWasCompletelyAnalyzed(const CFG *cfg,
+IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
const CFGBlock *CB,
- const CFGStmtMap *CBM,
const CoreEngine &CE) {
- if (!CRA.get())
- CRA.reset(new CFGReachabilityAnalysis(*cfg));
+ CFGReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis();
// Test for reachability from any aborted blocks to this block
typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
@@ -621,14 +583,14 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(const CFG *cfg,
return CRA.isReachable(B, TargetBlock);
}
};
- VisitWL visitWL(CBM, CB, *CRA.get());
+ VisitWL visitWL(AC->getCFGStmtMap(), CB, *CRA);
// Were there any items in the worklist that could potentially reach
// this block?
if (CE.getWorkList()->visitItemsInWorkList(visitWL))
return false;
// Verify that this block is reachable from the entry block
- if (!CRA->isReachable(&cfg->getEntry(), CB))
+ if (!CRA->isReachable(&AC->getCFG()->getEntry(), CB))
return false;
// If we get to this point, there is no connection to the entry block or an
@@ -766,57 +728,7 @@ bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) {
return false;
}
-bool IdempotentOperationChecker::CFGReachabilityAnalysis::isReachable(
- const CFGBlock *Src,
- const CFGBlock *Dst) {
- const unsigned DstBlockID = Dst->getBlockID();
- // If we haven't analyzed the destination node, run the analysis now
- if (!analyzed[DstBlockID]) {
- MapReachability(Dst);
- analyzed[DstBlockID] = true;
- }
-
- // Return the cached result
- return reachable[DstBlockID][Src->getBlockID()];
-}
-
-// Maps reachability to a common node by walking the predecessors of the
-// destination node.
-void IdempotentOperationChecker::CFGReachabilityAnalysis::MapReachability(
- const CFGBlock *Dst) {
-
- llvm::SmallVector<const CFGBlock *, 11> worklist;
- llvm::BitVector visited(analyzed.size());
-
- ReachableSet &DstReachability = reachable[Dst->getBlockID()];
- DstReachability.resize(analyzed.size(), false);
-
- // Start searching from the destination node, since we commonly will perform
- // multiple queries relating to a destination node.
- worklist.push_back(Dst);
- bool firstRun = true;
-
- while (!worklist.empty()) {
- const CFGBlock *block = worklist.back();
- worklist.pop_back();
-
- if (visited[block->getBlockID()])
- continue;
- visited[block->getBlockID()] = true;
-
- // Update reachability information for this node -> Dst
- if (!firstRun) {
- // Don't insert Dst -> Dst unless it was a predecessor of itself
- DstReachability[block->getBlockID()] = true;
- }
- else
- firstRun = false;
-
- // Add the predecessors to the worklist.
- for (CFGBlock::const_pred_iterator i = block->pred_begin(),
- e = block->pred_end(); i != e; ++i) {
- worklist.push_back(*i);
- }
- }
+void ento::registerIdempotentOperationChecker(CheckerManager &mgr) {
+ mgr.registerChecker<IdempotentOperationChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/InternalChecks.h b/lib/StaticAnalyzer/Checkers/InternalChecks.h
index e855386fffea..e7c38ee25d8f 100644
--- a/lib/StaticAnalyzer/Checkers/InternalChecks.h
+++ b/lib/StaticAnalyzer/Checkers/InternalChecks.h
@@ -23,16 +23,13 @@ class ExprEngine;
// Foundational checks that handle basic semantics.
void RegisterAdjustedReturnValueChecker(ExprEngine &Eng);
-void RegisterArrayBoundChecker(ExprEngine &Eng);
void RegisterArrayBoundCheckerV2(ExprEngine &Eng);
void RegisterAttrNonNullChecker(ExprEngine &Eng);
void RegisterBuiltinFunctionChecker(ExprEngine &Eng);
void RegisterCallAndMessageChecker(ExprEngine &Eng);
-void RegisterCastSizeChecker(ExprEngine &Eng);
void RegisterDereferenceChecker(ExprEngine &Eng);
void RegisterDivZeroChecker(ExprEngine &Eng);
void RegisterNoReturnFunctionChecker(ExprEngine &Eng);
-void RegisterReturnPointerRangeChecker(ExprEngine &Eng);
void RegisterReturnUndefChecker(ExprEngine &Eng);
void RegisterUndefBranchChecker(ExprEngine &Eng);
void RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng);
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 358be124b9e4..d70c65ae3073 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -16,11 +16,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
@@ -29,31 +30,26 @@ using namespace clang;
using namespace ento;
namespace {
-class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
+class MacOSXAPIChecker : public CheckerV2< check::PreStmt<CallExpr> > {
enum SubChecks {
DispatchOnce = 0,
DispatchOnceF,
NumChecks
};
- BugType *BTypes[NumChecks];
+ mutable BugType *BTypes[NumChecks];
public:
MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
- static void *getTag() { static unsigned tag = 0; return &tag; }
+ ~MacOSXAPIChecker() {
+ for (unsigned i=0; i != NumChecks; ++i)
+ delete BTypes[i];
+ }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} //end anonymous namespace
-static void RegisterMacOSXAPIChecker(ExprEngine &Eng) {
- Eng.registerCheck(new MacOSXAPIChecker());
-}
-
-void ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterMacOSXAPIChecker);
-}
-
//===----------------------------------------------------------------------===//
// dispatch_once and dispatch_once_f
//===----------------------------------------------------------------------===//
@@ -121,7 +117,8 @@ namespace {
};
} // end anonymous namespace
-void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
// FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
@@ -144,3 +141,11 @@ void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
SC.run(C, CE, FI);
}
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MacOSXAPIChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 9d3a887cdbf1..794740ab7203 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -599,7 +599,7 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
RefState RS = I->second;
if (RS.isAllocated()) {
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ ExplodedNode *N = B.generateNode(state);
if (N) {
if (!BT_Leak)
BT_Leak = new BuiltinBug("Memory leak",
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 9fb89d79fc79..fed6a99c89a2 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -16,10 +16,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
@@ -28,39 +29,18 @@ using namespace ento;
namespace {
class NSAutoreleasePoolChecker
- : public CheckerVisitor<NSAutoreleasePoolChecker> {
+ : public CheckerV2<check::PreObjCMessage> {
- Selector releaseS;
+ mutable Selector releaseS;
public:
- NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {}
-
- static void *getTag() {
- static int x = 0;
- return &x;
- }
-
- void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
};
} // end anonymous namespace
-
-static void RegisterNSAutoreleasePoolChecker(ExprEngine &Eng) {
- ASTContext &Ctx = Eng.getContext();
- if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) {
- Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release",
- Ctx)));
- }
-}
-
-void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterNSAutoreleasePoolChecker);
-}
-
-void
-NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg) {
+void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
const Expr *receiver = msg.getInstanceReceiver();
if (!receiver)
@@ -78,7 +58,9 @@ NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
return;
if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
return;
-
+
+ if (releaseS.isNull())
+ releaseS = GetNullarySelector("release", C.getASTContext());
// Sending 'release' message?
if (msg.getSelector() != releaseS)
return;
@@ -90,3 +72,8 @@ NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
"Use -drain instead of -release when using NSAutoreleasePool "
"and garbage collection", R.getBegin(), &R, 1);
}
+
+void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
+ if (mgr.getLangOptions().getGCMode() != LangOptions::NonGC)
+ mgr.registerChecker<NSAutoreleasePoolChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 7d440ab17e9f..77467190db73 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -13,39 +13,29 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
namespace {
-class ObjCAtSyncChecker : public CheckerVisitor<ObjCAtSyncChecker> {
- BuiltinBug *BT_null;
- BuiltinBug *BT_undef;
+class ObjCAtSyncChecker
+ : public CheckerV2< check::PreStmt<ObjCAtSynchronizedStmt> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT_null;
+ mutable llvm::OwningPtr<BuiltinBug> BT_undef;
+
public:
- ObjCAtSyncChecker() : BT_null(0), BT_undef(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
- const ObjCAtSynchronizedStmt *S);
+ void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
};
} // end anonymous namespace
-static void RegisterObjCAtSyncChecker(ExprEngine &Eng) {
- // @synchronized is an Objective-C 2 feature.
- if (Eng.getContext().getLangOptions().ObjC2)
- Eng.registerCheck(new ObjCAtSyncChecker());
-}
-
-void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterObjCAtSyncChecker);
-}
-
-void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
- const ObjCAtSynchronizedStmt *S) {
+void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
+ CheckerContext &C) const {
const Expr *Ex = S->getSynchExpr();
const GRState *state = C.getState();
@@ -55,8 +45,8 @@ void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
if (isa<UndefinedVal>(V)) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_undef)
- BT_undef = new BuiltinBug("Uninitialized value used as mutex "
- "for @synchronized");
+ BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex "
+ "for @synchronized"));
EnhancedBugReport *report =
new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
@@ -78,8 +68,8 @@ void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
// a null mutex just means no synchronization occurs.
if (ExplodedNode *N = C.generateNode(nullState)) {
if (!BT_null)
- BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
- "(no synchronization will occur)");
+ BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() "
+ "(no synchronization will occur)"));
EnhancedBugReport *report =
new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
@@ -98,3 +88,7 @@ void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
C.addTransition(notNullState);
}
+void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
+ if (mgr.getLangOptions().ObjC2)
+ mgr.registerChecker<ObjCAtSyncChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 4f247ea14670..5f32bb8f53a2 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -47,8 +47,9 @@
// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
@@ -63,45 +64,23 @@ static bool isInitMessage(const ObjCMessage &msg);
static bool isSelfVar(SVal location, CheckerContext &C);
namespace {
-enum SelfFlagEnum {
- /// \brief No flag set.
- SelfFlag_None = 0x0,
- /// \brief Value came from 'self'.
- SelfFlag_Self = 0x1,
- /// \brief Value came from the result of an initializer (e.g. [super init]).
- SelfFlag_InitRes = 0x2
-};
-}
-
-namespace {
-class ObjCSelfInitChecker : public CheckerVisitor<ObjCSelfInitChecker> {
- /// \brief A call receiving a reference to 'self' invalidates the object that
- /// 'self' contains. This field keeps the "self flags" assigned to the 'self'
- /// object before the call and assign them to the new object that 'self'
- /// points to after the call.
- SelfFlagEnum preCallSelfFlags;
-
+class ObjCSelfInitChecker : public CheckerV2<
+ check::PostObjCMessage,
+ check::PostStmt<ObjCIvarRefExpr>,
+ check::PreStmt<ReturnStmt>,
+ check::PreStmt<CallExpr>,
+ check::PostStmt<CallExpr>,
+ check::Location > {
public:
- static void *getTag() { static int tag = 0; return &tag; }
- void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
- void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
- void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE);
- void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE);
- virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location,
- bool isLoad);
+ void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+ void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
+ void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkLocation(SVal location, bool isLoad, CheckerContext &C) const;
};
} // end anonymous namespace
-static void RegisterObjCSelfInitChecker(ExprEngine &Eng) {
- if (Eng.getContext().getLangOptions().ObjC1)
- Eng.registerCheck(new ObjCSelfInitChecker());
-}
-
-void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterObjCSelfInitChecker);
-}
-
namespace {
class InitSelfBug : public BugType {
@@ -113,22 +92,40 @@ public:
} // end anonymous namespace
+namespace {
+enum SelfFlagEnum {
+ /// \brief No flag set.
+ SelfFlag_None = 0x0,
+ /// \brief Value came from 'self'.
+ SelfFlag_Self = 0x1,
+ /// \brief Value came from the result of an initializer (e.g. [super init]).
+ SelfFlag_InitRes = 0x2
+};
+}
+
typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag;
namespace { struct CalledInit {}; }
+namespace { struct PreCallSelfFlags {}; }
namespace clang {
namespace ento {
template<>
struct GRStateTrait<SelfFlag> : public GRStatePartialTrait<SelfFlag> {
- static void* GDMIndex() {
- static int index = 0;
- return &index;
- }
+ static void* GDMIndex() { static int index = 0; return &index; }
};
template <>
struct GRStateTrait<CalledInit> : public GRStatePartialTrait<bool> {
static void *GDMIndex() { static int index = 0; return &index; }
};
+
+ /// \brief A call receiving a reference to 'self' invalidates the object that
+ /// 'self' contains. This keeps the "self flags" assigned to the 'self'
+ /// object before the call so we can assign them to the new object that 'self'
+ /// points to after the call.
+ template <>
+ struct GRStateTrait<PreCallSelfFlags> : public GRStatePartialTrait<unsigned> {
+ static void *GDMIndex() { static int index = 0; return &index; }
+ };
}
}
@@ -188,8 +185,8 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
C.EmitReport(report);
}
-void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg) {
+void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
// When encountering a message that does initialization (init rule),
// tag the return value so that we know later on that if self has this value
// then it is properly initialized.
@@ -219,8 +216,8 @@ void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
// fails.
}
-void ObjCSelfInitChecker::PostVisitObjCIvarRefExpr(CheckerContext &C,
- const ObjCIvarRefExpr *E) {
+void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
+ CheckerContext &C) const {
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
C.getCurrentAnalysisContext()->getDecl())))
@@ -231,8 +228,8 @@ void ObjCSelfInitChecker::PostVisitObjCIvarRefExpr(CheckerContext &C,
"'[(super or self) init...]'");
}
-void ObjCSelfInitChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *S) {
+void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
+ CheckerContext &C) const {
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
C.getCurrentAnalysisContext()->getDecl())))
@@ -259,40 +256,46 @@ void ObjCSelfInitChecker::PreVisitReturnStmt(CheckerContext &C,
// Until we can use inter-procedural analysis, in such a call, transfer the
// SelfFlags to the result of the call.
-void ObjCSelfInitChecker::PreVisitGenericCall(CheckerContext &C,
- const CallExpr *CE) {
+void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
SVal argV = state->getSVal(*I);
if (isSelfVar(argV, C)) {
- preCallSelfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+ unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+ C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
- preCallSelfFlags = getSelfFlags(argV, C);
+ unsigned selfFlags = getSelfFlags(argV, C);
+ C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
return;
}
}
}
-void ObjCSelfInitChecker::PostVisitGenericCall(CheckerContext &C,
- const CallExpr *CE) {
+void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
SVal argV = state->getSVal(*I);
if (isSelfVar(argV, C)) {
- addSelfFlag(state, state->getSVal(cast<Loc>(argV)), preCallSelfFlags, C);
+ SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
+ state = state->remove<PreCallSelfFlags>();
+ addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
- addSelfFlag(state, state->getSVal(CE), preCallSelfFlags, C);
+ SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
+ state = state->remove<PreCallSelfFlags>();
+ addSelfFlag(state, state->getSVal(CE), prevFlags, C);
return;
}
}
}
-void ObjCSelfInitChecker::visitLocation(CheckerContext &C, const Stmt *S,
- SVal location, bool isLoad) {
+void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
+ CheckerContext &C) const {
// Tag the result of a load from 'self' so that we can easily know that the
// value is the object that 'self' points to.
const GRState *state = C.getState();
@@ -354,3 +357,11 @@ static bool isInitializationMethod(const ObjCMethodDecl *MD) {
static bool isInitMessage(const ObjCMessage &msg) {
return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule;
}
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ObjCSelfInitChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 741e48bfcbe0..034a2aaef74e 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -13,31 +13,26 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class PointerArithChecker
- : public CheckerVisitor<PointerArithChecker> {
- BuiltinBug *BT;
+ : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+
public:
- PointerArithChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
};
}
-void *PointerArithChecker::getTag() {
- static int x;
- return &x;
-}
-
-void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add)
return;
@@ -57,10 +52,10 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
if (ExplodedNode *N = C.generateNode()) {
if (!BT)
- BT = new BuiltinBug("Dangerous pointer arithmetic",
+ BT.reset(new BuiltinBug("Dangerous pointer arithmetic",
"Pointer arithmetic done on non-array variables "
"means reliance on memory layout, which is "
- "dangerous.");
+ "dangerous."));
RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.EmitReport(R);
@@ -68,10 +63,6 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
}
}
-static void RegisterPointerArithChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PointerArithChecker());
-}
-
void ento::registerPointerArithChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterPointerArithChecker);
+ mgr.registerChecker<PointerArithChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index f28fe9a5379e..bf85b959c9ee 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -14,31 +14,26 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class PointerSubChecker
- : public CheckerVisitor<PointerSubChecker> {
- BuiltinBug *BT;
+ : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+
public:
- PointerSubChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
};
}
-void *PointerSubChecker::getTag() {
- static int x;
- return &x;
-}
-
-void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
// When doing pointer subtraction, if the two pointers do not point to the
// same memory chunk, emit a warning.
if (B->getOpcode() != BO_Sub)
@@ -66,19 +61,15 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
if (ExplodedNode *N = C.generateNode()) {
if (!BT)
- BT = new BuiltinBug("Pointer subtraction",
+ BT.reset(new BuiltinBug("Pointer subtraction",
"Subtraction of two pointers that do not point to "
- "the same memory chunk may cause incorrect result.");
+ "the same memory chunk may cause incorrect result."));
RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.EmitReport(R);
}
}
-static void RegisterPointerSubChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PointerSubChecker());
-}
-
void ento::registerPointerSubChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterPointerSubChecker);
+ mgr.registerChecker<PointerSubChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 34c095f42e08..6c6901f41263 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -13,8 +13,9 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "llvm/ADT/ImmutableSet.h"
@@ -24,21 +25,15 @@ using namespace ento;
namespace {
class PthreadLockChecker
- : public CheckerVisitor<PthreadLockChecker> {
- BugType *BT;
+ : public CheckerV2< check::PostStmt<CallExpr> > {
public:
- PthreadLockChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void AcquireLock(CheckerContext &C, const CallExpr *CE,
- SVal lock, bool isTryLock);
+ SVal lock, bool isTryLock) const;
void ReleaseLock(CheckerContext &C, const CallExpr *CE,
- SVal lock);
+ SVal lock) const;
};
} // end anonymous namespace
@@ -49,22 +44,14 @@ namespace clang {
namespace ento {
template <> struct GRStateTrait<LockSet> :
public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
- static void* GDMIndex() { return PthreadLockChecker::getTag(); }
+ static void* GDMIndex() { static int x = 0; return &x; }
};
} // end GR namespace
} // end clang namespace
-static void RegisterPthreadLockChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PthreadLockChecker());
-}
-
-void ento::registerPthreadLockChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterPthreadLockChecker);
-}
-
-void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
+void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionTextRegion *R =
@@ -96,7 +83,7 @@ void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
}
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
- SVal lock, bool isTryLock) {
+ SVal lock, bool isTryLock) const {
const MemRegion *lockR = lock.getAsRegion();
if (!lockR)
@@ -132,7 +119,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
}
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
- SVal lock) {
+ SVal lock) const {
const MemRegion *lockR = lock.getAsRegion();
if (!lockR)
@@ -150,3 +137,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
C.addTransition(C.generateNode(CE, unlockState));
}
+
+void ento::registerPthreadLockChecker(CheckerManager &mgr) {
+ mgr.registerChecker<PthreadLockChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 838a00f18785..298515609cd0 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -12,9 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -22,25 +24,15 @@ using namespace ento;
namespace {
class ReturnPointerRangeChecker :
- public CheckerVisitor<ReturnPointerRangeChecker> {
- BuiltinBug *BT;
+ public CheckerV2< check::PreStmt<ReturnStmt> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- ReturnPointerRangeChecker() : BT(0) {}
- static void *getTag();
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+ void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
}
-void ento::RegisterReturnPointerRangeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ReturnPointerRangeChecker());
-}
-
-void *ReturnPointerRangeChecker::getTag() {
- static int x = 0; return &x;
-}
-
-void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
+void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
+ CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *RetE = RS->getRetValue();
@@ -77,9 +69,9 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
// FIXME: This bug correspond to CWE-466. Eventually we should have bug
// types explicitly reference such exploit categories (when applicable).
if (!BT)
- BT = new BuiltinBug("Return of pointer value outside of expected range",
+ BT.reset(new BuiltinBug("Return of pointer value outside of expected range",
"Returned pointer value points outside the original object "
- "(potential buffer overflow)");
+ "(potential buffer overflow)"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
@@ -93,3 +85,7 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
C.EmitReport(report);
}
}
+
+void ento::registerReturnPointerRangeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ReturnPointerRangeChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrLeakChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 363f4042db6b..6a9a37d955bf 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrLeakChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -1,4 +1,4 @@
-//=== StackAddrLeakChecker.cpp ------------------------------------*- C++ -*--//
+//=== StackAddrEscapeChecker.cpp ----------------------------------*- C++ -*--//
//
// The LLVM Compiler Infrastructure
//
@@ -13,9 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
@@ -23,34 +24,23 @@ using namespace clang;
using namespace ento;
namespace {
-class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
- BuiltinBug *BT_stackleak;
- BuiltinBug *BT_returnstack;
+class StackAddrEscapeChecker : public CheckerV2< check::PreStmt<ReturnStmt>,
+ check::EndPath > {
+ mutable llvm::OwningPtr<BuiltinBug> BT_stackleak;
+ mutable llvm::OwningPtr<BuiltinBug> BT_returnstack;
public:
- StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
- static void *getTag() {
- static int x;
- return &x;
- }
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
- void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
+ void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
+ void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
private:
- void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
- SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
- SourceManager &SM);
+ void EmitStackError(CheckerContext &C, const MemRegion *R,
+ const Expr *RetE) const;
+ static SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
+ SourceManager &SM);
};
}
-static void RegisterStackAddrLeakChecker(ExprEngine &Eng) {
- Eng.registerCheck(new StackAddrLeakChecker());
-}
-
-void ento::registerStackAddrLeakChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterStackAddrLeakChecker);
-}
-
-SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
+SourceRange StackAddrEscapeChecker::GenName(llvm::raw_ostream &os,
const MemRegion *R,
SourceManager &SM) {
// Get the base region, stripping away fields and elements.
@@ -93,15 +83,16 @@ SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
return range;
}
-void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
- const Expr *RetE) {
+void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
+ const Expr *RetE) const {
ExplodedNode *N = C.generateSink();
if (!N)
return;
if (!BT_returnstack)
- BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
+ BT_returnstack.reset(
+ new BuiltinBug("Return of address to stack-allocated memory"));
// Generate a report for this bug.
llvm::SmallString<512> buf;
@@ -116,8 +107,8 @@ void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
C.EmitReport(report);
}
-void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
+void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
+ CheckerContext &C) const {
const Expr *RetE = RS->getRetValue();
if (!RetE)
@@ -135,8 +126,8 @@ void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
}
}
-void StackAddrLeakChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
- ExprEngine &Eng) {
+void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
+ ExprEngine &Eng) const {
const GRState *state = B.getState();
@@ -180,16 +171,16 @@ void StackAddrLeakChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
return;
// Generate an error node.
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ ExplodedNode *N = B.generateNode(state);
if (!N)
return;
if (!BT_stackleak)
- BT_stackleak =
+ BT_stackleak.reset(
new BuiltinBug("Stack address stored into global variable",
"Stack address was saved into a global variable. "
"This is dangerous because the address will become "
- "invalid after returning from the function");
+ "invalid after returning from the function"));
for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
// Generate a report for this bug.
@@ -208,3 +199,7 @@ void StackAddrLeakChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
Eng.getBugReporter().EmitReport(report);
}
}
+
+void ento::registerStackAddrEscapeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<StackAddrEscapeChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 2655be28a462..d0626b8cef83 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -12,9 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -55,52 +56,50 @@ struct StreamState {
}
};
-class StreamChecker : public CheckerVisitor<StreamChecker> {
- IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, *II_fwrite,
+class StreamChecker : public CheckerV2<eval::Call,
+ check::DeadSymbols,
+ check::EndPath,
+ check::PreStmt<ReturnStmt> > {
+ mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
+ *II_fwrite,
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
*II_clearerr, *II_feof, *II_ferror, *II_fileno;
- BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose, *BT_ResourceLeak;
+ mutable llvm::OwningPtr<BuiltinBug> BT_nullfp, BT_illegalwhence,
+ BT_doubleclose, BT_ResourceLeak;
public:
StreamChecker()
: II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0),
II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0),
- II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0),
- BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0),
- BT_ResourceLeak(0) {}
+ II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0) {}
- static void *getTag() {
- static int x;
- return &x;
- }
-
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
- void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+ void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+ void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
private:
- void Fopen(CheckerContext &C, const CallExpr *CE);
- void Tmpfile(CheckerContext &C, const CallExpr *CE);
- void Fclose(CheckerContext &C, const CallExpr *CE);
- void Fread(CheckerContext &C, const CallExpr *CE);
- void Fwrite(CheckerContext &C, const CallExpr *CE);
- void Fseek(CheckerContext &C, const CallExpr *CE);
- void Ftell(CheckerContext &C, const CallExpr *CE);
- void Rewind(CheckerContext &C, const CallExpr *CE);
- void Fgetpos(CheckerContext &C, const CallExpr *CE);
- void Fsetpos(CheckerContext &C, const CallExpr *CE);
- void Clearerr(CheckerContext &C, const CallExpr *CE);
- void Feof(CheckerContext &C, const CallExpr *CE);
- void Ferror(CheckerContext &C, const CallExpr *CE);
- void Fileno(CheckerContext &C, const CallExpr *CE);
-
- void OpenFileAux(CheckerContext &C, const CallExpr *CE);
+ void Fopen(CheckerContext &C, const CallExpr *CE) const;
+ void Tmpfile(CheckerContext &C, const CallExpr *CE) const;
+ void Fclose(CheckerContext &C, const CallExpr *CE) const;
+ void Fread(CheckerContext &C, const CallExpr *CE) const;
+ void Fwrite(CheckerContext &C, const CallExpr *CE) const;
+ void Fseek(CheckerContext &C, const CallExpr *CE) const;
+ void Ftell(CheckerContext &C, const CallExpr *CE) const;
+ void Rewind(CheckerContext &C, const CallExpr *CE) const;
+ void Fgetpos(CheckerContext &C, const CallExpr *CE) const;
+ void Fsetpos(CheckerContext &C, const CallExpr *CE) const;
+ void Clearerr(CheckerContext &C, const CallExpr *CE) const;
+ void Feof(CheckerContext &C, const CallExpr *CE) const;
+ void Ferror(CheckerContext &C, const CallExpr *CE) const;
+ void Fileno(CheckerContext &C, const CallExpr *CE) const;
+
+ void OpenFileAux(CheckerContext &C, const CallExpr *CE) const;
const GRState *CheckNullStream(SVal SV, const GRState *state,
- CheckerContext &C);
+ CheckerContext &C) const;
const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state,
- CheckerContext &C);
+ CheckerContext &C) const;
};
} // end anonymous namespace
@@ -110,20 +109,12 @@ namespace ento {
template <>
struct GRStateTrait<StreamState>
: public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
- static void *GDMIndex() { return StreamChecker::getTag(); }
+ static void *GDMIndex() { static int x; return &x; }
};
}
}
-static void RegisterStreamChecker(ExprEngine &Eng) {
- Eng.registerCheck(new StreamChecker());
-}
-
-void ento::registerStreamChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterStreamChecker);
-}
-
-bool StreamChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -221,15 +212,15 @@ bool StreamChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
return false;
}
-void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) const {
OpenFileAux(C, CE);
}
-void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const {
OpenFileAux(C, CE);
}
-void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -255,25 +246,25 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) {
}
}
-void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = CheckDoubleClose(CE, C.getState(), C);
if (state)
C.addTransition(state);
}
-void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
return;
}
-void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
return;
}
-void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
return;
@@ -290,65 +281,65 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) {
if (ExplodedNode *N = C.generateNode(state)) {
if (!BT_illegalwhence)
- BT_illegalwhence = new BuiltinBug("Illegal whence argument",
+ BT_illegalwhence.reset(new BuiltinBug("Illegal whence argument",
"The whence argument to fseek() should be "
- "SEEK_SET, SEEK_END, or SEEK_CUR.");
+ "SEEK_SET, SEEK_END, or SEEK_CUR."));
BugReport *R = new BugReport(*BT_illegalwhence,
BT_illegalwhence->getDescription(), N);
C.EmitReport(R);
}
}
-void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
- CheckerContext &C) {
+ CheckerContext &C) const {
const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
if (!DV)
return 0;
@@ -360,8 +351,8 @@ const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
if (!stateNotNull && stateNull) {
if (ExplodedNode *N = C.generateSink(stateNull)) {
if (!BT_nullfp)
- BT_nullfp = new BuiltinBug("NULL stream pointer",
- "Stream pointer might be NULL.");
+ BT_nullfp.reset(new BuiltinBug("NULL stream pointer",
+ "Stream pointer might be NULL."));
BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
C.EmitReport(R);
}
@@ -372,7 +363,7 @@ const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
const GRState *state,
- CheckerContext &C) {
+ CheckerContext &C) const {
SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
if (!Sym)
return state;
@@ -389,9 +380,9 @@ const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
ExplodedNode *N = C.generateSink();
if (N) {
if (!BT_doubleclose)
- BT_doubleclose = new BuiltinBug("Double fclose",
+ BT_doubleclose.reset(new BuiltinBug("Double fclose",
"Try to close a file Descriptor already"
- " closed. Cause undefined behaviour.");
+ " closed. Cause undefined behaviour."));
BugReport *R = new BugReport(*BT_doubleclose,
BT_doubleclose->getDescription(), N);
C.EmitReport(R);
@@ -403,7 +394,8 @@ const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
return state->set<StreamState>(Sym, StreamState::getClosed(CE));
}
-void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
+void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I) {
SymbolRef Sym = *I;
@@ -416,8 +408,8 @@ void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
ExplodedNode *N = C.generateSink();
if (N) {
if (!BT_ResourceLeak)
- BT_ResourceLeak = new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak.");
+ BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
+ "Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
C.EmitReport(R);
@@ -426,8 +418,8 @@ void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
}
}
-void StreamChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
- ExprEngine &Eng) {
+void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
+ ExprEngine &Eng) const {
const GRState *state = B.getState();
typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
SymMap M = state->get<StreamState>();
@@ -435,11 +427,11 @@ void StreamChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
StreamState SS = I->second;
if (SS.isOpened()) {
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ ExplodedNode *N = B.generateNode(state);
if (N) {
if (!BT_ResourceLeak)
- BT_ResourceLeak = new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak.");
+ BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
+ "Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
Eng.getBugReporter().EmitReport(R);
@@ -448,7 +440,7 @@ void StreamChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
}
}
-void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
const Expr *RetE = S->getRetValue();
if (!RetE)
return;
@@ -468,3 +460,7 @@ void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
C.addTransition(state);
}
+
+void ento::registerStreamChecker(CheckerManager &mgr) {
+ mgr.registerChecker<StreamChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index a53ebb5ae19c..be4fbf60eb2e 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -13,10 +13,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include <fcntl.h>
@@ -26,7 +27,7 @@ using namespace ento;
using llvm::Optional;
namespace {
-class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
+class UnixAPIChecker : public CheckerV2< check::PreStmt<CallExpr> > {
enum SubChecks {
OpenFn = 0,
PthreadOnceFn = 1,
@@ -34,27 +35,22 @@ class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
NumChecks
};
- BugType *BTypes[NumChecks];
+ mutable BugType *BTypes[NumChecks];
public:
- Optional<uint64_t> Val_O_CREAT;
+ mutable Optional<uint64_t> Val_O_CREAT;
public:
UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
- static void *getTag() { static unsigned tag = 0; return &tag; }
+ ~UnixAPIChecker() {
+ for (unsigned i=0; i != NumChecks; ++i)
+ delete BTypes[i];
+ }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} //end anonymous namespace
-static void RegisterUnixAPIChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UnixAPIChecker());
-}
-
-void ento::registerUnixAPIChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterUnixAPIChecker);
-}
-
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
@@ -69,7 +65,7 @@ static inline void LazyInitialize(BugType *&BT, const char *name) {
// "open" (man 2 open)
//===----------------------------------------------------------------------===//
-static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
+static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,
const CallExpr *CE, BugType *&BT) {
// The definition of O_CREAT is platform specific. We need a better way
// of querying this information from the checking environment.
@@ -141,7 +137,7 @@ static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
// pthread_once
//===----------------------------------------------------------------------===//
-static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
+static void CheckPthreadOnce(CheckerContext &C, const UnixAPIChecker &,
const CallExpr *CE, BugType *&BT) {
// This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
@@ -186,7 +182,7 @@ static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
// FIXME: Eventually this should be rolled into the MallocChecker, but this
// check is more basic and is valuable for widespread use.
-static void CheckMallocZero(CheckerContext &C, UnixAPIChecker &UC,
+static void CheckMallocZero(CheckerContext &C, const UnixAPIChecker &UC,
const CallExpr *CE, BugType *&BT) {
// Sanity check that malloc takes one argument.
@@ -234,16 +230,16 @@ static void CheckMallocZero(CheckerContext &C, UnixAPIChecker &UC,
// Central dispatch function.
//===----------------------------------------------------------------------===//
-typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC,
+typedef void (*SubChecker)(CheckerContext &C, const UnixAPIChecker &UC,
const CallExpr *CE, BugType *&BT);
namespace {
class SubCheck {
SubChecker SC;
- UnixAPIChecker *UC;
+ const UnixAPIChecker *UC;
BugType **BT;
public:
- SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc),
- BT(&bt) {}
+ SubCheck(SubChecker sc, const UnixAPIChecker *uc, BugType *& bt)
+ : SC(sc), UC(uc), BT(&bt) {}
SubCheck() : SC(NULL), UC(NULL), BT(NULL) {}
void run(CheckerContext &C, const CallExpr *CE) const {
@@ -253,7 +249,7 @@ namespace {
};
} // end anonymous namespace
-void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
const GRState *state = C.getState();
@@ -280,3 +276,11 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
SC.run(C, CE);
}
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerUnixAPIChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UnixAPIChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 3038e29c0efc..1bc487a49c1e 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -14,15 +14,16 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
// The number of CFGBlock pointers we want to reserve memory for. This is used
@@ -33,40 +34,27 @@ using namespace clang;
using namespace ento;
namespace {
-class UnreachableCodeChecker : public Checker {
+class UnreachableCodeChecker : public CheckerV2<check::EndAnalysis> {
public:
- static void *getTag();
- void VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &B,
- ExprEngine &Eng);
+ void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
+ ExprEngine &Eng) const;
private:
+ typedef llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> CFGBlocksSet;
+
static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
- void FindUnreachableEntryPoints(const CFGBlock *CB);
+ static void FindUnreachableEntryPoints(const CFGBlock *CB,
+ CFGBlocksSet &reachable,
+ CFGBlocksSet &visited);
static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
static inline bool isEmptyCFGBlock(const CFGBlock *CB);
-
- llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> reachable;
- llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> visited;
};
}
-void *UnreachableCodeChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-static void RegisterUnreachableCodeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UnreachableCodeChecker());
-}
-
-void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterUnreachableCodeChecker);
-}
-
-void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
+void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &B,
- ExprEngine &Eng) {
- // Bail out if we didn't cover all paths
+ ExprEngine &Eng) const {
+ CFGBlocksSet reachable, visited;
+
if (Eng.hasWorkRemaining())
return;
@@ -109,7 +97,7 @@ void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
// Find the entry points for this block
if (!visited.count(CB->getBlockID()))
- FindUnreachableEntryPoints(CB);
+ FindUnreachableEntryPoints(CB, reachable, visited);
// This block may have been pruned; check if we still want to report it
if (reachable.count(CB->getBlockID()))
@@ -155,7 +143,9 @@ void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
}
// Recursively finds the entry point(s) for this dead CFGBlock.
-void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
+void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
+ CFGBlocksSet &reachable,
+ CFGBlocksSet &visited) {
visited.insert(CB->getBlockID());
for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end();
@@ -166,7 +156,7 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
reachable.insert(CB->getBlockID());
if (!visited.count((*I)->getBlockID()))
// If we haven't previously visited the unreachable predecessor, recurse
- FindUnreachableEntryPoints(*I);
+ FindUnreachableEntryPoints(*I, reachable, visited);
}
}
}
@@ -226,3 +216,7 @@ bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
&& CB->size() == 0 // No statements
&& CB->getTerminator() == 0; // No terminator
}
+
+void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UnreachableCodeChecker>();
+}