brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.8 KiB · 9a58a7a Raw
916 lines · cpp
1// RUN: %check_clang_tidy %s bugprone-infinite-loop %t \2// RUN:                   -- -- -fexceptions -fblocks -fno-delayed-template-parsing3 4void 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 32void 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 61void 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 updated90    (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 115void 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 121int unknown_function();122 123void 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 138void 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 155void 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 172void 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 188void 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 203void 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 analysis210  }211  int *p = &i;212}213 214void 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 analysis221  }222  int &ii = i;223}224 225int glob;226 227void 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 235void 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 243struct 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 or251      // 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 269void 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 289void no_loop_variable() {290  while (0)291    ;292}293 294void volatile_in_condition() {295  volatile int cond = 0;296  while (!cond) {297  }298}299 300namespace std {301template<typename T> class atomic {302  T val;303public:304  atomic(T v): val(v) {};305  operator T() { return val; };306};307}308 309void atomic_in_condition() {310  std::atomic<int> cond = 0;311  while (!cond) {312  }313}314 315void loop_exit1() {316  int i = 0;317  while (i) {318    if (unknown_function())319      break;320  }321}322 323void loop_exit2() {324  int i = 0;325  while (i) {326    if (unknown_function())327      return;328  }329}330 331void loop_exit3() {332  int i = 0;333  while (i) {334    if (unknown_function())335      goto end;336  }337 end:338  ;339}340 341void 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 351void loop_exit5() {352  int i = 0;353  while (i) {354    if (unknown_function())355      exit(1);356  }357}358 359void 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 367void 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 382template <typename T> void accept_callback(T t) {383  // Potentially call the callback.384  // Possibly on a background thread or something.385}386 387void accept_block(void (^)(void)) {388  // Potentially call the callback.389  // Possibly on a background thread or something.390}391 392void wait(void) {393  // Wait for the previously passed callback to be called.394}395 396void lambda_capture_from_outside() {397  bool finished = false;398  accept_callback([&]() {399    finished = true;400  });401  while (!finished) {402    wait();403  }404}405 406void 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 417void 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 428void block_capture_from_outside() {429  __block bool finished = false;430  accept_block(^{431    finished = true;432  });433  while (!finished) {434    wait();435  }436}437 438void 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 449void 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 460void finish_at_any_time(bool *finished);461 462void 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 474void 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 486void 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 updated491              // from outside the lambda.492    }493  };494  finish_at_any_time(&finished);495  lambda();496}497 498void 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 updated503              // from outside the lambda.504    }505  };506  finish_at_any_time(&finished);507  lambda();508}509 510void 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 522void 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 533void 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 updated538              // from outside the block.539    }540  };541  finish_at_any_time(&finished);542  block();543}544 545void evaluatable(bool CondVar) {546  for (; false && CondVar;) {547  }548  while (false && CondVar) {549  }550  do {551  } while (false && CondVar);552}553 554struct logger {555  void (*debug)(struct logger *, const char *, ...);556};557 558int 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 569struct AggregateWithReference {570  int &y;571};572 573void 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 582struct AggregateWithValue {583  int y;584};585 586void 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 595void 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 602void test_volatile_concrete_address(int i, int size) {603  // No warning. The value behind the volatile concrete address604  // 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 else620  // 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 626template <typename T>627int some_template_fn() { return 1; }628 629template <typename T>630void 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 654void test_typeof() {655  __typeof__({656    for (int i = 0; i < 10; ++i) {657    }658    0;659  }) x;660}661 662void test_typeof_infinite() {663  __typeof__({664    for (int i = 0; i < 10;) {665    }666    0;667  }) x;668}669 670void test_typeof_while_infinite() {671  __typeof__({672    int i = 0;673    while (i < 10) {674    }675    0;676  }) x;677}678 679void test_typeof_dowhile_infinite() {680  __typeof__({681    int i = 0;682    do {683 684    } while (i < 10);685    0;686  }) x;687}688 689void 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 i696  for (; i >= 0;)697    test_local_static_recursion(); // no warning, recursively decrement i698  for (; i + j >= 0;)699    test_local_static_recursion(); // no warning, recursively decrement i700  for (; i >= 0; i--)701    ; // no warning, i decrements702  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 warning713}714 715struct PairVal {716  int a;717  int b;718  PairVal(int a, int b) : a(a), b(b) {}719};720 721void structured_binding_infinite_loop1() {722  auto [x, y] = PairVal(0, 0);723  while (x < 10) {724    // 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]725    y++;726  }727  while (y < 10) {728    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (y) are updated in the loop body [bugprone-infinite-loop]729    x++;730  }731}732 733void structured_binding_infinite_loop2() {734  auto [x, y] = PairVal(0, 0);735  while (x < 10) {736    // 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]737    // No update to x or y738  }739  while (y < 10) {740    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (y) are updated in the loop body [bugprone-infinite-loop]741    // No update to x or y742  }743}744 745void structured_binding_not_infinite1() {746  auto [x, y] = PairVal(0, 0);747  while (x < 10) {748    x++;749  }750  while (y < 10) {751    y++;752  }753}754 755void volatile_structured_binding_in_condition() {756  volatile auto [x, y] = PairVal(0, 0);757  while (!x) {}758}759 760void test_local_static_structured_binding_recursion() {761  static auto [i, _] = PairVal(0, 0);762  int j = 0;763 764  i--;765  while (i >= 0)766    test_local_static_structured_binding_recursion(); // no warning, recursively decrement i767  for (; i >= 0;)768    test_local_static_structured_binding_recursion(); // no warning, recursively decrement i769  for (; i + j >= 0;)770    test_local_static_structured_binding_recursion(); // no warning, recursively decrement i771  for (; i >= 0; i--)772    ; // no warning, i decrements773  while (j >= 0)774    // 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]775    test_local_static_structured_binding_recursion();776 777  int (*p)(int) = 0;778 779  while (i >= 0)780    // 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]781    p = 0;782  while (i >= 0)783    p(0); // we don't know what p points to so no warning784}785 786struct S { int a; };787void issue_138842_reduced() {788    int x = 10;789    auto [y] = S{1};790 791    while (y < x) {792      y++;793    }794}795 796namespace std {797template <typename T, typename U>798struct pair {799  T first;800  U second;801 802  pair(T a, U b) : first(a), second(b) {}803};804}805 806template <typename T, typename U>807void structured_binding_in_template_byval(T a, U b) {808  auto [c, d] = std::pair<T, U>(a,b);809 810  while (c < 10) {811    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (c) are updated in the loop body [bugprone-infinite-loop]812    d++;813  }814 815  while (c < 10) {816    c++; // no warning817  }818}819 820template <typename T, typename U>821void structured_binding_in_template_bylref(T a, U b) {822  auto p = std::pair<T, U>(a,b);823  auto& [c, d] = p;824 825  while (c < 10) {826    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (c) are updated in the loop body [bugprone-infinite-loop]827    d++;828  }829 830  while (c < 10) {831    c++; // no warning832  }833}834 835template <typename T, typename U>836void structured_binding_in_template_byrref(T a, U b) {837  auto p = std::pair<T, U>(a,b);838  auto&& [c, d] = p;839 840  while (c < 10) {841    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (c) are updated in the loop body [bugprone-infinite-loop]842    d++;843  }844 845  while (c < 10) {846    c++; // no warning847  }848}849 850void structured_binding_in_template_instantiation(int b) {851  structured_binding_in_template_byval(b, 0);852  structured_binding_in_template_bylref(b, 0);853  structured_binding_in_template_byrref(b, 0);854}855 856void array_structured_binding() {857  int arr[2] = {0, 0};858  auto [x, y] = arr;859 860  while (x < 10) {861    // 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]862    y++;863  }864 865  while (y < 10) {866    y++; // no warning867  }868}869 870namespace std {871    using size_t = int;872    template <class> struct tuple_size;873    template <std::size_t, class> struct tuple_element;874    template <class...> class tuple;875 876namespace {877    template <class T, T v>878    struct size_helper { static const T value = v; };879} // namespace880 881template <class... T>882struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};883 884template <std::size_t I, class... T>885struct tuple_element<I, tuple<T...>> {886    using type =  __type_pack_element<I, T...>;887};888 889template <class...> class tuple {};890 891template <std::size_t I, class... T>892typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);893} // namespace std894 895std::tuple<int*, int> &get_chunk();896 897void test_structured_bindings_tuple() {898  auto [buffer, size ] = get_chunk();899  int maxLen = 8;900 901  while (size < maxLen) {902    // No warning. The loop is finite because 'size' is being incremented in each iteration and compared against 'maxLen' for termination903    buffer[size++] = 2;904  }905}906 907void test_structured_bindings_tuple_ref() {908  auto& [buffer, size ] = get_chunk();909  int maxLen = 8;910 911  while (size < maxLen) {912    // No warning. The loop is finite because 'size' is being incremented in each iteration and compared against 'maxLen' for termination913    buffer[size++] = 2;914  }915}916