UndefCapturedBlockVarChecker.cpp revision 469a1eb996e1cb0be54f9b210f836afbddcbb2cc
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
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