blob: 267e747928a245d0e1e5233e49d593895c21ad2a [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.
Ted Kremenekfe97fa12010-08-02 20:33:02 +000073 enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0,
Tom Caredb2fa8a2010-07-06 21:43:29 +000074 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) {
Ted Kremenekfe97fa12010-08-02 20:33:02 +0000104 // Find or create an entry in the hash for this BinaryOperator instance.
105 // If we haven't done a lookup before, it will get default initialized to
106 // 'Possible'.
107 Assumption &A = hash[B];
Tom Caredb2fa8a2010-07-06 21:43:29 +0000108
109 // If we already have visited this node on a path that does not contain an
110 // idempotent operation, return immediately.
111 if (A == Impossible)
112 return;
113
114 // Skip binary operators containing common false positives
115 if (containsMacro(B) || containsEnum(B) || containsStmt<SizeOfAlignOfExpr>(B)
116 || containsZeroConstant(B) || containsOneConstant(B)
Tom Caredf4ca422010-07-16 20:41:41 +0000117 || containsBuiltinOffsetOf(B) || containsStaticLocal(B)) {
Tom Caredb2fa8a2010-07-06 21:43:29 +0000118 A = Impossible;
119 return;
120 }
121
122 const Expr *LHS = B->getLHS();
123 const Expr *RHS = B->getRHS();
124
125 const GRState *state = C.getState();
126
127 SVal LHSVal = state->getSVal(LHS);
128 SVal RHSVal = state->getSVal(RHS);
129
130 // If either value is unknown, we can't be 100% sure of all paths.
131 if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
132 A = Impossible;
133 return;
134 }
135 BinaryOperator::Opcode Op = B->getOpcode();
136
137 // Dereference the LHS SVal if this is an assign operation
138 switch (Op) {
139 default:
140 break;
141
142 // Fall through intentional
143 case BinaryOperator::AddAssign:
144 case BinaryOperator::SubAssign:
145 case BinaryOperator::MulAssign:
146 case BinaryOperator::DivAssign:
147 case BinaryOperator::AndAssign:
148 case BinaryOperator::OrAssign:
149 case BinaryOperator::XorAssign:
150 case BinaryOperator::ShlAssign:
151 case BinaryOperator::ShrAssign:
152 case BinaryOperator::Assign:
153 // Assign statements have one extra level of indirection
154 if (!isa<Loc>(LHSVal)) {
155 A = Impossible;
156 return;
157 }
158 LHSVal = state->getSVal(cast<Loc>(LHSVal));
159 }
160
161
162 // We now check for various cases which result in an idempotent operation.
163
164 // x op x
165 switch (Op) {
166 default:
167 break; // We don't care about any other operators.
168
169 // Fall through intentional
Tom Caredf4ca422010-07-16 20:41:41 +0000170 case BinaryOperator::Assign:
171 // x Assign x has a few more false positives we can check for
172 if (isParameterSelfAssign(RHS, LHS)
173 || isTruncationExtensionAssignment(RHS, LHS)) {
174 A = Impossible;
175 return;
176 }
177
Tom Caredb2fa8a2010-07-06 21:43:29 +0000178 case BinaryOperator::SubAssign:
179 case BinaryOperator::DivAssign:
180 case BinaryOperator::AndAssign:
181 case BinaryOperator::OrAssign:
182 case BinaryOperator::XorAssign:
Tom Caredb2fa8a2010-07-06 21:43:29 +0000183 case BinaryOperator::Sub:
184 case BinaryOperator::Div:
185 case BinaryOperator::And:
186 case BinaryOperator::Or:
187 case BinaryOperator::Xor:
188 case BinaryOperator::LOr:
189 case BinaryOperator::LAnd:
190 if (LHSVal != RHSVal)
191 break;
192 UpdateAssumption(A, Equal);
193 return;
194 }
195
196 // x op 1
197 switch (Op) {
198 default:
199 break; // We don't care about any other operators.
200
201 // Fall through intentional
202 case BinaryOperator::MulAssign:
203 case BinaryOperator::DivAssign:
204 case BinaryOperator::Mul:
205 case BinaryOperator::Div:
206 case BinaryOperator::LOr:
207 case BinaryOperator::LAnd:
208 if (!RHSVal.isConstant(1))
209 break;
210 UpdateAssumption(A, RHSis1);
211 return;
212 }
213
214 // 1 op x
215 switch (Op) {
216 default:
217 break; // We don't care about any other operators.
218
219 // Fall through intentional
220 case BinaryOperator::MulAssign:
221 case BinaryOperator::Mul:
222 case BinaryOperator::LOr:
223 case BinaryOperator::LAnd:
224 if (!LHSVal.isConstant(1))
225 break;
226 UpdateAssumption(A, LHSis1);
227 return;
228 }
229
230 // x op 0
231 switch (Op) {
232 default:
233 break; // We don't care about any other operators.
234
235 // Fall through intentional
236 case BinaryOperator::AddAssign:
237 case BinaryOperator::SubAssign:
238 case BinaryOperator::MulAssign:
239 case BinaryOperator::AndAssign:
240 case BinaryOperator::OrAssign:
241 case BinaryOperator::XorAssign:
242 case BinaryOperator::Add:
243 case BinaryOperator::Sub:
244 case BinaryOperator::Mul:
245 case BinaryOperator::And:
246 case BinaryOperator::Or:
247 case BinaryOperator::Xor:
248 case BinaryOperator::Shl:
249 case BinaryOperator::Shr:
250 case BinaryOperator::LOr:
251 case BinaryOperator::LAnd:
252 if (!RHSVal.isConstant(0))
253 break;
254 UpdateAssumption(A, RHSis0);
255 return;
256 }
257
258 // 0 op x
259 switch (Op) {
260 default:
261 break; // We don't care about any other operators.
262
263 // Fall through intentional
264 //case BinaryOperator::AddAssign: // Common false positive
265 case BinaryOperator::SubAssign: // Check only if unsigned
266 case BinaryOperator::MulAssign:
267 case BinaryOperator::DivAssign:
268 case BinaryOperator::AndAssign:
269 //case BinaryOperator::OrAssign: // Common false positive
270 //case BinaryOperator::XorAssign: // Common false positive
271 case BinaryOperator::ShlAssign:
272 case BinaryOperator::ShrAssign:
273 case BinaryOperator::Add:
274 case BinaryOperator::Sub:
275 case BinaryOperator::Mul:
276 case BinaryOperator::Div:
277 case BinaryOperator::And:
278 case BinaryOperator::Or:
279 case BinaryOperator::Xor:
280 case BinaryOperator::Shl:
281 case BinaryOperator::Shr:
282 case BinaryOperator::LOr:
283 case BinaryOperator::LAnd:
284 if (!LHSVal.isConstant(0))
285 break;
286 UpdateAssumption(A, LHSis0);
287 return;
288 }
289
290 // If we get to this point, there has been a valid use of this operation.
291 A = Impossible;
292}
293
294void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000295 BugReporter &BR,
Tom Caredb2fa8a2010-07-06 21:43:29 +0000296 bool hasWorkRemaining) {
297 // If there is any work remaining we cannot be 100% sure about our warnings
Tom Care216b2012010-07-30 21:14:15 +0000298 if (hasWorkRemaining)
299 return;
Tom Caredb2fa8a2010-07-06 21:43:29 +0000300
301 // Iterate over the hash to see if we have any paths with definite
302 // idempotent operations.
303 for (AssumptionMap::const_iterator i =
304 hash.begin(); i != hash.end(); ++i) {
305 if (i->second != Impossible) {
306 // Select the error message.
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000307 const BinaryOperator *B = i->first;
308 llvm::SmallString<128> buf;
309 llvm::raw_svector_ostream os(buf);
310
Tom Caredb2fa8a2010-07-06 21:43:29 +0000311 switch (i->second) {
312 case Equal:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000313 if (B->getOpcode() == BinaryOperator::Assign)
314 os << "Assigned value is always the same as the existing value";
315 else
316 os << "Both operands to '" << B->getOpcodeStr()
317 << "' always have the same value";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000318 break;
319 case LHSis1:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000320 os << "The left operand to '" << B->getOpcodeStr() << "' is always 1";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000321 break;
322 case RHSis1:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000323 os << "The right operand to '" << B->getOpcodeStr() << "' is always 1";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000324 break;
325 case LHSis0:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000326 os << "The left operand to '" << B->getOpcodeStr() << "' is always 0";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000327 break;
328 case RHSis0:
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000329 os << "The right operand to '" << B->getOpcodeStr() << "' is always 0";
Tom Caredb2fa8a2010-07-06 21:43:29 +0000330 break;
Tom Caredb2fa8a2010-07-06 21:43:29 +0000331 case Possible:
Chandler Carruth256565b2010-07-07 00:07:37 +0000332 llvm_unreachable("Operation was never marked with an assumption");
Tom Care7dbf8182010-07-07 01:27:17 +0000333 case Impossible:
334 llvm_unreachable(0);
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() };
Ted Kremenek3e5637f2010-07-27 18:49:08 +0000340 BR.EmitBasicReport("Idempotent operation", "Dead code",
341 os.str(), i->first->getOperatorLoc(), S, 2);
Tom Caredb2fa8a2010-07-06 21:43:29 +0000342 }
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
Tom Caredf4ca422010-07-16 20:41:41 +0000369// Check for a statement were a parameter is self assigned (to avoid an unused
370// variable warning)
371bool IdempotentOperationChecker::isParameterSelfAssign(const Expr *LHS,
372 const Expr *RHS) {
373 LHS = LHS->IgnoreParenCasts();
374 RHS = RHS->IgnoreParenCasts();
375
376 const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS);
377 if (!LHS_DR)
378 return false;
379
380 const ParmVarDecl *PD = dyn_cast<ParmVarDecl>(LHS_DR->getDecl());
381 if (!PD)
382 return false;
383
384 const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS);
385 if (!RHS_DR)
386 return false;
387
388 return PD == RHS_DR->getDecl();
389}
390
391// Check for self casts truncating/extending a variable
392bool IdempotentOperationChecker::isTruncationExtensionAssignment(
393 const Expr *LHS,
394 const Expr *RHS) {
395
396 const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts());
397 if (!LHS_DR)
398 return false;
399
400 const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
401 if (!VD)
402 return false;
403
404 const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts());
405 if (!RHS_DR)
406 return false;
407
408 if (VD != RHS_DR->getDecl())
409 return false;
410
411 return dyn_cast<DeclRefExpr>(RHS->IgnoreParens()) == NULL;
412}
413
Tom Caredf4ca422010-07-16 20:41:41 +0000414// Check for a integer or float constant of 0
Tom Caredb2fa8a2010-07-06 21:43:29 +0000415bool IdempotentOperationChecker::containsZeroConstant(const Stmt *S) {
416 const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
417 if (IL && IL->getValue() == 0)
418 return true;
419
420 const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S);
421 if (FL && FL->getValue().isZero())
422 return true;
423
424 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
425 ++I)
426 if (const Stmt *child = *I)
427 if (containsZeroConstant(child))
428 return true;
429
430 return false;
431}
432
Tom Caredf4ca422010-07-16 20:41:41 +0000433// Check for an integer or float constant of 1
Tom Caredb2fa8a2010-07-06 21:43:29 +0000434bool IdempotentOperationChecker::containsOneConstant(const Stmt *S) {
435 const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
436 if (IL && IL->getValue() == 1)
437 return true;
438
Ted Kremenek45329312010-07-17 00:40:32 +0000439 if (const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S)) {
440 const llvm::APFloat &val = FL->getValue();
441 const llvm::APFloat one(val.getSemantics(), 1);
442 if (val.compare(one) == llvm::APFloat::cmpEqual)
443 return true;
444 }
Tom Caredb2fa8a2010-07-06 21:43:29 +0000445
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