1 // RUN: %check_clang_tidy %s bugprone-infinite-loop %t \
2 // RUN:                   -- -- -fexceptions -fblocks
3 
simple_infinite_loop1()4 void simple_infinite_loop1() {
5   int i = 0;
6   int j = 0;
7   while (i < 10) {
8   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
9     j++;
10   }
11 
12   while (int k = 10) {
13     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; it does not check any variables in the condition [bugprone-infinite-loop]
14     j--;
15   }
16 
17   while (int k = 10) {
18     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; it does not check any variables in the condition [bugprone-infinite-loop]
19     k--;
20   }
21 
22   do {
23   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
24     j++;
25   } while (i < 10);
26 
27   for (i = 0; i < 10; ++j) {
28     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
29   }
30 }
31 
simple_infinite_loop2()32 void simple_infinite_loop2() {
33   int i = 0;
34   int j = 0;
35   int Limit = 10;
36   while (i < Limit) {
37     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
38     j++;
39   }
40 
41   while (int k = Limit) {
42     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (Limit) are updated in the loop body [bugprone-infinite-loop]
43     j--;
44   }
45 
46   while (int k = Limit) {
47     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (Limit) are updated in the loop body [bugprone-infinite-loop]
48     k--;
49   }
50 
51   do {
52   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
53     j++;
54   } while (i < Limit);
55 
56   for (i = 0; i < Limit; ++j) {
57     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
58   }
59 }
60 
simple_not_infinite1()61 void simple_not_infinite1() {
62   int i = 0;
63   int Limit = 100;
64   while (i < Limit) {
65     // Not an error since 'Limit' is updated.
66     Limit--;
67   }
68 
69   while (Limit--) {
70     // Not an error since 'Limit' is updated.
71     i++;
72   }
73 
74   while ((Limit)--) {
75     // Not an error since 'Limit' is updated.
76     i++;
77   }
78 
79   while ((Limit) -= 1) {
80     // Not an error since 'Limit' is updated.
81   }
82 
83   while (int k = Limit) {
84     // Not an error since 'Limit' is updated.
85     Limit--;
86   }
87 
88   while (int k = Limit) {
89     // Not an error since 'Limit' is updated
90     (Limit)--;
91   }
92 
93   while (int k = Limit--) {
94     // Not an error since 'Limit' is updated.
95     i++;
96   }
97 
98   do {
99     Limit--;
100   } while (i < Limit);
101 
102   for (i = 0; i < Limit; Limit--) {
103   }
104 
105   for (i = 0; i < Limit; (Limit) = Limit - 1) {
106   }
107 
108   for (i = 0; i < Limit; (Limit) -= 1) {
109   }
110 
111   for (i = 0; i < Limit; --(Limit)) {
112   }
113 }
114 
simple_not_infinite2()115 void simple_not_infinite2() {
116   for (int i = 10; i-- > 0;) {
117     // Not an error, since loop variable is modified in its condition part.
118   }
119 }
120 
121 int unknown_function();
122 
function_call()123 void function_call() {
124   int i = 0;
125   while (i < unknown_function()) {
126     // Not an error, since the function may return different values.
127   }
128 
129   do {
130     // Not an error, since the function may return different values.
131   } while (i < unknown_function());
132 
133   for (i = 0; i < unknown_function();) {
134     // Not an error, since the function may return different values.
135   }
136 }
137 
escape_before1()138 void escape_before1() {
139   int i = 0;
140   int Limit = 100;
141   int *p = &i;
142   while (i < Limit) {
143     // Not an error, since *p is alias of i.
144     (*p)++;
145   }
146 
147   do {
148     (*p)++;
149   } while (i < Limit);
150 
151   for (i = 0; i < Limit; ++(*p)) {
152   }
153 }
154 
escape_before2()155 void escape_before2() {
156   int i = 0;
157   int Limit = 100;
158   int &ii = i;
159   while (i < Limit) {
160     // Not an error, since ii is alias of i.
161     ii++;
162   }
163 
164   do {
165     ii++;
166   } while (i < Limit);
167 
168   for (i = 0; i < Limit; ++ii) {
169   }
170 }
171 
escape_inside1()172 void escape_inside1() {
173   int i = 0;
174   int Limit = 100;
175   int *p = &i;
176   while (i < Limit) {
177     // Not an error, since *p is alias of i.
178     int *p = &i;
179     (*p)++;
180   }
181 
182   do {
183     int *p = &i;
184     (*p)++;
185   } while (i < Limit);
186 }
187 
escape_inside2()188 void escape_inside2() {
189   int i = 0;
190   int Limit = 100;
191   while (i < Limit) {
192     // Not an error, since ii is alias of i.
193     int &ii = i;
194     ii++;
195   }
196 
197   do {
198     int &ii = i;
199     ii++;
200   } while (i < Limit);
201 }
202 
escape_after1()203 void escape_after1() {
204   int i = 0;
205   int j = 0;
206   int Limit = 10;
207 
208   while (i < Limit) {
209     // False negative, but difficult to detect without CFG-based analysis
210   }
211   int *p = &i;
212 }
213 
escape_after2()214 void escape_after2() {
215   int i = 0;
216   int j = 0;
217   int Limit = 10;
218 
219   while (i < Limit) {
220     // False negative, but difficult to detect without CFG-based analysis
221   }
222   int &ii = i;
223 }
224 
225 int glob;
226 
global1(int & x)227 void global1(int &x) {
228   int i = 0, Limit = 100;
229   while (x < Limit) {
230     // Not an error since 'x' can be an alias of 'glob'.
231     glob++;
232   }
233 }
234 
global2()235 void global2() {
236   int i = 0, Limit = 100;
237   while (glob < Limit) {
238     // Since 'glob' is declared out of the function we do not warn.
239     i++;
240   }
241 }
242 
243 struct X {
244   int m;
245 
246   void change_m();
247 
member_expr1X248   void member_expr1(int i) {
249     while (i < m) {
250       // False negative: No warning, since skipping the case where a struct or
251       // class can be found in its condition.
252       ;
253     }
254   }
255 
member_expr2X256   void member_expr2(int i) {
257     while (i < m) {
258       --m;
259     }
260   }
261 
member_expr3X262   void member_expr3(int i) {
263     while (i < m) {
264       change_m();
265     }
266   }
267 };
268 
array_index()269 void array_index() {
270   int i = 0;
271   int v[10];
272   while (i < 10) {
273     v[i++] = 0;
274   }
275 
276   i = 0;
277   do {
278     v[i++] = 0;
279   } while (i < 9);
280 
281   for (i = 0; i < 10;) {
282     v[i++] = 0;
283   }
284 
285   for (i = 0; i < 10; v[i++] = 0) {
286   }
287 }
288 
no_loop_variable()289 void no_loop_variable() {
290   while (0)
291     ;
292 }
293 
volatile_in_condition()294 void volatile_in_condition() {
295   volatile int cond = 0;
296   while (!cond) {
297   }
298 }
299 
300 namespace std {
301 template<typename T> class atomic {
302   T val;
303 public:
atomic(T v)304   atomic(T v): val(v) {};
operator T()305   operator T() { return val; };
306 };
307 }
308 
atomic_in_condition()309 void atomic_in_condition() {
310   std::atomic<int> cond = 0;
311   while (!cond) {
312   }
313 }
314 
loop_exit1()315 void loop_exit1() {
316   int i = 0;
317   while (i) {
318     if (unknown_function())
319       break;
320   }
321 }
322 
loop_exit2()323 void loop_exit2() {
324   int i = 0;
325   while (i) {
326     if (unknown_function())
327       return;
328   }
329 }
330 
loop_exit3()331 void loop_exit3() {
332   int i = 0;
333   while (i) {
334     if (unknown_function())
335       goto end;
336   }
337  end:
338   ;
339 }
340 
loop_exit4()341 void loop_exit4() {
342   int i = 0;
343   while (i) {
344     if (unknown_function())
345       throw 1;
346   }
347 }
348 
349 [[noreturn]] void exit(int);
350 
loop_exit5()351 void loop_exit5() {
352   int i = 0;
353   while (i) {
354     if (unknown_function())
355       exit(1);
356   }
357 }
358 
loop_exit_in_lambda()359 void loop_exit_in_lambda() {
360   int i = 0;
361   while (i) {
362     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
363     auto l = []() { return 0; };
364   }
365 }
366 
lambda_capture()367 void lambda_capture() {
368   int i = 0;
369   int Limit = 100;
370   int *p = &i;
371   while (i < Limit) {
372     // Not an error, since i is captured by reference in a lambda.
373     auto l = [&i]() { ++i; };
374   }
375 
376   do {
377     int *p = &i;
378     (*p)++;
379   } while (i < Limit);
380 }
381 
accept_callback(T t)382 template <typename T> void accept_callback(T t) {
383   // Potentially call the callback.
384   // Possibly on a background thread or something.
385 }
386 
387 void accept_block(void (^)(void)) {
388   // Potentially call the callback.
389   // Possibly on a background thread or something.
390 }
391 
wait(void)392 void wait(void) {
393   // Wait for the previously passed callback to be called.
394 }
395 
lambda_capture_from_outside()396 void lambda_capture_from_outside() {
397   bool finished = false;
398   accept_callback([&]() {
399     finished = true;
400   });
401   while (!finished) {
402     wait();
403   }
404 }
405 
lambda_capture_from_outside_by_value()406 void lambda_capture_from_outside_by_value() {
407   bool finished = false;
408   accept_callback([finished]() {
409     if (finished) {}
410   });
411   while (!finished) {
412     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
413     wait();
414   }
415 }
416 
lambda_capture_from_outside_but_unchanged()417 void lambda_capture_from_outside_but_unchanged() {
418   bool finished = false;
419   accept_callback([&finished]() {
420     if (finished) {}
421   });
422   while (!finished) {
423     // FIXME: Should warn.
424     wait();
425   }
426 }
427 
block_capture_from_outside()428 void block_capture_from_outside() {
429   __block bool finished = false;
430   accept_block(^{
431     finished = true;
432   });
433   while (!finished) {
434     wait();
435   }
436 }
437 
block_capture_from_outside_by_value()438 void block_capture_from_outside_by_value() {
439   bool finished = false;
440   accept_block(^{
441     if (finished) {}
442   });
443   while (!finished) {
444     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
445     wait();
446   }
447 }
448 
block_capture_from_outside_but_unchanged()449 void block_capture_from_outside_but_unchanged() {
450   __block bool finished = false;
451   accept_block(^{
452     if (finished) {}
453   });
454   while (!finished) {
455     // FIXME: Should warn.
456     wait();
457   }
458 }
459 
460 void finish_at_any_time(bool *finished);
461 
lambda_capture_with_loop_inside_lambda_bad()462 void lambda_capture_with_loop_inside_lambda_bad() {
463   bool finished = false;
464   auto lambda = [=]() {
465     while (!finished) {
466       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
467       wait();
468     }
469   };
470   finish_at_any_time(&finished);
471   lambda();
472 }
473 
lambda_capture_with_loop_inside_lambda_bad_init_capture()474 void lambda_capture_with_loop_inside_lambda_bad_init_capture() {
475   bool finished = false;
476   auto lambda = [captured_finished=finished]() {
477     while (!captured_finished) {
478       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (captured_finished) are updated in the loop body [bugprone-infinite-loop]
479       wait();
480     }
481   };
482   finish_at_any_time(&finished);
483   lambda();
484 }
485 
lambda_capture_with_loop_inside_lambda_good()486 void lambda_capture_with_loop_inside_lambda_good() {
487   bool finished = false;
488   auto lambda = [&]() {
489     while (!finished) {
490       wait(); // No warning: the variable may be updated
491               // from outside the lambda.
492     }
493   };
494   finish_at_any_time(&finished);
495   lambda();
496 }
497 
lambda_capture_with_loop_inside_lambda_good_init_capture()498 void lambda_capture_with_loop_inside_lambda_good_init_capture() {
499   bool finished = false;
500   auto lambda = [&captured_finished=finished]() {
501     while (!captured_finished) {
502       wait(); // No warning: the variable may be updated
503               // from outside the lambda.
504     }
505   };
506   finish_at_any_time(&finished);
507   lambda();
508 }
509 
block_capture_with_loop_inside_block_bad()510 void block_capture_with_loop_inside_block_bad() {
511   bool finished = false;
512   auto block = ^() {
513     while (!finished) {
514       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
515       wait();
516     }
517   };
518   finish_at_any_time(&finished);
519   block();
520 }
521 
block_capture_with_loop_inside_block_bad_simpler()522 void block_capture_with_loop_inside_block_bad_simpler() {
523   bool finished = false;
524   auto block = ^() {
525     while (!finished) {
526       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
527       wait();
528     }
529   };
530   block();
531 }
532 
block_capture_with_loop_inside_block_good()533 void block_capture_with_loop_inside_block_good() {
534   __block bool finished = false;
535   auto block = ^() {
536     while (!finished) {
537       wait(); // No warning: the variable may be updated
538               // from outside the block.
539     }
540   };
541   finish_at_any_time(&finished);
542   block();
543 }
544 
evaluatable(bool CondVar)545 void evaluatable(bool CondVar) {
546   for (; false && CondVar;) {
547   }
548   while (false && CondVar) {
549   }
550   do {
551   } while (false && CondVar);
552 }
553 
554 struct logger {
555   void (*debug)(struct logger *, const char *, ...);
556 };
557 
foo(void)558 int foo(void) {
559   struct logger *pl = 0;
560   int iterator = 0;
561   while (iterator < 10) {
562     char *l_tmp_msg = 0;
563     pl->debug(pl, "%d: %s\n", iterator, l_tmp_msg);
564     iterator++;
565   }
566   return 0;
567 }
568 
569 struct AggregateWithReference {
570   int &y;
571 };
572 
test_structured_bindings_good()573 void test_structured_bindings_good() {
574   int x = 0;
575   AggregateWithReference ref { x };
576   auto &[y] = ref;
577   for (; x < 10; ++y) {
578     // No warning. The loop is finite because 'y' is a reference to 'x'.
579   }
580 }
581 
582 struct AggregateWithValue {
583   int y;
584 };
585 
test_structured_bindings_bad()586 void test_structured_bindings_bad() {
587   int x = 0;
588   AggregateWithValue val { x };
589   auto &[y] = val;
590   for (; x < 10; ++y) {
591       // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (x) are updated in the loop body [bugprone-infinite-loop]
592   }
593 }
594