1 | // RUN: %check_clang_tidy %s bugprone-infinite-loop %t \ |
2 | // RUN: -- -- -fexceptions -fblocks -fno-delayed-template-parsing |
3 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
248 | 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 | |
256 | void member_expr2(int i) { |
257 | while (i < m) { |
258 | --m; |
259 | } |
260 | } |
261 | |
262 | void member_expr3(int i) { |
263 | while (i < m) { |
264 | change_m(); |
265 | } |
266 | } |
267 | }; |
268 | |
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 | |
289 | void no_loop_variable() { |
290 | while (0) |
291 | ; |
292 | } |
293 | |
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: |
304 | atomic(T v): val(v) {}; |
305 | operator T() { return val; }; |
306 | }; |
307 | } |
308 | |
309 | void atomic_in_condition() { |
310 | std::atomic<int> cond = 0; |
311 | while (!cond) { |
312 | } |
313 | } |
314 | |
315 | void loop_exit1() { |
316 | int i = 0; |
317 | while (i) { |
318 | if (unknown_function()) |
319 | break; |
320 | } |
321 | } |
322 | |
323 | void loop_exit2() { |
324 | int i = 0; |
325 | while (i) { |
326 | if (unknown_function()) |
327 | return; |
328 | } |
329 | } |
330 | |
331 | void loop_exit3() { |
332 | int i = 0; |
333 | while (i) { |
334 | if (unknown_function()) |
335 | goto end; |
336 | } |
337 | end: |
338 | ; |
339 | } |
340 | |
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 | |
351 | void loop_exit5() { |
352 | int i = 0; |
353 | while (i) { |
354 | if (unknown_function()) |
355 | exit(1); |
356 | } |
357 | } |
358 | |
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 | |
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 | |
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 | |
392 | void wait(void) { |
393 | // Wait for the previously passed callback to be called. |
394 | } |
395 | |
396 | void lambda_capture_from_outside() { |
397 | bool finished = false; |
398 | accept_callback(t: [&]() { |
399 | finished = true; |
400 | }); |
401 | while (!finished) { |
402 | wait(); |
403 | } |
404 | } |
405 | |
406 | void lambda_capture_from_outside_by_value() { |
407 | bool finished = false; |
408 | accept_callback(t: [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 | |
417 | void lambda_capture_from_outside_but_unchanged() { |
418 | bool finished = false; |
419 | accept_callback(t: [&finished]() { |
420 | if (finished) {} |
421 | }); |
422 | while (!finished) { |
423 | // FIXME: Should warn. |
424 | wait(); |
425 | } |
426 | } |
427 | |
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 | |
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 | |
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 | |
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: &finished); |
471 | lambda(); |
472 | } |
473 | |
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: &finished); |
483 | lambda(); |
484 | } |
485 | |
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: &finished); |
495 | lambda(); |
496 | } |
497 | |
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: &finished); |
507 | lambda(); |
508 | } |
509 | |
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: &finished); |
519 | block(); |
520 | } |
521 | |
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 | |
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 | |
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 | |
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 | |
573 | void test_structured_bindings_good() { |
574 | int x = 0; |
575 | AggregateWithReference ref { .y: 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 | |
586 | void test_structured_bindings_bad() { |
587 | int x = 0; |
588 | AggregateWithValue val { .y: 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 | |
595 | void test_volatile_cast() { |
596 | // This is a no-op cast. Clang ignores the qualifier, we should too. |
597 | for (int i = 0; (volatile int)i < 10;) { |
598 | // 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] |
599 | } |
600 | } |
601 | |
602 | void test_volatile_concrete_address(int i, int size) { |
603 | // No warning. The value behind the volatile concrete address |
604 | // is beyond our control. It may change at any time. |
605 | for (; *((volatile int *)0x1234) < size;) { |
606 | } |
607 | |
608 | for (; *((volatile int *)(0x1234 + i)) < size;) { |
609 | } |
610 | |
611 | for (; **((volatile int **)0x1234) < size;) { |
612 | } |
613 | |
614 | volatile int *x = (volatile int *)0x1234; |
615 | for (; *x < 10;) { |
616 | } |
617 | |
618 | // FIXME: This one should probably also be suppressed. |
619 | // Whatever the developer is doing here, they can do that again anywhere else |
620 | // which basically makes it a global. |
621 | for (; *(int *)0x1234 < size;) { |
622 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (size) are updated in the loop body [bugprone-infinite-loop] |
623 | } |
624 | } |
625 | |
626 | template <typename T> |
627 | int some_template_fn() { return 1; } |
628 | |
629 | template <typename T> |
630 | void test_dependent_condition() { |
631 | const int error = some_template_fn<T>(); |
632 | do { |
633 | } while (false && error == 0); |
634 | |
635 | const int val = some_template_fn<T>(); |
636 | for (; !(val == 0 || true);) { |
637 | } |
638 | |
639 | const int val2 = some_template_fn<T>(); |
640 | for (; !(val2 == 0 || false);) { |
641 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val2) are updated in the loop body [bugprone-infinite-loop] |
642 | } |
643 | |
644 | const int val3 = some_template_fn<T>(); |
645 | do { |
646 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val3) are updated in the loop body [bugprone-infinite-loop] |
647 | } while (1, (true) && val3 == 1); |
648 | |
649 | const int val4 = some_template_fn<T>(); |
650 | do { |
651 | } while (1, (false) && val4 == 1); |
652 | } |
653 | |
654 | void test_typeof() { |
655 | __typeof__({ |
656 | for (int i = 0; i < 10; ++i) { |
657 | } |
658 | 0; |
659 | }) x; |
660 | } |
661 | |
662 | void test_typeof_infinite() { |
663 | __typeof__({ |
664 | for (int i = 0; i < 10;) { |
665 | } |
666 | 0; |
667 | }) x; |
668 | } |
669 | |
670 | void test_typeof_while_infinite() { |
671 | __typeof__({ |
672 | int i = 0; |
673 | while (i < 10) { |
674 | } |
675 | 0; |
676 | }) x; |
677 | } |
678 | |
679 | void test_typeof_dowhile_infinite() { |
680 | __typeof__({ |
681 | int i = 0; |
682 | do { |
683 | |
684 | } while (i < 10); |
685 | 0; |
686 | }) x; |
687 | } |
688 | |
689 | void test_local_static_recursion() { |
690 | static int i = 10; |
691 | int j = 0; |
692 | |
693 | i--; |
694 | while (i >= 0) |
695 | test_local_static_recursion(); // no warning, recursively decrement i |
696 | for (; i >= 0;) |
697 | test_local_static_recursion(); // no warning, recursively decrement i |
698 | for (; i + j >= 0;) |
699 | test_local_static_recursion(); // no warning, recursively decrement i |
700 | for (; i >= 0; i--) |
701 | ; // no warning, i decrements |
702 | while (j >= 0) |
703 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (j) are updated in the loop body [bugprone-infinite-loop] |
704 | test_local_static_recursion(); |
705 | |
706 | int (*p)(int) = 0; |
707 | |
708 | while (i >= 0) |
709 | // 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] |
710 | p = 0; |
711 | while (i >= 0) |
712 | p(0); // we don't know what p points to so no warning |
713 | } |
714 | |