1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
15 | #include "clang/AST/StmtObjC.h" |
16 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
17 | #include "clang/StaticAnalyzer/Core/Checker.h" |
18 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
19 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
20 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
21 | |
22 | using namespace clang; |
23 | using namespace ento; |
24 | |
25 | namespace { |
26 | class ObjCAtSyncChecker |
27 | : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > { |
28 | mutable std::unique_ptr<BuiltinBug> BT_null; |
29 | mutable std::unique_ptr<BuiltinBug> BT_undef; |
30 | |
31 | public: |
32 | void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const; |
33 | }; |
34 | } |
35 | |
36 | void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, |
37 | CheckerContext &C) const { |
38 | |
39 | const Expr *Ex = S->getSynchExpr(); |
40 | ProgramStateRef state = C.getState(); |
41 | SVal V = C.getSVal(Ex); |
42 | |
43 | |
44 | if (V.getAs<UndefinedVal>()) { |
45 | if (ExplodedNode *N = C.generateErrorNode()) { |
46 | if (!BT_undef) |
47 | BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex " |
48 | "for @synchronized")); |
49 | auto report = |
50 | llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N); |
51 | bugreporter::trackExpressionValue(N, Ex, *report); |
52 | C.emitReport(std::move(report)); |
53 | } |
54 | return; |
55 | } |
56 | |
57 | if (V.isUnknown()) |
58 | return; |
59 | |
60 | |
61 | ProgramStateRef notNullState, nullState; |
62 | std::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>()); |
63 | |
64 | if (nullState) { |
65 | if (!notNullState) { |
66 | |
67 | |
68 | if (ExplodedNode *N = C.generateNonFatalErrorNode(nullState)) { |
69 | if (!BT_null) |
70 | BT_null.reset(new BuiltinBug( |
71 | this, "Nil value used as mutex for @synchronized() " |
72 | "(no synchronization will occur)")); |
73 | auto report = |
74 | llvm::make_unique<BugReport>(*BT_null, BT_null->getDescription(), N); |
75 | bugreporter::trackExpressionValue(N, Ex, *report); |
76 | |
77 | C.emitReport(std::move(report)); |
78 | return; |
79 | } |
80 | } |
81 | |
82 | |
83 | |
84 | } |
85 | |
86 | if (notNullState) |
87 | C.addTransition(notNullState); |
88 | } |
89 | |
90 | void ento::registerObjCAtSyncChecker(CheckerManager &mgr) { |
91 | mgr.registerChecker<ObjCAtSyncChecker>(); |
92 | } |
93 | |
94 | bool ento::shouldRegisterObjCAtSyncChecker(const LangOptions &LO) { |
95 | return LO.ObjC; |
96 | } |
97 | |