blob: 6e6f5bdd96bf10697aa5bcdff5e1649da789d12e [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
Tom Caredf4ca422010-07-16 20:41:41 +000051#include "GRExprEngineInternalChecks.h"
Tom Caredb2fa8a2010-07-06 21:43:29 +000052#include "clang/Checker/BugReporter/BugType.h"
Tom Carea9fbf5b2010-07-27 23:26:07 +000053#include "clang/Checker/PathSensitive/CheckerHelpers.h"
Tom Caredb2fa8a2010-07-06 21:43:29 +000054#include "clang/Checker/PathSensitive/CheckerVisitor.h"
55#include "clang/Checker/PathSensitive/SVals.h"
56#include "clang/AST/Stmt.h"
57#include "llvm/ADT/DenseMap.h"
Chandler Carruth256565b2010-07-07 00:07:37 +000058#include "llvm/Support/ErrorHandling.h"
Tom Caredb2fa8a2010-07-06 21:43:29 +000059
60using namespace clang;
61
62namespace {
63class IdempotentOperationChecker
64 : public CheckerVisitor<IdempotentOperationChecker> {
65 public:
66 static void *getTag();
67 void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
68 void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
69 bool hasWorkRemaining);
70
71 private:
72 // Our assumption about a particular operation.
73 enum Assumption { Possible, Impossible, Equal, LHSis1, RHSis1, LHSis0,
74 RHSis0 };
75
76 void UpdateAssumption(Assumption &A, const Assumption &New);
77
78 /// contains* - Useful recursive methods to see if a statement contains an
79 /// element somewhere. Used in static analysis to reduce false positives.
Tom Caredf4ca422010-07-16 20:41:41 +000080 static bool isParameterSelfAssign(const Expr *LHS, const Expr *RHS);
81 static bool isTruncationExtensionAssignment(const Expr *LHS,
82 const Expr *RHS);
Tom Caredb2fa8a2010-07-06 21:43:29 +000083 static bool containsZeroConstant(const Stmt *S);
84 static bool containsOneConstant(const Stmt *S);
Tom Caredb2fa8a2010-07-06 21:43:29 +000085
86 // Hash table
87 typedef llvm::DenseMap<const BinaryOperator *, Assumption> AssumptionMap;
88 AssumptionMap hash;
89};
90}
91
92void *IdempotentOperationChecker::getTag() {
93 static int x = 0;
94 return &x;
95}
96
97void clang::RegisterIdempotentOperationChecker(GRExprEngine &Eng) {
98 Eng.registerCheck(new IdempotentOperationChecker());
99}
100
101void IdempotentOperationChecker::PreVisitBinaryOperator(
102 CheckerContext &C,
103 const BinaryOperator *B) {
104 // Find or create an entry in the hash for this BinaryOperator instance
105 AssumptionMap::iterator i = hash.find(B);
106 Assumption &A = i == hash.end() ? hash[B] : i->second;
107
108 // If we had to create an entry, initialise the value to Possible
109 if (i == hash.end())
110 A = Possible;
111
112 // If we already have visited this node on a path that does not contain an
113 // idempotent operation, return immediately.
114 if (A == Impossible)
115 return;
116
117 // Skip binary operators containing common false positives
118 if (containsMacro(B) || containsEnum(B) || containsStmt<SizeOfAlignOfExpr>(B)
119 || containsZeroConstant(B) || containsOneConstant(B)
Tom Caredf4ca422010-07-16 20:41:41 +0000120 || containsBuiltinOffsetOf(B) || containsStaticLocal(B)) {
Tom Caredb2fa8a2010-07-06 21:43:29 +0000121 A = Impossible;
122 return;
123 }
124
125 const Expr *LHS = B->getLHS();
126 const Expr *RHS = B->getRHS();
127
128 const GRState *state = C.getState();
129
130 SVal LHSVal = state->getSVal(LHS);
131 SVal RHSVal = state->getSVal(RHS);
132
133 // If either value is unknown, we can't be 100% sure of all paths.
134 if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
135 A = Impossible;
136 return;
137 }
138 BinaryOperator::Opcode Op = B->getOpcode();
139
140 // Dereference the LHS SVal if this is an assign operation
141 switch (Op) {
142 default:
143 break;
144
145 // Fall through intentional
146 case BinaryOperator::AddAssign:
147 case BinaryOperator::SubAssign:
148 case BinaryOperator::MulAssign:
149 case BinaryOperator::DivAssign:
150 case BinaryOperator::AndAssign:
151 case BinaryOperator::OrAssign:
152 case BinaryOperator::XorAssign:
153 case BinaryOperator::ShlAssign:
154 case BinaryOperator::ShrAssign:
155 case BinaryOperator::Assign:
156 // Assign statements have one extra level of indirection
157 if (!isa<Loc>(LHSVal)) {
158 A = Impossible;
159 return;
160 }
161 LHSVal = state->getSVal(cast<Loc>(LHSVal));
162 }
163
164
165 // We now check for various cases which result in an idempotent operation.
166
167 // x op x
168 switch (Op) {
169 default:
170 break; // We don't care about any other operators.
171
172 // Fall through intentional
Tom Caredf4ca422010-07-16 20:41:41 +0000173 case BinaryOperator::Assign:
174 // x Assign x has a few more false positives we can check for
175 if (isParameterSelfAssign(RHS, LHS)
176 || isTruncationExtensionAssignment(RHS, LHS)) {
177 A = Impossible;
178 return;
179 }
180
Tom Caredb2fa8a2010-07-06 21:43:29 +0000181 case BinaryOperator::SubAssign:
182 case BinaryOperator::DivAssign:
183 case BinaryOperator::AndAssign:
184 case BinaryOperator::OrAssign:
185 case BinaryOperator::XorAssign:
Tom Caredb2fa8a2010-07-06 21:43:29 +0000186 case BinaryOperator::Sub:
187 case BinaryOperator::Div:
188 case BinaryOperator::And:
189 case BinaryOperator::Or:
190 case BinaryOperator::Xor:
191 case BinaryOperator::LOr:
192 case BinaryOperator::LAnd:
193 if (LHSVal != RHSVal)
194 break;
195 UpdateAssumption(A, Equal);
196 return;
197 }
198
199 // x op 1
200 switch (Op) {
201 default:
202 break; // We don't care about any other operators.
203
204 // Fall through intentional
205 case BinaryOperator::MulAssign:
206 case BinaryOperator::DivAssign:
207 case BinaryOperator::Mul:
208 case BinaryOperator::Div:
209 case BinaryOperator::LOr:
210 case BinaryOperator::LAnd:
211 if (!RHSVal.isConstant(1))
212 break;
213 UpdateAssumption(A, RHSis1);
214 return;
215 }
216
217 // 1 op x
218 switch (Op) {
219 default:
220 break; // We don't care about any other operators.
221
222 // Fall through intentional
223 case BinaryOperator::MulAssign:
224 case BinaryOperator::Mul:
225 case BinaryOperator::LOr:
226 case BinaryOperator::LAnd:
227 if (!LHSVal.isConstant(1))
228 break;
229 UpdateAssumption(A, LHSis1);
230 return;
231 }
232
233 // x op 0
234 switch (Op) {
235 default:
236 break; // We don't care about any other operators.
237
238 // Fall through intentional
239 case BinaryOperator::AddAssign:
240 case BinaryOperator::SubAssign:
241 case BinaryOperator::MulAssign:
242 case BinaryOperator::AndAssign:
243 case BinaryOperator::OrAssign:
244 case BinaryOperator::XorAssign:
245 case BinaryOperator::Add:
246 case BinaryOperator::Sub:
247 case BinaryOperator::Mul:
248 case BinaryOperator::And:
249 case BinaryOperator::Or:
250 case BinaryOperator::Xor:
251 case BinaryOperator::Shl:
252 case BinaryOperator::Shr:
253 case BinaryOperator::LOr:
254 case BinaryOperator::LAnd:
255 if (!RHSVal.isConstant(0))
256 break;
257 UpdateAssumption(A, RHSis0);
258 return;
259 }
260
261 // 0 op x
262 switch (Op) {
263 default:
264 break; // We don't care about any other operators.
265
266 // Fall through intentional
267 //case BinaryOperator::AddAssign: // Common false positive
268 case BinaryOperator::SubAssign: // Check only if unsigned
269 case BinaryOperator::MulAssign:
270 case BinaryOperator::DivAssign:
271 case BinaryOperator::AndAssign:
272 //case BinaryOperator::OrAssign: // Common false positive
273 //case BinaryOperator::XorAssign: // Common false positive
274 case BinaryOperator::ShlAssign:
275 case BinaryOperator::ShrAssign:
276 case BinaryOperator::Add:
277 case BinaryOperator::Sub:
278 case BinaryOperator::Mul:
279 case BinaryOperator::Div:
280 case BinaryOperator::And:
281 case BinaryOperator::Or:
282 case BinaryOperator::Xor:
283 case BinaryOperator::Shl:
284 case BinaryOperator::Shr:
285 case BinaryOperator::LOr:
286 case BinaryOperator::LAnd:
287 if (!LHSVal.isConstant(0))
288 break;
289 UpdateAssumption(A, LHSis0);
290 return;
291 }
292
293 // If we get to this point, there has been a valid use of this operation.
294 A = Impossible;
295}
296
297void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000298 BugReporter &BR,
Tom Caredb2fa8a2010-07-06 21:43:29 +0000299 bool hasWorkRemaining) {
300 // If there is any work remaining we cannot be 100% sure about our warnings
Tom Carea9fbf5b2010-07-27 23:26:07 +0000301// if (hasWorkRemaining)
302// return;
Tom Caredb2fa8a2010-07-06 21:43:29 +0000303
304 // Iterate over the hash to see if we have any paths with definite
305 // idempotent operations.
306 for (AssumptionMap::const_iterator i =
307 hash.begin(); i != hash.end(); ++i) {
308 if (i->second != Impossible) {
309 // Select the error message.
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000310 const BinaryOperator *B = i->first;
311 llvm::SmallString<128> buf;
312 llvm::raw_svector_ostream os(buf);
313
Tom Caredb2fa8a2010-07-06 21:43:29 +0000314 switch (i->second) {
315 case Equal:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000316 if (B->getOpcode() == BinaryOperator::Assign)
317 os << "Assigned value is always the same as the existing value";
318 else
319 os << "Both operands to '" << B->getOpcodeStr()
320 << "' always have the same value";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000321 break;
322 case LHSis1:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000323 os << "The left operand to '" << B->getOpcodeStr() << "' is always 1";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000324 break;
325 case RHSis1:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000326 os << "The right operand to '" << B->getOpcodeStr() << "' is always 1";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000327 break;
328 case LHSis0:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000329 os << "The left operand to '" << B->getOpcodeStr() << "' is always 0";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000330 break;
331 case RHSis0:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000332 os << "The right operand to '" << B->getOpcodeStr() << "' is always 0";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000333 break;
Tom Caredb2fa8a2010-07-06 21:43:29 +0000334 case Possible:
Chandler Carruth256565b2010-07-07 00:07:37 +0000335 llvm_unreachable("Operation was never marked with an assumption");
Tom Care7dbf8182010-07-07 01:27:17 +0000336 case Impossible:
337 llvm_unreachable(0);
Tom Caredb2fa8a2010-07-06 21:43:29 +0000338 }
339
340 // Create the SourceRange Arrays
341 SourceRange S[2] = { i->first->getLHS()->getSourceRange(),
342 i->first->getRHS()->getSourceRange() };
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000343 BR.EmitBasicReport("Idempotent operation", "Dead code",
344 os.str(), i->first->getOperatorLoc(), S, 2);
Tom Caredb2fa8a2010-07-06 21:43:29 +0000345 }
346 }
347}
348
349// Updates the current assumption given the new assumption
350inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A,
351 const Assumption &New) {
352 switch (A) {
353 // If we don't currently have an assumption, set it
354 case Possible:
355 A = New;
356 return;
357
358 // If we have determined that a valid state happened, ignore the new
359 // assumption.
360 case Impossible:
361 return;
362
363 // Any other case means that we had a different assumption last time. We don't
364 // currently support mixing assumptions for diagnostic reasons, so we set
365 // our assumption to be impossible.
366 default:
367 A = Impossible;
368 return;
369 }
370}
371
Tom Caredf4ca422010-07-16 20:41:41 +0000372// Check for a statement were a parameter is self assigned (to avoid an unused
373// variable warning)
374bool IdempotentOperationChecker::isParameterSelfAssign(const Expr *LHS,
375 const Expr *RHS) {
376 LHS = LHS->IgnoreParenCasts();
377 RHS = RHS->IgnoreParenCasts();
378
379 const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS);
380 if (!LHS_DR)
381 return false;
382
383 const ParmVarDecl *PD = dyn_cast<ParmVarDecl>(LHS_DR->getDecl());
384 if (!PD)
385 return false;
386
387 const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS);
388 if (!RHS_DR)
389 return false;
390
391 return PD == RHS_DR->getDecl();
392}
393
394// Check for self casts truncating/extending a variable
395bool IdempotentOperationChecker::isTruncationExtensionAssignment(
396 const Expr *LHS,
397 const Expr *RHS) {
398
399 const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts());
400 if (!LHS_DR)
401 return false;
402
403 const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
404 if (!VD)
405 return false;
406
407 const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts());
408 if (!RHS_DR)
409 return false;
410
411 if (VD != RHS_DR->getDecl())
412 return false;
413
414 return dyn_cast<DeclRefExpr>(RHS->IgnoreParens()) == NULL;
415}
416
Tom Caredf4ca422010-07-16 20:41:41 +0000417// Check for a integer or float constant of 0
Tom Caredb2fa8a2010-07-06 21:43:29 +0000418bool 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
Tom Caredf4ca422010-07-16 20:41:41 +0000436// Check for an integer or float constant of 1
Tom Caredb2fa8a2010-07-06 21:43:29 +0000437bool IdempotentOperationChecker::containsOneConstant(const Stmt *S) {
438 const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
439 if (IL && IL->getValue() == 1)
440 return true;
441
Ted Kremenek45329312010-07-17 00:40:32 +0000442 if (const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S)) {
443 const llvm::APFloat &val = FL->getValue();
444 const llvm::APFloat one(val.getSemantics(), 1);
445 if (val.compare(one) == llvm::APFloat::cmpEqual)
446 return true;
447 }
Tom Caredb2fa8a2010-07-06 21:43:29 +0000448
449 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
450 ++I)
451 if (const Stmt *child = *I)
452 if (containsOneConstant(child))
453 return true;
454
455 return false;
456}
457