| Argyrios Kyrtzidis | c9f2e0f | 2011-02-15 22:55:14 +0000 | [diff] [blame] | 1 | // RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps -verify %s | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 2 |  | 
 | 3 | // Basic tests | 
 | 4 |  | 
 | 5 | extern void test(int i); | 
| Ted Kremenek | 4532931 | 2010-07-17 00:40:32 +0000 | [diff] [blame] | 6 | extern void test_f(float f); | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 7 |  | 
| Tom Care | 245adab | 2010-08-18 21:17:24 +0000 | [diff] [blame] | 8 | unsigned basic() { | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 9 |   int x = 10, zero = 0, one = 1; | 
 | 10 |  | 
 | 11 |   // x op x | 
| Ted Kremenek | 3e5637f | 2010-07-27 18:49:08 +0000 | [diff] [blame] | 12 |   x = x;        // expected-warning {{Assigned value is always the same as the existing value}} | 
 | 13 |   test(x - x);  // expected-warning {{Both operands to '-' always have the same value}} | 
 | 14 |   x -= x;       // expected-warning {{Both operands to '-=' always have the same value}} | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 15 |   x = 10;       // no-warning | 
| Ted Kremenek | 3e5637f | 2010-07-27 18:49:08 +0000 | [diff] [blame] | 16 |   test(x / x);  // expected-warning {{Both operands to '/' always have the same value}} | 
 | 17 |   x /= x;       // expected-warning {{Both operands to '/=' always have the same value}} | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 18 |   x = 10;       // no-warning | 
| Ted Kremenek | 3e5637f | 2010-07-27 18:49:08 +0000 | [diff] [blame] | 19 |   test(x & x);  // expected-warning {{Both operands to '&' always have the same value}} | 
 | 20 |   x &= x;       // expected-warning {{Both operands to '&=' always have the same value}} | 
 | 21 |   test(x | x);  // expected-warning {{Both operands to '|' always have the same value}} | 
 | 22 |   x |= x;       // expected-warning {{Both operands to '|=' always have the same value}} | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 23 |  | 
 | 24 |   // x op 1 | 
| Ted Kremenek | 3e5637f | 2010-07-27 18:49:08 +0000 | [diff] [blame] | 25 |   test(x * one);  // expected-warning {{The right operand to '*' is always 1}} | 
 | 26 |   x *= one;       // expected-warning {{The right operand to '*=' is always 1}} | 
 | 27 |   test(x / one);  // expected-warning {{The right operand to '/' is always 1}} | 
 | 28 |   x /= one;       // expected-warning {{The right operand to '/=' is always 1}} | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 29 |  | 
 | 30 |   // 1 op x | 
| Ted Kremenek | 3e5637f | 2010-07-27 18:49:08 +0000 | [diff] [blame] | 31 |   test(one * x);   // expected-warning {{The left operand to '*' is always 1}} | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 32 |  | 
 | 33 |   // x op 0 | 
| Ted Kremenek | 3e5637f | 2010-07-27 18:49:08 +0000 | [diff] [blame] | 34 |   test(x + zero);  // expected-warning {{The right operand to '+' is always 0}} | 
 | 35 |   test(x - zero);  // expected-warning {{The right operand to '-' is always 0}} | 
 | 36 |   test(x * zero);  // expected-warning {{The right operand to '*' is always 0}} | 
 | 37 |   test(x & zero);  // expected-warning {{The right operand to '&' is always 0}} | 
 | 38 |   test(x | zero);  // expected-warning {{The right operand to '|' is always 0}} | 
 | 39 |   test(x ^ zero);  // expected-warning {{The right operand to '^' is always 0}} | 
 | 40 |   test(x << zero); // expected-warning {{The right operand to '<<' is always 0}} | 
 | 41 |   test(x >> zero); // expected-warning {{The right operand to '>>' is always 0}} | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 42 |  | 
 | 43 |   // 0 op x | 
| Ted Kremenek | 3e5637f | 2010-07-27 18:49:08 +0000 | [diff] [blame] | 44 |   test(zero + x);  // expected-warning {{The left operand to '+' is always 0}} | 
 | 45 |   test(zero - x);  // expected-warning {{The left operand to '-' is always 0}} | 
 | 46 |   test(zero / x);  // expected-warning {{The left operand to '/' is always 0}} | 
 | 47 |   test(zero * x);  // expected-warning {{The left operand to '*' is always 0}} | 
 | 48 |   test(zero & x);  // expected-warning {{The left operand to '&' is always 0}} | 
 | 49 |   test(zero | x);  // expected-warning {{The left operand to '|' is always 0}} | 
 | 50 |   test(zero ^ x);  // expected-warning {{The left operand to '^' is always 0}} | 
 | 51 |   test(zero << x); // expected-warning {{The left operand to '<<' is always 0}} | 
 | 52 |   test(zero >> x); // expected-warning {{The left operand to '>>' is always 0}} | 
| Tom Care | 245adab | 2010-08-18 21:17:24 +0000 | [diff] [blame] | 53 |  | 
| Tom Care | db34ab7 | 2010-08-23 19:51:57 +0000 | [diff] [blame] | 54 |   // Overwrite the values so these aren't marked as Pseudoconstants | 
| Tom Care | 245adab | 2010-08-18 21:17:24 +0000 | [diff] [blame] | 55 |   x = 1; | 
 | 56 |   zero = 2; | 
 | 57 |   one = 3; | 
 | 58 |  | 
 | 59 |   return x + zero + one; | 
| Tom Care | db2fa8a | 2010-07-06 21:43:29 +0000 | [diff] [blame] | 60 | } | 
| Ted Kremenek | 4532931 | 2010-07-17 00:40:32 +0000 | [diff] [blame] | 61 |  | 
 | 62 | void floats(float x) { | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 63 |   test_f(x * 1.0);  // no-warning | 
| Ted Kremenek | 4532931 | 2010-07-17 00:40:32 +0000 | [diff] [blame] | 64 |   test_f(x * 1.0F); // no-warning | 
 | 65 | } | 
