1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
14 | #include "clang/AST/Attr.h" |
15 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
16 | #include "clang/StaticAnalyzer/Core/Checker.h" |
17 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
18 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
19 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.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 std::unique_ptr<BugType> BT; |
30 | |
31 | public: |
32 | void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; |
33 | }; |
34 | } |
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 (const Stmt *Child : S->children()) |
43 | if (Child) |
44 | if (const DeclRefExpr *BR = FindBlockDeclRefExpr(Child, VD)) |
45 | return BR; |
46 | |
47 | return nullptr; |
48 | } |
49 | |
50 | void |
51 | UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, |
52 | CheckerContext &C) const { |
53 | if (!BE->getBlockDecl()->hasCaptures()) |
54 | return; |
55 | |
56 | ProgramStateRef state = C.getState(); |
57 | auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion()); |
58 | |
59 | BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), |
60 | E = R->referenced_vars_end(); |
61 | |
62 | for (; I != E; ++I) { |
63 | |
64 | |
65 | const VarRegion *VR = I.getCapturedRegion(); |
66 | const VarDecl *VD = VR->getDecl(); |
67 | |
68 | if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage()) |
69 | continue; |
70 | |
71 | |
72 | if (Optional<UndefinedVal> V = |
73 | state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) { |
74 | if (ExplodedNode *N = C.generateErrorNode()) { |
75 | if (!BT) |
76 | BT.reset( |
77 | new BuiltinBug(this, "uninitialized variable captured by block")); |
78 | |
79 | |
80 | SmallString<128> buf; |
81 | llvm::raw_svector_ostream os(buf); |
82 | |
83 | os << "Variable '" << VD->getName() |
84 | << "' is uninitialized when captured by block"; |
85 | |
86 | auto R = llvm::make_unique<BugReport>(*BT, os.str(), N); |
87 | if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) |
88 | R->addRange(Ex->getSourceRange()); |
89 | R->addVisitor(llvm::make_unique<FindLastStoreBRVisitor>( |
90 | *V, VR, false)); |
91 | R->disablePathPruning(); |
92 | |
93 | C.emitReport(std::move(R)); |
94 | } |
95 | } |
96 | } |
97 | } |
98 | |
99 | void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) { |
100 | mgr.registerChecker<UndefCapturedBlockVarChecker>(); |
101 | } |
102 | |
103 | bool ento::shouldRegisterUndefCapturedBlockVarChecker(const LangOptions &LO) { |
104 | return true; |
105 | } |
106 | |