1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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 | |
20 | using namespace clang; |
21 | using namespace ento; |
22 | |
23 | namespace { |
24 | class BoolAssignmentChecker : public Checker< check::Bind > { |
25 | mutable std::unique_ptr<BuiltinBug> BT; |
26 | void emitReport(ProgramStateRef state, CheckerContext &C) const; |
27 | public: |
28 | void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; |
29 | }; |
30 | } |
31 | |
32 | void BoolAssignmentChecker::emitReport(ProgramStateRef state, |
33 | CheckerContext &C) const { |
34 | if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) { |
35 | if (!BT) |
36 | BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value")); |
37 | C.emitReport(llvm::make_unique<BugReport>(*BT, BT->getDescription(), N)); |
38 | } |
39 | } |
40 | |
41 | static bool isBooleanType(QualType Ty) { |
42 | if (Ty->isBooleanType()) |
43 | return true; |
44 | |
45 | if (const TypedefType *TT = Ty->getAs<TypedefType>()) |
46 | return TT->getDecl()->getName() == "BOOL" || |
47 | TT->getDecl()->getName() == "_Bool" || |
48 | TT->getDecl()->getName() == "Boolean"; |
49 | |
50 | return false; |
51 | } |
52 | |
53 | void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S, |
54 | CheckerContext &C) const { |
55 | |
56 | |
57 | const TypedValueRegion *TR = |
58 | dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion()); |
59 | |
60 | if (!TR) |
61 | return; |
62 | |
63 | QualType valTy = TR->getValueType(); |
64 | |
65 | if (!isBooleanType(valTy)) |
66 | return; |
67 | |
68 | |
69 | |
70 | |
71 | Optional<DefinedSVal> DV = val.getAs<DefinedSVal>(); |
72 | if (!DV) |
73 | return; |
74 | |
75 | |
76 | |
77 | |
78 | ProgramStateRef state = C.getState(); |
79 | SValBuilder &svalBuilder = C.getSValBuilder(); |
80 | ConstraintManager &CM = C.getConstraintManager(); |
81 | |
82 | |
83 | DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy); |
84 | SVal greaterThanOrEqualToZeroVal = |
85 | svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal, |
86 | svalBuilder.getConditionType()); |
87 | |
88 | Optional<DefinedSVal> greaterThanEqualToZero = |
89 | greaterThanOrEqualToZeroVal.getAs<DefinedSVal>(); |
90 | |
91 | if (!greaterThanEqualToZero) { |
92 | |
93 | |
94 | return; |
95 | } |
96 | |
97 | ProgramStateRef stateLT, stateGE; |
98 | std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero); |
99 | |
100 | |
101 | if (stateLT) { |
102 | |
103 | |
104 | |
105 | |
106 | if (!stateGE) |
107 | emitReport(stateLT, C); |
108 | |
109 | |
110 | return; |
111 | } |
112 | |
113 | |
114 | |
115 | assert(stateGE == state); |
116 | |
117 | |
118 | |
119 | DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy); |
120 | SVal lessThanEqToOneVal = |
121 | svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal, |
122 | svalBuilder.getConditionType()); |
123 | |
124 | Optional<DefinedSVal> lessThanEqToOne = |
125 | lessThanEqToOneVal.getAs<DefinedSVal>(); |
126 | |
127 | if (!lessThanEqToOne) { |
128 | |
129 | |
130 | return; |
131 | } |
132 | |
133 | ProgramStateRef stateGT, stateLE; |
134 | std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne); |
135 | |
136 | |
137 | if (stateGT) { |
138 | |
139 | |
140 | |
141 | |
142 | if (!stateLE) |
143 | emitReport(stateGT, C); |
144 | |
145 | |
146 | return; |
147 | } |
148 | |
149 | |
150 | |
151 | assert(stateLE == state); |
152 | } |
153 | |
154 | void ento::registerBoolAssignmentChecker(CheckerManager &mgr) { |
155 | mgr.registerChecker<BoolAssignmentChecker>(); |
156 | } |
157 | |
158 | bool ento::shouldRegisterBoolAssignmentChecker(const LangOptions &LO) { |
159 | return true; |
160 | } |
161 | |