diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-02-16 08:33:59 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-02-16 08:33:59 +0000 |
commit | 94fd0b8c88db9b1cd99457d3cd8cd333341dd39c (patch) | |
tree | aacf7dcf58f0a413b1a325bb9da5a78f64090876 /lib | |
parent | 3dbd3d5c04cd5abd7dfd83b15f51d7c610a3c512 (diff) |
Add simpler checker to check if variables captured by a block are uninitialized.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96341 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Checker/BugReporterVisitors.cpp | 20 | ||||
-rw-r--r-- | lib/Checker/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Checker/GRExprEngine.cpp | 1 | ||||
-rw-r--r-- | lib/Checker/GRExprEngineInternalChecks.h | 2 | ||||
-rw-r--r-- | lib/Checker/UndefCapturedBlockVarChecker.cpp | 101 |
5 files changed, 123 insertions, 2 deletions
diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index b8f657b31b..6cf41b14dc 100644 --- a/lib/Checker/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -323,7 +323,7 @@ void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC, if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V) || V.isUndef()) { - registerFindLastStore(BRC, R, V); + ::registerFindLastStore(BRC, R, V); } } } @@ -347,3 +347,21 @@ void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC, } } } + +void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC, + const void *data, + const ExplodedNode* N) { + + const MemRegion *R = static_cast<const MemRegion*>(data); + + if (!R) + return; + + const GRState *state = N->getState(); + SVal V = state->getSVal(R); + + if (V.isUnknown()) + return; + + BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); +} diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index 2aca818caa..7b21d08dcb 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -58,6 +58,7 @@ add_clang_library(clangChecker Store.cpp SymbolManager.cpp UndefBranchChecker.cpp + UndefCapturedBlockVarChecker.cpp UndefResultChecker.cpp UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 7f40d4db1c..7f86319374 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -311,6 +311,7 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { RegisterUndefinedArraySubscriptChecker(Eng); RegisterUndefinedAssignmentChecker(Eng); RegisterUndefBranchChecker(Eng); + RegisterUndefCapturedBlockVarChecker(Eng); RegisterUndefResultChecker(Eng); // This is not a checker yet. diff --git a/lib/Checker/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h index 1246703b86..64a930d504 100644 --- a/lib/Checker/GRExprEngineInternalChecks.h +++ b/lib/Checker/GRExprEngineInternalChecks.h @@ -36,8 +36,8 @@ void RegisterArrayBoundChecker(GRExprEngine &Eng); void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); void RegisterUndefBranchChecker(GRExprEngine &Eng); +void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng); void RegisterUndefResultChecker(GRExprEngine &Eng); - void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); void RegisterOSAtomicChecker(GRExprEngine &Eng); diff --git a/lib/Checker/UndefCapturedBlockVarChecker.cpp b/lib/Checker/UndefCapturedBlockVarChecker.cpp new file mode 100644 index 0000000000..a8d7284b40 --- /dev/null +++ b/lib/Checker/UndefCapturedBlockVarChecker.cpp @@ -0,0 +1,101 @@ +// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker detects blocks that capture uninitialized values. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +namespace { +class UndefCapturedBlockVarChecker + : public CheckerVisitor<UndefCapturedBlockVarChecker> { + BugType *BT; + +public: + UndefCapturedBlockVarChecker() : BT(0) {} + static void *getTag() { static int tag = 0; return &tag; } + void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); +}; +} // end anonymous namespace + +void clang::RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UndefCapturedBlockVarChecker()); +} + +static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S, + const VarDecl *VD){ + if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S)) + if (BR->getDecl() == VD) + return BR; + + for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); + I!=E; ++I) + if (const Stmt *child = *I) { + const BlockDeclRefExpr *BR = FindBlockDeclRefExpr(child, VD); + if (BR) + return BR; + } + + return NULL; +} + +void +UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C, + const BlockExpr *BE) { + if (!BE->hasBlockDeclRefExprs()) + return; + + const GRState *state = C.getState(); + const BlockDataRegion *R = + cast<BlockDataRegion>(state->getSVal(BE).getAsRegion()); + + BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), + E = R->referenced_vars_end(); + + for (; I != E; ++I) { + // This VarRegion is the region associated with the block; we need + // the one associated with the encompassing context. + const VarRegion *VR = *I; + const VarDecl *VD = VR->getDecl(); + + if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) + continue; + + // Get the VarRegion associated with VD in the local stack frame. + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + VR = C.getValueManager().getRegionManager().getVarRegion(VD, LC); + + if (state->getSVal(VR).isUndef()) + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT) + BT = new BuiltinBug("Captured block variable is uninitialized"); + + // Generate a bug report. + llvm::SmallString<128> buf; + llvm::raw_svector_ostream os(buf); + + os << "Variable '" << VD->getName() << "' is captured by block with " + "a garbage value"; + + EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); + if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) + R->addRange(Ex->getSourceRange()); + R->addVisitorCreator(bugreporter::registerFindLastStore, VR); + // need location of block + C.EmitReport(R); + } + } +} |