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 "ExprEngineInternalChecks.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 20 using namespace clang; 21 using namespace ento; 22 23 namespace { 24 class UndefCapturedBlockVarChecker 25 : public CheckerVisitor<UndefCapturedBlockVarChecker> { 26 BugType *BT; 27 28 public: 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 35 void ento::RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng) { 36 Eng.registerCheck(new UndefCapturedBlockVarChecker()); 37 } 38 39 static 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 56 void 57 UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C, 58 const BlockExpr *BE) { 59 if (!BE->hasBlockDeclRefExprs()) 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("Captured block variable is uninitialized"); 86 87 // Generate a bug report. 88 llvm::SmallString<128> buf; 89 llvm::raw_svector_ostream os(buf); 90 91 os << "Variable '" << VD->getName() << "' is captured by block with " 92 "a garbage value"; 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