Author: kremenek Date: Tue Feb 16 02:33:59 2010 New Revision: 96341 URL: http://llvm.org/viewvc/llvm-project?rev=96341&view=rev Log: Add simpler checker to check if variables captured by a block are uninitialized.
Added: cfe/trunk/lib/Checker/UndefCapturedBlockVarChecker.cpp Modified: cfe/trunk/include/clang/Checker/BugReporter/BugReporter.h cfe/trunk/lib/Checker/BugReporterVisitors.cpp cfe/trunk/lib/Checker/CMakeLists.txt cfe/trunk/lib/Checker/GRExprEngine.cpp cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h cfe/trunk/test/Analysis/blocks.m Modified: cfe/trunk/include/clang/Checker/BugReporter/BugReporter.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/BugReporter/BugReporter.h?rev=96341&r1=96340&r2=96341&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/BugReporter/BugReporter.h (original) +++ cfe/trunk/include/clang/Checker/BugReporter/BugReporter.h Tue Feb 16 02:33:59 2010 @@ -202,7 +202,7 @@ ~RangedBugReport(); // FIXME: Move this out of line. - void addRange(SourceRange R) { + void addRange(SourceRange R) { assert(R.isValid()); Ranges.push_back(R); } @@ -464,6 +464,10 @@ void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt, const ExplodedNode* N); +void registerFindLastStore(BugReporterContext& BRC, const void *memregion, + const ExplodedNode *N); + + } // end namespace clang::bugreporter //===----------------------------------------------------------------------===// Modified: cfe/trunk/lib/Checker/BugReporterVisitors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/BugReporterVisitors.cpp?rev=96341&r1=96340&r2=96341&view=diff ============================================================================== --- cfe/trunk/lib/Checker/BugReporterVisitors.cpp (original) +++ cfe/trunk/lib/Checker/BugReporterVisitors.cpp Tue Feb 16 02:33:59 2010 @@ -323,7 +323,7 @@ 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::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)); +} Modified: cfe/trunk/lib/Checker/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CMakeLists.txt?rev=96341&r1=96340&r2=96341&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CMakeLists.txt (original) +++ cfe/trunk/lib/Checker/CMakeLists.txt Tue Feb 16 02:33:59 2010 @@ -58,6 +58,7 @@ Store.cpp SymbolManager.cpp UndefBranchChecker.cpp + UndefCapturedBlockVarChecker.cpp UndefResultChecker.cpp UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=96341&r1=96340&r2=96341&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Tue Feb 16 02:33:59 2010 @@ -311,6 +311,7 @@ RegisterUndefinedArraySubscriptChecker(Eng); RegisterUndefinedAssignmentChecker(Eng); RegisterUndefBranchChecker(Eng); + RegisterUndefCapturedBlockVarChecker(Eng); RegisterUndefResultChecker(Eng); // This is not a checker yet. Modified: cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h?rev=96341&r1=96340&r2=96341&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h (original) +++ cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Tue Feb 16 02:33:59 2010 @@ -36,8 +36,8 @@ 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); Added: cfe/trunk/lib/Checker/UndefCapturedBlockVarChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/UndefCapturedBlockVarChecker.cpp?rev=96341&view=auto ============================================================================== --- cfe/trunk/lib/Checker/UndefCapturedBlockVarChecker.cpp (added) +++ cfe/trunk/lib/Checker/UndefCapturedBlockVarChecker.cpp Tue Feb 16 02:33:59 2010 @@ -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); + } + } +} Modified: cfe/trunk/test/Analysis/blocks.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/blocks.m?rev=96341&r1=96340&r2=96341&view=diff ============================================================================== --- cfe/trunk/test/Analysis/blocks.m (original) +++ cfe/trunk/test/Analysis/blocks.m Tue Feb 16 02:33:59 2010 @@ -67,3 +67,19 @@ __builtin_va_end(args); } + +// test2 - Test that captured variables that are uninitialized are flagged +// as such. +void test2() { + static int y = 0; + int x; + ^{ y = x + 1; }(); // expected-warning{{Variable 'x' is captured by block with a garbage value}} +} + +void test2_b() { + static int y = 0; + __block int x; + // This is also a bug, but should be found not by checking the value + // 'x' is bound at block creation. + ^{ y = x + 1; }(); // no-warning +} _______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits