]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
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 "ClangSACheckers.h" | |
15 | #include "clang/StaticAnalyzer/Core/Checker.h" | |
16 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" | |
17 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" | |
18 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" | |
19 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" | |
20 | #include "llvm/ADT/SmallString.h" | |
21 | #include "llvm/Support/raw_ostream.h" | |
22 | ||
23 | using namespace clang; | |
24 | using namespace ento; | |
25 | ||
26 | namespace { | |
27 | class UndefCapturedBlockVarChecker | |
28 | : public Checker< check::PostStmt<BlockExpr> > { | |
29 | mutable OwningPtr<BugType> BT; | |
30 | ||
31 | public: | |
32 | void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; | |
33 | }; | |
34 | } // end anonymous namespace | |
35 | ||
36 | static const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S, | |
37 | const VarDecl *VD) { | |
38 | if (const DeclRefExpr *BR = dyn_cast<DeclRefExpr>(S)) | |
39 | if (BR->getDecl() == VD) | |
40 | return BR; | |
41 | ||
42 | for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); | |
43 | I!=E; ++I) | |
44 | if (const Stmt *child = *I) { | |
45 | const DeclRefExpr *BR = FindBlockDeclRefExpr(child, VD); | |
46 | if (BR) | |
47 | return BR; | |
48 | } | |
49 | ||
50 | return NULL; | |
51 | } | |
52 | ||
53 | void | |
54 | UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, | |
55 | CheckerContext &C) const { | |
56 | if (!BE->getBlockDecl()->hasCaptures()) | |
57 | return; | |
58 | ||
59 | ProgramStateRef state = C.getState(); | |
60 | const BlockDataRegion *R = | |
61 | cast<BlockDataRegion>(state->getSVal(BE, | |
62 | C.getLocationContext()).getAsRegion()); | |
63 | ||
64 | BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), | |
65 | E = R->referenced_vars_end(); | |
66 | ||
67 | for (; I != E; ++I) { | |
68 | // This VarRegion is the region associated with the block; we need | |
69 | // the one associated with the encompassing context. | |
70 | const VarRegion *VR = *I; | |
71 | const VarDecl *VD = VR->getDecl(); | |
72 | ||
73 | if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) | |
74 | continue; | |
75 | ||
76 | // Get the VarRegion associated with VD in the local stack frame. | |
77 | const LocationContext *LC = C.getLocationContext(); | |
78 | VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC); | |
79 | SVal VRVal = state->getSVal(VR); | |
80 | ||
81 | if (VRVal.isUndef()) | |
82 | if (ExplodedNode *N = C.generateSink()) { | |
83 | if (!BT) | |
84 | BT.reset(new BuiltinBug("uninitialized variable captured by block")); | |
85 | ||
86 | // Generate a bug report. | |
87 | SmallString<128> buf; | |
88 | llvm::raw_svector_ostream os(buf); | |
89 | ||
90 | os << "Variable '" << VD->getName() | |
91 | << "' is uninitialized when captured by block"; | |
92 | ||
93 | BugReport *R = new BugReport(*BT, os.str(), N); | |
94 | if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) | |
95 | R->addRange(Ex->getSourceRange()); | |
96 | R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR)); | |
97 | R->disablePathPruning(); | |
98 | // need location of block | |
99 | C.EmitReport(R); | |
100 | } | |
101 | } | |
102 | } | |
103 | ||
104 | void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) { | |
105 | mgr.registerChecker<UndefCapturedBlockVarChecker>(); | |
106 | } |