| Tom Care | d85770b | 2010-07-30 21:42:31 +0000 | [diff] [blame] | 66 |  | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 67 | // Ensure that we don't report false poitives in complex loops | 
| Tom Care | d85770b | 2010-07-30 21:42:31 +0000 | [diff] [blame] | 68 | void bailout() { | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 69 |   int unused = 0, result = 4; | 
 | 70 |   result = result; // expected-warning {{Assigned value is always the same as the existing value}} | 
| Tom Care | d85770b | 2010-07-30 21:42:31 +0000 | [diff] [blame] | 71 |  | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 72 |   for (unsigned bg = 0; bg < 1024; bg ++) { | 
 | 73 |     result = bg * result; // no-warning | 
| Tom Care | d85770b | 2010-07-30 21:42:31 +0000 | [diff] [blame] | 74 |  | 
 | 75 |     for (int i = 0; i < 256; i++) { | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 76 |       unused *= i; // no-warning | 
| Tom Care | d85770b | 2010-07-30 21:42:31 +0000 | [diff] [blame] | 77 |     } | 
 | 78 |   } | 
 | 79 | } | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 80 |  | 
| Tom Care | 6d0e6ce | 2010-08-27 22:46:32 +0000 | [diff] [blame] | 81 | // Relaxed liveness - check that we don't kill liveness at assignments | 
 | 82 | typedef unsigned uintptr_t; | 
 | 83 | void kill_at_assign() { | 
 | 84 |   short array[2]; | 
 | 85 |   uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion}} | 
 | 86 |   short *p = x; // expected-warning{{incompatible integer to pointer conversion}} | 
 | 87 |  | 
 | 88 |   // The following branch should be infeasible. | 
 | 89 |   if (!(p = &array[0])) { // expected-warning{{Assigned value is always the same as the existing value}} | 
 | 90 |     p = 0; | 
 | 91 |     *p = 1; // no-warning | 
 | 92 |   } | 
 | 93 | } | 
 | 94 |  | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 95 | // False positive tests | 
 | 96 |  | 
 | 97 | unsigned false1() { | 
| Tom Care | 50e8ac2 | 2010-08-16 21:43:52 +0000 | [diff] [blame] | 98 |   int a = 10; | 
 | 99 |   return a * (5 - 2 - 3); // no-warning | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 100 | } | 
 | 101 |  | 
 | 102 | enum testenum { enum1 = 0, enum2 }; | 
 | 103 | unsigned false2() { | 
| Tom Care | 50e8ac2 | 2010-08-16 21:43:52 +0000 | [diff] [blame] | 104 |   int a = 1234; | 
 | 105 |   return enum1 + a; // no-warning | 
| Tom Care | a7a8a45 | 2010-08-12 22:45:47 +0000 | [diff] [blame] | 106 | } | 
 | 107 |  | 
| Tom Care | ef52bcb | 2010-08-24 21:09:07 +0000 | [diff] [blame] | 108 | // Self assignments of unused variables are common false positives | 
 | 109 | unsigned false3(int param, int param2) { | 
| Tom Care | 245adab | 2010-08-18 21:17:24 +0000 | [diff] [blame] | 110 |   param = param; // no-warning | 
 | 111 |  | 
| Tom Care | ef52bcb | 2010-08-24 21:09:07 +0000 | [diff] [blame] | 112 |   // if a self assigned variable is used later, then it should be reported still | 
 | 113 |   param2 = param2; // expected-warning{{Assigned value is always the same as the existing value}} | 
 | 114 |  | 
| Tom Care | 245adab | 2010-08-18 21:17:24 +0000 | [diff] [blame] | 115 |   unsigned nonparam = 5; | 
 | 116 |  | 
 | 117 |   nonparam = nonparam; // expected-warning{{Assigned value is always the same as the existing value}} | 
 | 118 |  | 
| Tom Care | ef52bcb | 2010-08-24 21:09:07 +0000 | [diff] [blame] | 119 |   return param2 + nonparam; | 
| Tom Care | 245adab | 2010-08-18 21:17:24 +0000 | [diff] [blame] | 120 | } | 
 | 121 |  | 
| Tom Care | db34ab7 | 2010-08-23 19:51:57 +0000 | [diff] [blame] | 122 | // Pseudo-constants (vars only read) and constants should not be reported | 
| Tom Care | 245adab | 2010-08-18 21:17:24 +0000 | [diff] [blame] | 123 | unsigned false4() { | 
 | 124 |   // Trivial constant | 
| Tom Care | db34ab7 | 2010-08-23 19:51:57 +0000 | [diff] [blame] | 125 |   const int height = 1; | 
| Tom Care | 8238941 | 2010-08-23 19:57:25 +0000 | [diff] [blame] | 126 |   int c = 42; | 
 | 127 |   test(height * c); // no-warning | 
| Tom Care | db34ab7 | 2010-08-23 19:51:57 +0000 | [diff] [blame] | 128 |  | 
| Tom Care | 8238941 | 2010-08-23 19:57:25 +0000 | [diff] [blame] | 129 |   // Pseudo-constant (never changes after decl) | 
 | 130 |   int width = height; | 
 | 131 |  | 
| Tom Care | 245adab | 2010-08-18 21:17:24 +0000 | [diff] [blame] | 132 |   return width * 10; // no-warning | 
 | 133 | } | 
| Tom Care | db34ab7 | 2010-08-23 19:51:57 +0000 | [diff] [blame] | 134 |  | 
| Tom Care | 967fea6 | 2010-08-25 22:37:26 +0000 | [diff] [blame] | 135 | // Block pseudoconstants | 
 | 136 | void false4a() { | 
 | 137 |   // Pseudo-constant | 
 | 138 |   __block int a = 1; | 
 | 139 |   int b = 10; | 
 | 140 |   __block int c = 0; | 
 | 141 |   b *= a; // no-warning | 
 | 142 |  | 
 | 143 |   ^{ | 
 | 144 |     // Psuedoconstant block var | 
 | 145 |     test(b * c); // no-warning | 
 | 146 |  | 
 | 147 |     // Non-pseudoconstant block var | 
 | 148 |     int d = 0; | 
 | 149 |     test(b * d); // expected-warning{{The right operand to '*' is always 0}} | 
 | 150 |     d = 5; | 
 | 151 |     test(d); | 
 | 152 |   }(); | 
 | 153 |  | 
 | 154 |   test(a + b); | 
 | 155 | } | 
 | 156 |  | 
| Tom Care | db34ab7 | 2010-08-23 19:51:57 +0000 | [diff] [blame] | 157 | // Static vars are common false positives | 
 | 158 | int false5() { | 
 | 159 |   static int test = 0; | 
 | 160 |   int a = 56; | 
 | 161 |   a *= test; // no-warning | 
 | 162 |   test++; | 
 | 163 |   return a; | 
 | 164 | } | 
 | 165 |  | 
 | 166 | // Non-local storage vars are considered false positives | 
 | 167 | int globalInt = 1; | 
 | 168 | int false6() { | 
 | 169 |   int localInt = 23; | 
 | 170 |  | 
 | 171 |   localInt /= globalInt; | 
 | 172 |  | 
 | 173 |   return localInt; | 
 | 174 | } | 
| Tom Care | 6216dc0 | 2010-08-30 19:25:43 +0000 | [diff] [blame] | 175 |  | 
 | 176 | // Check that assignments filter out false positives correctly | 
 | 177 | int false7() { | 
 | 178 |   int zero = 0; // psuedo-constant | 
 | 179 |   int one = 1; | 
 | 180 |  | 
 | 181 |   int a = 55; | 
 | 182 |   a = a; // expected-warning{{Assigned value is always the same as the existing value}} | 
 | 183 |   a = enum1 * a; // no-warning | 
 | 184 |  | 
 | 185 |   int b = 123; | 
 | 186 |   b = b; // no-warning | 
 | 187 |  | 
 | 188 |   return a; | 
 | 189 | } | 
| Tom Care | 84c24ed | 2010-09-07 20:27:56 +0000 | [diff] [blame] | 190 |  | 
 | 191 | // Check truncations do not flag as self-assignments | 
 | 192 | void false8() { | 
 | 193 |   int a = 10000000; | 
 | 194 |   a = (short)a; // no-warning | 
 | 195 |   test(a); | 
 | 196 | } | 
| Ted Kremenek | 02282ac | 2010-09-15 03:13:30 +0000 | [diff] [blame] | 197 |  | 
 | 198 | // This test case previously flagged a warning at 'b == c' because the | 
 | 199 | // analyzer previously allowed 'UnknownVal' as the index for ElementRegions. | 
 | 200 | typedef struct RDar8431728_F { | 
 | 201 |   int RDar8431728_A; | 
 | 202 |   unsigned char *RDar8431728_B; | 
 | 203 |   int RDar8431728_E[6]; | 
 | 204 | } RDar8431728_D; | 
 | 205 | static inline int RDar8431728_C(RDar8431728_D * s, int n, | 
 | 206 |     unsigned char **RDar8431728_B_ptr) { | 
 | 207 |   int xy, wrap, pred, a, b, c; | 
 | 208 |  | 
 | 209 |   xy = s->RDar8431728_E[n]; | 
 | 210 |   wrap = s->RDar8431728_A; | 
 | 211 |  | 
 | 212 |   a = s->RDar8431728_B[xy - 1]; | 
 | 213 |   b = s->RDar8431728_B[xy - 1 - wrap]; | 
 | 214 |   c = s->RDar8431728_B[xy - wrap]; | 
 | 215 |  | 
 | 216 |   if (b == c) { // no-warning | 
 | 217 |     pred = a; | 
 | 218 |   } else { | 
 | 219 |     pred = c; | 
 | 220 |   } | 
 | 221 |  | 
 | 222 |   *RDar8431728_B_ptr = &s->RDar8431728_B[xy]; | 
 | 223 |  | 
 | 224 |   return pred; | 
 | 225 | } | 
 | 226 |  | 
| Ted Kremenek | 74faec2 | 2010-10-29 01:06:54 +0000 | [diff] [blame] | 227 | // <rdar://problem/8601243> - Don't warn on pointer arithmetic.  This | 
 | 228 | // is often idiomatic. | 
 | 229 | unsigned rdar8601243_aux(unsigned n); | 
 | 230 | void rdar8601243() { | 
 | 231 |   char arr[100]; | 
 | 232 |   char *start = arr; | 
 | 233 |   start = start + rdar8601243_aux(sizeof(arr) - (arr - start)); // no-warning | 
 | 234 |   (void) start; | 
 | 235 | } | 
 | 236 |  |