blob: 1118d5e279d4a6226d463b934141dd368cd5fa7c [file] [log] [blame]
Tom Caredb2fa8a2010-07-06 21:43:29 +00001//==- IdempotentOperationChecker.cpp - Idempotent Operations ----*- 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 file defines a set of path-sensitive checks for idempotent and/or
11// tautological operations. Each potential operation is checked along all paths
12// to see if every path results in a pointless operation.
13// +-------------------------------------------+
14// |Table of idempotent/tautological operations|
15// +-------------------------------------------+
16//+--------------------------------------------------------------------------+
17//|Operator | x op x | x op 1 | 1 op x | x op 0 | 0 op x | x op ~0 | ~0 op x |
18//+--------------------------------------------------------------------------+
19// +, += | | | | x | x | |
20// -, -= | | | | x | -x | |
21// *, *= | | x | x | 0 | 0 | |
22// /, /= | 1 | x | | N/A | 0 | |
23// &, &= | x | | | 0 | 0 | x | x
24// |, |= | x | | | x | x | ~0 | ~0
25// ^, ^= | 0 | | | x | x | |
26// <<, <<= | | | | x | 0 | |
27// >>, >>= | | | | x | 0 | |
28// || | 1 | 1 | 1 | x | x | 1 | 1
29// && | 1 | x | x | 0 | 0 | x | x
30// = | x | | | | | |
31// == | 1 | | | | | |
32// >= | 1 | | | | | |
33// <= | 1 | | | | | |
34// > | 0 | | | | | |
35// < | 0 | | | | | |
36// != | 0 | | | | | |
37//===----------------------------------------------------------------------===//
38//
39// Ways to reduce false positives (that need to be implemented):
40// - Don't flag downsizing casts
41// - Improved handling of static/global variables
42// - Per-block marking of incomplete analysis
43// - Handling ~0 values
44// - False positives involving silencing unused variable warnings
45//
46// Other things TODO:
47// - Improved error messages
48// - Handle mixed assumptions (which assumptions can belong together?)
49// - Finer grained false positive control (levels)
50
51#include "GRExprEngineExperimentalChecks.h"
52#include "clang/Checker/BugReporter/BugType.h"
53#include "clang/Checker/PathSensitive/CheckerVisitor.h"
54#include "clang/Checker/PathSensitive/SVals.h"
55#include "clang/AST/Stmt.h"
56#include "llvm/ADT/DenseMap.h"
Chandler Carruth256565b2010-07-07 00:07:37 +000057#include "llvm/Support/ErrorHandling.h"
Tom Caredb2fa8a2010-07-06 21:43:29 +000058
59using namespace clang;
60
61namespace {
62class IdempotentOperationChecker
63 : public CheckerVisitor<IdempotentOperationChecker> {
64 public:
65 static void *getTag();
66 void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
67 void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
68 bool hasWorkRemaining);
69
70 private:
71 // Our assumption about a particular operation.
72 enum Assumption { Possible, Impossible, Equal, LHSis1, RHSis1, LHSis0,
73 RHSis0 };
74
75 void UpdateAssumption(Assumption &A, const Assumption &New);
76
77 /// contains* - Useful recursive methods to see if a statement contains an
78 /// element somewhere. Used in static analysis to reduce false positives.
79 static bool containsMacro(const Stmt *S);
80 static bool containsEnum(const Stmt *S);
81 static bool containsBuiltinOffsetOf(const Stmt *S);
82 static bool containsZeroConstant(const Stmt *S);
83 static bool containsOneConstant(const Stmt *S);
84 template <class T> static bool containsStmt(const Stmt *S) {
85 if (isa<T>(S))
86 return true;
87
88 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
89 ++I)
90 if (const Stmt *child = *I)
91 if (containsStmt<T>(child))
92 return true;
93
94 return false;
95 }
96
97 // Hash table
98 typedef llvm::DenseMap<const BinaryOperator *, Assumption> AssumptionMap;
99 AssumptionMap hash;
100};
101}
102
103void *IdempotentOperationChecker::getTag() {
104 static int x = 0;
105 return &x;
106}
107
108void clang::RegisterIdempotentOperationChecker(GRExprEngine &Eng) {
109 Eng.registerCheck(new IdempotentOperationChecker());
110}
111
112void IdempotentOperationChecker::PreVisitBinaryOperator(
113 CheckerContext &C,
114 const BinaryOperator *B) {
115 // Find or create an entry in the hash for this BinaryOperator instance
116 AssumptionMap::iterator i = hash.find(B);
117 Assumption &A = i == hash.end() ? hash[B] : i->second;
118
119 // If we had to create an entry, initialise the value to Possible
120 if (i == hash.end())
121 A = Possible;
122
123 // If we already have visited this node on a path that does not contain an
124 // idempotent operation, return immediately.
125 if (A == Impossible)
126 return;
127
128 // Skip binary operators containing common false positives
129 if (containsMacro(B) || containsEnum(B) || containsStmt<SizeOfAlignOfExpr>(B)
130 || containsZeroConstant(B) || containsOneConstant(B)
131 || containsBuiltinOffsetOf(B)) {
132 A = Impossible;
133 return;
134 }
135
136 const Expr *LHS = B->getLHS();
137 const Expr *RHS = B->getRHS();
138
139 const GRState *state = C.getState();
140
141 SVal LHSVal = state->getSVal(LHS);
142 SVal RHSVal = state->getSVal(RHS);
143
144 // If either value is unknown, we can't be 100% sure of all paths.
145 if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
146 A = Impossible;
147 return;
148 }
149 BinaryOperator::Opcode Op = B->getOpcode();
150
151 // Dereference the LHS SVal if this is an assign operation
152 switch (Op) {
153 default:
154 break;
155
156 // Fall through intentional
157 case BinaryOperator::AddAssign:
158 case BinaryOperator::SubAssign:
159 case BinaryOperator::MulAssign:
160 case BinaryOperator::DivAssign:
161 case BinaryOperator::AndAssign:
162 case BinaryOperator::OrAssign:
163 case BinaryOperator::XorAssign:
164 case BinaryOperator::ShlAssign:
165 case BinaryOperator::ShrAssign:
166 case BinaryOperator::Assign:
167 // Assign statements have one extra level of indirection
168 if (!isa<Loc>(LHSVal)) {
169 A = Impossible;
170 return;
171 }
172 LHSVal = state->getSVal(cast<Loc>(LHSVal));
173 }
174
175
176 // We now check for various cases which result in an idempotent operation.
177
178 // x op x
179 switch (Op) {
180 default:
181 break; // We don't care about any other operators.
182
183 // Fall through intentional
184 case BinaryOperator::SubAssign:
185 case BinaryOperator::DivAssign:
186 case BinaryOperator::AndAssign:
187 case BinaryOperator::OrAssign:
188 case BinaryOperator::XorAssign:
189 case BinaryOperator::Assign:
190 case BinaryOperator::Sub:
191 case BinaryOperator::Div:
192 case BinaryOperator::And:
193 case BinaryOperator::Or:
194 case BinaryOperator::Xor:
195 case BinaryOperator::LOr:
196 case BinaryOperator::LAnd:
197 if (LHSVal != RHSVal)
198 break;
199 UpdateAssumption(A, Equal);
200 return;
201 }
202
203 // x op 1
204 switch (Op) {
205 default:
206 break; // We don't care about any other operators.
207
208 // Fall through intentional
209 case BinaryOperator::MulAssign:
210 case BinaryOperator::DivAssign:
211 case BinaryOperator::Mul:
212 case BinaryOperator::Div:
213 case BinaryOperator::LOr:
214 case BinaryOperator::LAnd:
215 if (!RHSVal.isConstant(1))
216 break;
217 UpdateAssumption(A, RHSis1);
218 return;
219 }
220
221 // 1 op x
222 switch (Op) {
223 default:
224 break; // We don't care about any other operators.
225
226 // Fall through intentional
227 case BinaryOperator::MulAssign:
228 case BinaryOperator::Mul:
229 case BinaryOperator::LOr:
230 case BinaryOperator::LAnd:
231 if (!LHSVal.isConstant(1))
232 break;
233 UpdateAssumption(A, LHSis1);
234 return;
235 }
236
237 // x op 0
238 switch (Op) {
239 default:
240 break; // We don't care about any other operators.
241
242 // Fall through intentional
243 case BinaryOperator::AddAssign:
244 case BinaryOperator::SubAssign:
245 case BinaryOperator::MulAssign:
246 case BinaryOperator::AndAssign:
247 case BinaryOperator::OrAssign:
248 case BinaryOperator::XorAssign:
249 case BinaryOperator::Add:
250 case BinaryOperator::Sub:
251 case BinaryOperator::Mul:
252 case BinaryOperator::And:
253 case BinaryOperator::Or:
254 case BinaryOperator::Xor:
255 case BinaryOperator::Shl:
256 case BinaryOperator::Shr:
257 case BinaryOperator::LOr:
258 case BinaryOperator::LAnd:
259 if (!RHSVal.isConstant(0))
260 break;
261 UpdateAssumption(A, RHSis0);
262 return;
263 }
264
265 // 0 op x
266 switch (Op) {
267 default:
268 break; // We don't care about any other operators.
269
270 // Fall through intentional
271 //case BinaryOperator::AddAssign: // Common false positive
272 case BinaryOperator::SubAssign: // Check only if unsigned
273 case BinaryOperator::MulAssign:
274 case BinaryOperator::DivAssign:
275 case BinaryOperator::AndAssign:
276 //case BinaryOperator::OrAssign: // Common false positive
277 //case BinaryOperator::XorAssign: // Common false positive
278 case BinaryOperator::ShlAssign:
279 case BinaryOperator::ShrAssign:
280 case BinaryOperator::Add:
281 case BinaryOperator::Sub:
282 case BinaryOperator::Mul:
283 case BinaryOperator::Div:
284 case BinaryOperator::And:
285 case BinaryOperator::Or:
286 case BinaryOperator::Xor:
287 case BinaryOperator::Shl:
288 case BinaryOperator::Shr:
289 case BinaryOperator::LOr:
290 case BinaryOperator::LAnd:
291 if (!LHSVal.isConstant(0))
292 break;
293 UpdateAssumption(A, LHSis0);
294 return;
295 }
296
297 // If we get to this point, there has been a valid use of this operation.
298 A = Impossible;
299}
300
301void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
302 BugReporter &B,
303 bool hasWorkRemaining) {
304 // If there is any work remaining we cannot be 100% sure about our warnings
305 if (hasWorkRemaining)
306 return;
307
308 // Iterate over the hash to see if we have any paths with definite
309 // idempotent operations.
310 for (AssumptionMap::const_iterator i =
311 hash.begin(); i != hash.end(); ++i) {
312 if (i->second != Impossible) {
313 // Select the error message.
314 const char *msg;
315 switch (i->second) {
316 case Equal:
317 msg = "idempotent operation; both operands are always equal in value";
318 break;
319 case LHSis1:
320 msg = "idempotent operation; the left operand is always 1";
321 break;
322 case RHSis1:
323 msg = "idempotent operation; the right operand is always 1";
324 break;
325 case LHSis0:
326 msg = "idempotent operation; the left operand is always 0";
327 break;
328 case RHSis0:
329 msg = "idempotent operation; the right operand is always 0";
330 break;
331 case Impossible:
332 break;
333 case Possible:
Chandler Carruth256565b2010-07-07 00:07:37 +0000334 llvm_unreachable("Operation was never marked with an assumption");
Tom Caredb2fa8a2010-07-06 21:43:29 +0000335 }
336
337 // Create the SourceRange Arrays
338 SourceRange S[2] = { i->first->getLHS()->getSourceRange(),
339 i->first->getRHS()->getSourceRange() };
340 B.EmitBasicReport("Idempotent operation", msg, i->first->getOperatorLoc(),
341 S, 2);
342 }
343 }
344}
345
346// Updates the current assumption given the new assumption
347inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A,
348 const Assumption &New) {
349 switch (A) {
350 // If we don't currently have an assumption, set it
351 case Possible:
352 A = New;
353 return;
354
355 // If we have determined that a valid state happened, ignore the new
356 // assumption.
357 case Impossible:
358 return;
359
360 // Any other case means that we had a different assumption last time. We don't
361 // currently support mixing assumptions for diagnostic reasons, so we set
362 // our assumption to be impossible.
363 default:
364 A = Impossible;
365 return;
366 }
367}
368
369// Recursively find any substatements containing macros
370bool IdempotentOperationChecker::containsMacro(const Stmt *S) {
371 if (S->getLocStart().isMacroID())
372 return true;
373
374 if (S->getLocEnd().isMacroID())
375 return true;
376
377 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
378 ++I)
379 if (const Stmt *child = *I)
380 if (containsMacro(child))
381 return true;
382
383 return false;
384}
385
386// Recursively find any substatements containing enum constants
387bool IdempotentOperationChecker::containsEnum(const Stmt *S) {
388 const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
389
390 if (DR && isa<EnumConstantDecl>(DR->getDecl()))
391 return true;
392
393 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
394 ++I)
395 if (const Stmt *child = *I)
396 if (containsEnum(child))
397 return true;
398
399 return false;
400}
401
402// Recursively find any substatements containing __builtin_offset_of
403bool IdempotentOperationChecker::containsBuiltinOffsetOf(const Stmt *S) {
404 const UnaryOperator *UO = dyn_cast<UnaryOperator>(S);
405
406 if (UO && UO->getOpcode() == UnaryOperator::OffsetOf)
407 return true;
408
409 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
410 ++I)
411 if (const Stmt *child = *I)
412 if (containsBuiltinOffsetOf(child))
413 return true;
414
415 return false;
416}
417
418bool IdempotentOperationChecker::containsZeroConstant(const Stmt *S) {
419 const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
420 if (IL && IL->getValue() == 0)
421 return true;
422
423 const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S);
424 if (FL && FL->getValue().isZero())
425 return true;
426
427 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
428 ++I)
429 if (const Stmt *child = *I)
430 if (containsZeroConstant(child))
431 return true;
432
433 return false;
434}
435
436bool IdempotentOperationChecker::containsOneConstant(const Stmt *S) {
437 const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
438 if (IL && IL->getValue() == 1)
439 return true;
440
441 const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S);
442 const llvm::APFloat one(1.0);
443 if (FL && FL->getValue().compare(one) == llvm::APFloat::cmpEqual)
444 return true;
445
446 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
447 ++I)
448 if (const Stmt *child = *I)
449 if (containsOneConstant(child))
450 return true;
451
452 return false;
453}
454