UndefCapturedBlockVarChecker.cpp revision 04291a7c76e16a2dc5433c80c3d13c826bf372dc
1// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This checker detects blocks that capture uninitialized values. 11// 12//===----------------------------------------------------------------------===// 13 14#include "InternalChecks.h" 15#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h" 16#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h" 17#include "clang/StaticAnalyzer/BugReporter/BugType.h" 18#include "llvm/Support/raw_ostream.h" 19 20using namespace clang; 21using namespace ento; 22 23namespace { 24class UndefCapturedBlockVarChecker 25 : public CheckerVisitor<UndefCapturedBlockVarChecker> { 26 BugType *BT; 27 28public: 29 UndefCapturedBlockVarChecker() : BT(0) {} 30 static void *getTag() { static int tag = 0; return &tag; } 31 void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); 32}; 33} // end anonymous namespace 34 35void ento::RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng) { 36 Eng.registerCheck(new UndefCapturedBlockVarChecker()); 37} 38 39static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S, 40 const VarDecl *VD){ 41 if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S)) 42 if (BR->getDecl() == VD) 43 return BR; 44 45 for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); 46 I!=E; ++I) 47 if (const Stmt *child = *I) { 48 const BlockDeclRefExpr *BR = FindBlockDeclRefExpr(child, VD); 49 if (BR) 50 return BR; 51 } 52 53 return NULL; 54} 55 56void 57UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C, 58 const BlockExpr *BE) { 59 if (!BE->getBlockDecl()->hasCaptures()) 60 return; 61 62 const GRState *state = C.getState(); 63 const BlockDataRegion *R = 64 cast<BlockDataRegion>(state->getSVal(BE).getAsRegion()); 65 66 BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), 67 E = R->referenced_vars_end(); 68 69 for (; I != E; ++I) { 70 // This VarRegion is the region associated with the block; we need 71 // the one associated with the encompassing context. 72 const VarRegion *VR = *I; 73 const VarDecl *VD = VR->getDecl(); 74 75 if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) 76 continue; 77 78 // Get the VarRegion associated with VD in the local stack frame. 79 const LocationContext *LC = C.getPredecessor()->getLocationContext(); 80 VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC); 81 82 if (state->getSVal(VR).isUndef()) 83 if (ExplodedNode *N = C.generateSink()) { 84 if (!BT) 85 BT = new BuiltinBug("uninitialized variable captured by block"); 86 87 // Generate a bug report. 88 llvm::SmallString<128> buf; 89 llvm::raw_svector_ostream os(buf); 90 91 os << "Variable '" << VD->getName() 92 << "' is uninitialized when captured by block"; 93 94 EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); 95 if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) 96 R->addRange(Ex->getSourceRange()); 97 R->addVisitorCreator(bugreporter::registerFindLastStore, VR); 98 // need location of block 99 C.EmitReport(R); 100 } 101 } 102} 103