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