blob: 2b45c95843e3935c9b8ef39e077eab5a416926fe [file] [log] [blame]
Ted Kremenek94fd0b82010-02-16 08:33:59 +00001// 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
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000014#include "ExprEngineInternalChecks.h"
Argyrios Kyrtzidis98cabba2010-12-22 18:51:49 +000015#include "clang/GR/PathSensitive/CheckerVisitor.h"
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000016#include "clang/GR/PathSensitive/ExprEngine.h"
Argyrios Kyrtzidis98cabba2010-12-22 18:51:49 +000017#include "clang/GR/BugReporter/BugType.h"
Ted Kremenek94fd0b82010-02-16 08:33:59 +000018#include "llvm/Support/raw_ostream.h"
19
20using namespace clang;
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000021using namespace GR;
Ted Kremenek94fd0b82010-02-16 08:33:59 +000022
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
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000035void GR::RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng) {
Ted Kremenek94fd0b82010-02-16 08:33:59 +000036 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->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();
Ted Kremenekc8413fd2010-12-02 07:49:45 +000080 VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC);
Ted Kremenek94fd0b82010-02-16 08:33:59 +000081
82 if (state->getSVal(VR).isUndef())
Ted Kremenekd048c6e2010-12-20 21:19:09 +000083 if (ExplodedNode *N = C.generateSink()) {
Ted Kremenek94fd0b82010-02-16 08:33:59 +000084 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}