idempotent-operations.c revision 02282acd7a42d06a3178e3102d34a585bd82dd9f
1// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-check-idempotent-operations -verify %s
2
3// Basic tests
4
5extern void test(int i);
6extern void test_f(float f);
7
8unsigned basic() {
9  int x = 10, zero = 0, one = 1;
10
11  // x op x
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}}
15  x = 10;       // no-warning
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}}
18  x = 10;       // no-warning
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}}
23
24  // x op 1
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}}
29
30  // 1 op x
31  test(one * x);   // expected-warning {{The left operand to '*' is always 1}}
32
33  // x op 0
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}}
42
43  // 0 op x
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}}
53
54  // Overwrite the values so these aren't marked as Pseudoconstants
55  x = 1;
56  zero = 2;
57  one = 3;
58
59  return x + zero + one;
60}
61
62void floats(float x) {
63  test_f(x * 1.0);  // no-warning
64  test_f(x * 1.0F); // no-warning
65}
66
67// Ensure that we don't report false poitives in complex loops
68void bailout() {
69  int unused = 0, result = 4;
70  result = result; // expected-warning {{Assigned value is always the same as the existing value}}
71
72  for (unsigned bg = 0; bg < 1024; bg ++) {
73    result = bg * result; // no-warning
74
75    for (int i = 0; i < 256; i++) {
76      unused *= i; // no-warning
77    }
78  }
79}
80
81// Relaxed liveness - check that we don't kill liveness at assignments
82typedef unsigned uintptr_t;
83void 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
95// False positive tests
96
97unsigned false1() {
98  int a = 10;
99  return a * (5 - 2 - 3); // no-warning
100}
101
102enum testenum { enum1 = 0, enum2 };
103unsigned false2() {
104  int a = 1234;
105  return enum1 + a; // no-warning
106}
107
108// Self assignments of unused variables are common false positives
109unsigned false3(int param, int param2) {
110  param = param; // no-warning
111
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
115  unsigned nonparam = 5;
116
117  nonparam = nonparam; // expected-warning{{Assigned value is always the same as the existing value}}
118
119  return param2 + nonparam;
120}
121
122// Pseudo-constants (vars only read) and constants should not be reported
123unsigned false4() {
124  // Trivial constant
125  const int height = 1;
126  int c = 42;
127  test(height * c); // no-warning
128
129  // Pseudo-constant (never changes after decl)
130  int width = height;
131
132  return width * 10; // no-warning
133}
134
135// Block pseudoconstants
136void 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
157// Static vars are common false positives
158int 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
167int globalInt = 1;
168int false6() {
169  int localInt = 23;
170
171  localInt /= globalInt;
172
173  return localInt;
174}
175
176// Check that assignments filter out false positives correctly
177int 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}
190
191// Check truncations do not flag as self-assignments
192void false8() {
193  int a = 10000000;
194  a = (short)a; // no-warning
195  test(a);
196}
197
198// This test case previously flagged a warning at 'b == c' because the
199// analyzer previously allowed 'UnknownVal' as the index for ElementRegions.
200typedef struct RDar8431728_F {
201  int RDar8431728_A;
202  unsigned char *RDar8431728_B;
203  int RDar8431728_E[6];
204} RDar8431728_D;
205static 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
227