1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 2 "http://www.w3.org/TR/html4/strict.dtd"> 3 <html> 4 <head> 5 <title>List of potential checkers</title> 6 <link type="text/css" rel="stylesheet" href="content.css"> 7 <link type="text/css" rel="stylesheet" href="menu.css"> 8 <script type="text/javascript" src="scripts/menu.js"></script> 9 <script type="text/javascript" src="scripts/dbtree.js"></script> 10 </head> 11 <body> 12 13 <div id="page"> 14 15 <!-- menu --> 16 <!--#include virtual="menu.html.incl"--> 17 <!-- page content --> 18 <div id="content"> 19 <h1>List of potential checkers</h1> 20 21 <p>This page contains a list of potential checkers to implement in the static analyzer. If you are interested in contributing to the analyzer's development, this is a good resource to help you get started. The specific names of the checkers are subject to review, and are provided here as suggestions.</p> 22 23 <!-- ========================= allocation/deallocation ======================= --> 24 <h3>allocation/deallocation</h3> 25 <table class="checkers"> 26 <col class="namedescr"><col class="example"><col class="progress"> 27 <thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> 28 29 <tr><td><span class="name">memory.LeakNeverReleased<br> 30 (C, C++)</span><br><br> 31 Memory may be never released, potential leak of memory 32 </td><td> 33 <pre> 34 #include <stdlib.h> 35 36 int f() {}; 37 38 void test() { 39 int *p1 = (int*)malloc(sizeof(int)); // warn 40 int *p2 = new int; // warn 41 int x = f(); 42 if (x==1) 43 return; 44 delete p2; 45 } 46 </pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=15237">PR15237</a> 47 </td></tr> 48 49 <tr><td><span class="name">memory.MismatchedFree 50 <br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> 51 Mismatched deallocation function is used 52 </td><td><pre> 53 #include <stdlib.h> 54 55 void test() { 56 int *p1 = new int; 57 int *p2 = new int[1]; 58 59 free(p1); // warn 60 free(p2); // warn 61 } 62 </pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=15238">PR15238</a> 63 </td></tr> 64 65 <tr><td><span class="name">memory.LeakPtrValChanged 66 <br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> 67 Potential memory leak: a pointer to newly allocated data loses its original 68 value 69 </td><td><pre> 70 #include <stdlib.h> 71 72 void f(const int *); 73 void g(int *); 74 75 void test() { 76 int *p1 = new int; 77 p1++; // warn 78 int *p2 = (int *)malloc(sizeof(int)); 79 p2 = p1; // warn 80 int *p3 = new int; 81 f(p3); 82 p3++; // warn 83 int *p4 = new int; 84 f(p4); 85 p4++; // ok 86 } 87 </pre></td><td class="aligned">done at r174678 (C case) 88 </td></tr> 89 90 <tr><td><span class="name">memory.LeakEvalOrder<br> 91 (C, C++)</span><br><br> 92 Potential memory leak: argument evaluation order is undefined, g() may never be called 93 </td><td><pre> 94 #include <stdlib.h> 95 96 void f1(int, int); 97 void f2(int*, int*); 98 int g(int *) { throw 1; }; 99 int h(); 100 101 void test() { 102 f1(g(new int), h()); // warn 103 f1(g((int *)malloc(sizeof(int))), h()); // warn 104 f2(new int, new int); 105 } 106 </pre></td><td class="aligned"></td></tr> 107 108 <tr><td><span class="name">memory.DstBufferTooSmall 109 <br>(C, C++)</span><br><br> 110 Destination buffer too small 111 </td><td><pre> 112 #include <string.h> 113 114 void test() { 115 const char* s1 = "abc"; 116 char *s2 = new char; 117 strcpy(s2, s1); // warn 118 119 int* p1 = new int[3]; 120 int* p2 = new int; 121 memcpy(p2, p1, 3); // warn 122 } 123 </pre></td><td class="aligned"></td></tr> 124 125 <tr><td><span class="name">memory.NegativeArraySize 126 <br>enhancement to experimental.security.MallocOverflow<br>(C, C++) 127 </span><br><br> 128 'n' is used to specify the buffer size may be negative 129 </td><td><pre> 130 #include <stdlib.h> 131 132 void test() { 133 int *p; 134 int n1 = -1; 135 p = new int[n1]; // warn 136 } 137 </pre></td><td class="aligned"></td></tr> 138 139 </table> 140 141 <!-- ======================= constructors/destructors ====================== --> 142 <h3>constructors/destructors</h3> 143 <table class="checkers"> 144 <col class="namedescr"><col class="example"><col class="progress"> 145 <thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> 146 147 <tr><td><span class="name">ctordtor.ExptInsideDtorExplicit<br> 148 (C++)</span><br><br> 149 It is dangerous to let an exception leave a destructor. Using try..catch will 150 solve the problem. 151 </td><td><pre> 152 void f(); 153 154 class A { 155 A() {} 156 ~A() { throw 1; } // warn 157 }; 158 </pre></td><td class="aligned"></td></tr> 159 160 <tr><td><span class="name">ctordtor.ExptInsideDtorImplicit<br> 161 (C++)</span><br><br> 162 Calls to functions inside a destructor that are known to throw exceptions is 163 dangerous. Using try..catch will solve the problem. 164 </td><td><pre> 165 void f() { throw 1; }; 166 167 class A { 168 A() {} 169 ~A() { f(); } // warn 170 }; 171 </pre></td><td class="aligned"></td></tr> 172 173 <tr><td><span class="name">ctordtor.PlacementSelfCopy<br> 174 (C++11)</span><br><br> 175 For a placement copy or move, it is almost certainly an error if the constructed object is also the object being copied from. 176 </td><td><pre> 177 class A {}; 178 179 void test(A *dst, A *src) { 180 ::new (dst) A(*dst); // warn (should be 'src') 181 } 182 </pre></td><td class="aligned"><!--rdar://problem/13688366--></td></tr> 183 184 </table> 185 186 <!-- ============================== exceptions ============================= --> 187 <h3>exceptions</h3> 188 <table class="checkers"> 189 <col class="namedescr"><col class="example"><col class="progress"> 190 <thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> 191 192 <tr><td><span class="name">exceptions.ThrowSpecButNotThrow 193 <br>(C++)</span><br><br> 194 Function prototype has throw(T) specifier but the function do not throw 195 </td><td><pre> 196 void f() throw(int) { // warn 197 } 198 </pre></td><td class="aligned"></td></tr> 199 200 <tr><td><span class="name">exceptions.NoThrowSpecButThrows 201 <br>(C++)</span><br><br> 202 An exception is throw from a function having the throw() specifier 203 </td><td><pre> 204 void f() throw() { 205 throw(1); // warn 206 } 207 </pre></td><td class="aligned"></td></tr> 208 209 <tr><td><span class="name">exceptions.ThrownTypeDiffersSpec 210 <br>(C++)</span><br><br> 211 The type of a thrown exception differs from those specified in the throw(T) 212 specifier 213 </td><td><pre> 214 struct S{}; 215 void f() throw(int) { 216 S s; 217 throw (s); // warn 218 } 219 </pre></td><td class="aligned"></td></tr> 220 221 </table> 222 223 <!-- ========================= smart pointers ============================== --> 224 <h3>smart pointers</h3> 225 <table class="checkers"> 226 <col class="namedescr"><col class="example"><col class="progress"> 227 <thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> 228 229 <tr><td><span class="name">smartptr.SmartPtrInit<br> 230 (C++)</span><br><br> 231 C++03: auto_ptr should store a pointer to an object obtained via new as allocated 232 memory will be cleaned using delete<br> 233 C++11: one should use unique_ptr<T[]> to keep a pointer to memory 234 allocated by new[]<br> 235 C++11: to keep a pointer to memory allocated by new[] in a shared_ptr one 236 should use a custom deleter that calls delete[] 237 </td><td><pre> 238 #include <stdlib.h> 239 #include <memory> 240 241 void test() { 242 std::auto_ptr<int> p1(new int); // Ok 243 std::auto_ptr<int> p2(new int[3]); // warn 244 std::auto_ptr<int> 245 p3((int *)malloc(sizeof(int))); // warn 246 } 247 </pre></td><td class="aligned"></td></tr> 248 249 </table> 250 251 <!-- ========================= undefined behavior ========================== --> 252 <h3>undefined behavior</h3> 253 <table class="checkers"> 254 <col class="namedescr"><col class="example"><col class="progress"> 255 <thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> 256 257 <tr><td><span class="name">undefbehavior.ExitInDtor 258 <br>(C++)</span><br><br> 259 Undefined behavior: std::exit is called to end the program during the 260 destruction of an object with static storage duration 261 </td><td><pre> 262 #include <cstdlib> 263 264 class A { 265 public: 266 ~A() { 267 std::exit(1); // warn 268 } 269 }; 270 271 A a; 272 </pre></td><td class="aligned"></td></tr> 273 274 <tr><td><span class="name">undefbehavior.LocalStaticDestroyed 275 <br>(C++)</span><br><br> 276 Undefined behavior: function containing a definition of static local object is 277 called during the destruction of an object with static storage duration so that 278 flow of control passes through the definition of the previously destroyed 279 static local object 280 </td><td><pre> 281 void f(); 282 283 class A { 284 public: 285 ~A() { 286 f(); // warn 287 } 288 }; 289 290 class B {}; 291 292 A a; 293 294 void f() { 295 static B b; // <- 296 } 297 </pre></td><td class="aligned"></td></tr> 298 299 <tr><td><span class="name">undefbehavior.UseAfterRelease 300 <br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> 301 Pointer to deleted object is referenced (The effect of using an invalid pointer 302 value is undefined) 303 </td><td><pre> 304 #include <stdlib.h> 305 306 void test() { 307 int *p = new int; 308 delete p; 309 int i = *p; // warn 310 } 311 312 </pre></td><td class="aligned"></td></tr> 313 314 <tr><td><span class="name">undefbehavior.ZeroAllocDereference 315 <br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> 316 The effect of dereferencing a pointer returned as a request for zero size is 317 undefined 318 </td><td><pre> 319 #include <stdlib.h> 320 321 int *p = new int[0]; 322 int i = p[0]; // warn 323 </pre></td><td class="aligned"></td></tr> 324 325 <tr><td><span class="name">undefbehavior.DeadReferenced 326 <br>(C++)</span><br><br> 327 Undefined behavior: the following usage of the pointer to the object whose 328 lifetime has ended can result in undefined behavior 329 </td><td><pre> 330 // C++03 331 #include <new> 332 333 class A { 334 public: 335 int i; 336 void f() {}; 337 }; 338 339 class B : public A { 340 }; 341 342 void test() { 343 B *b = new B; 344 new(b) A; 345 b->i; // warn 346 b->f(); // warn 347 static_cast<A*>(b); // warn 348 dynamic_cast<A*>(b); // warn 349 delete b; // warn 350 } 351 352 // C++11 353 #include <new> 354 355 class A { 356 public: 357 int i; 358 void f() {}; 359 }; 360 361 class B : public A { 362 public: 363 ~B() {}; 364 }; 365 366 void test() { 367 A *a = new A; 368 new(a) B; 369 a->i; // warn 370 a->f(); // warn 371 B *b = new B; 372 new(b) A; 373 b->i; // warn 374 b->f(); // warn 375 static_cast<A*>(b); // warn 376 dynamic_cast<A*>(b); // warn 377 delete b; // warn 378 } 379 </pre></td><td class="aligned"></td></tr> 380 381 <tr><td><span class="name">undefbehavior.ObjLocChanges 382 <br>(C++)</span><br><br> 383 Undefined behavior: the program must ensure that an object occupies the same 384 storage location when the implicit or explicit destructor call takes place 385 </td><td><pre> 386 #include <new> 387 388 class T { }; 389 struct B { 390 ~B(); 391 }; 392 393 void test() { 394 B *b1 = new B; 395 B b2; 396 new (b1) T; 397 new (&b2) T; 398 delete b1; // warn 399 } // warn 400 </pre></td><td class="aligned"></td></tr> 401 402 <tr><td><span class="name">undefbehavior.ExprEvalOrderUndef 403 <br>(C, C++03)</span><br><br> 404 Undefined behavior: a scalar object shall have its stored value modified at 405 most once by the evaluation of an expression 406 </td><td><pre> 407 void test () { 408 int i = 0; 409 int v[1] = {0}; 410 i = v[i++]; // warn 411 i = ++i + 1; // warn 412 } 413 </pre></td><td class="aligned"></td></tr> 414 415 <tr><td><span class="name">undefbehavior.StaticInitReentered 416 <br>(C)</span><br><br> 417 Undefined behavior: static declaration is re-entered while the object is being 418 initialized 419 </td><td><pre> 420 int test(int i) { 421 static int s = test(2*i); // warn 422 return i+1; 423 } 424 </pre></td><td class="aligned"></td></tr> 425 426 <tr><td><span class="name">undefbehavior.ConstModified 427 <br>(C, C++)</span><br><br> 428 Undefined behavior: const object is being modified 429 </td><td><pre> 430 #include <stdlib.h> 431 432 class X { 433 public : 434 mutable int i; 435 int j; 436 }; 437 class Y { 438 public : 439 X x; 440 Y(); 441 }; 442 443 void test() { 444 const int *ciq = 445 (int *)malloc(sizeof(int)); 446 int *iq = const_cast<int *>(ciq); 447 *iq = 1; // warn 448 449 const Y y; 450 Y* p = const_cast<Y*>(&y); 451 p->x.i = 1; // ok 452 p->x.j = 1; // warn 453 } 454 </pre></td><td class="aligned"></td></tr> 455 456 <tr><td><span class="name">undefbehavior.DeadDestructed 457 <br>(C++)</span><br><br> 458 Undefined behavior: the destructor is invoked for an object whose lifetime 459 has ended 460 </td><td><pre> 461 class A { 462 public: 463 void f() {}; 464 A() {}; 465 ~A() {}; 466 }; 467 468 void test() { 469 A a; 470 a.~A(); 471 } // warn 472 </pre></td><td class="aligned"></td></tr> 473 474 <tr><td><span class="name">undefbehavior.MethodCallBeforeBaseInit 475 <br>(C++)</span><br><br> 476 Undefined behavior: calls member function but base not yet initialized 477 </td><td><pre> 478 class A { 479 public : 480 A(int ); 481 }; 482 class B : public A { 483 public : 484 int f(); 485 B() : A(f()) {} // warn 486 }; 487 </pre></td><td class="aligned"></td></tr> 488 489 <tr><td><span class="name">undefbehavior.MemberOrBaseRefBeforeCtor 490 <br>(C++)</span><br><br> 491 C++ Undefined behavior: non-static member or base class of non-POD class type 492 is referred before constructor begins execution<br> 493 C++11 Undefined behavior: non-static member or base class of a class with a 494 non-trivial constructor is referred before constructor begins execution 495 </td><td><pre> 496 // C++03 497 struct POD { 498 int i; 499 }; 500 501 struct non_POD : public POD { 502 int j; 503 POD pod; 504 }; 505 506 extern POD pod; 507 extern non_POD non_pod; 508 509 int *p1 = &non_pod.j; // warn 510 int *p2 = &non_pod.pod.i; // warn 511 int *p3 = &pod.i; // ok 512 POD *p4 = &non_pod; // warn 513 514 POD a; 515 non_POD b; 516 517 struct S { 518 int *k; 519 non_POD non_pod; 520 S() : k(&non_pod.j) {} // warn 521 }; 522 523 // C++11 524 struct trivial { 525 int i; 526 }; 527 528 struct non_trivial: public trivial { 529 non_trivial() {}; 530 int j; 531 trivial pod; 532 }; 533 534 extern trivial t; 535 extern non_trivial nt; 536 537 int *p1 = &nt.j; // warn 538 int *p2 = &nt.i; // warn 539 int *p3 = &t.i; // ok 540 trivial *p4 = &nt; 541 542 trivial t; 543 non_trivial nt; 544 545 struct S { 546 int *k; 547 non_trivial nt; 548 S() : k(&nt.j) {} // warn 549 }; 550 </pre></td><td class="aligned"></td></tr> 551 552 <tr><td><span class="name">undefbehavior.MemberRefAfterDtor 553 <br>(C++)</span><br><br> 554 C++03: Undefined behavior: non-static member of non-POD class type is referred 555 after destructor ends execution<br> 556 C++11: Undefined behavior: non-static member of a class with a non-trivial 557 destructor is referred after destructor ends execution 558 </td><td><pre> 559 // C++03 560 struct non_POD { 561 virtual void f() {}; 562 }; 563 564 void test() { 565 non_POD *non_pod = new non_POD(); 566 non_pod->~non_POD(); 567 non_pod->f(); // warn 568 } 569 570 // C++11 571 struct S { 572 ~S() {}; 573 void f() {}; 574 }; 575 576 void test() { 577 S *s = new S(); 578 s->~S(); 579 s->f(); // warn 580 } 581 </pre></td><td class="aligned"></td></tr> 582 583 <tr><td><span class="name">undefbehavior.CtorForeignCall 584 <br>(C++)</span><br><br> 585 Undefined behavior: call to virtual function of an object under construction 586 whose type is neither the constructors own class or one of its bases 587 </td><td><pre> 588 class A { 589 public: 590 virtual void f() {}; 591 }; 592 593 class B { 594 public: 595 B(A* a) { a->f(); } // warn 596 }; 597 598 class C : public A, B { 599 public: 600 C() : B((A*)this) {} 601 }; 602 </pre></td><td class="aligned"></td></tr> 603 604 <tr><td><span class="name">undefbehavior.CtorForeignCast 605 undefbehavior.CtorForeignTypeid 606 <br>(C++)</span><br><br> 607 Undefined behavior: the operand of typeid/dynamic_cast is an object under 608 construction whose type is neither the constructors own class or one of its 609 bases 610 </td><td><pre> 611 #include <typeinfo> 612 613 class A { 614 public: 615 virtual void f() {}; 616 }; 617 618 class B { 619 public: 620 B(A* a) { 621 typeid(*a); // warn 622 dynamic_cast<B*>(a); //warn 623 } 624 }; 625 626 class C : public A, B { 627 public: 628 C() : B((A*)this) {} 629 }; 630 </pre></td><td class="aligned"></td></tr> 631 632 <tr><td><span class="name">undefbehavior.MemberRefInCatch 633 undefbehavior.BaseRefInCatch 634 <br>(C++)</span><br><br> 635 Undefined behavior: referring to any non-static member or base class of an 636 object in the handler for a function-try-block of a constructor or destructor 637 for that object results in undefined behavior 638 </td><td><pre> 639 class C { 640 int i; 641 public : 642 C() 643 try 644 : i(1) {} 645 catch (...) 646 { 647 i=2; // warn 648 } 649 }; 650 </pre></td><td class="aligned"></td></tr> 651 652 <tr><td><span class="name">undefbehavior.ReturnAtCatchEnd 653 <br>(C++)</span><br><br> 654 Undefined behavior: a function returns when control reaches the end of a 655 handler. This results in undefined behavior in a value-returning 656 function 657 </td><td><pre> 658 int test() try { 659 } 660 catch(int) { 661 } // warn 662 </pre></td><td class="aligned"></td></tr> 663 664 <tr><td><span class="name">undefbehavior.AutoptrsOwnSameObj 665 <br>(C++03)</span><br><br> 666 Undefined behavior: if more than one auto_ptr owns the same object at the same 667 time the behavior of the program is undefined. 668 </td><td><pre> 669 #include <memory> 670 671 void test() { 672 int *data = new int; 673 std::auto_ptr<int> p(data); 674 std::auto_ptr<int> q(data); // warn 675 } 676 </pre></td><td class="aligned"></td></tr> 677 678 <tr><td><span class="name">undefbehavior.BasicStringBoundAccess 679 <br>(C++03)</span><br><br> 680 Undefined behavior: out-of-bound basic_string access 681 </td><td><pre> 682 void test() { 683 std::basic_string<char> s; 684 char c = s[10]; // warn 685 } 686 </pre></td><td class="aligned"></td></tr> 687 688 <tr><td><span class="name">undefbehavior.BasicStringBoundModification 689 <br>(C++)</span><br><br> 690 Undefined behavior: out-of-bound basic_string modification 691 </td><td><pre> 692 void test() { 693 std::basic_string<char> s; 694 s[10] = 0; // warn 695 } 696 </pre></td><td class="aligned"></td></tr> 697 698 <tr><td><span class="name">undefbehavior.EosDereference 699 <br>(C++)</span><br><br> 700 Undefined behavior: the result of operator*() on an end of stream is 701 undefined 702 </td><td><pre> 703 #include <vector> 704 705 void test() { 706 std::vector<int> v; 707 int i = *v.end(); // warn 708 *v.end() = 0; // warn 709 } 710 </pre></td><td class="aligned"></td></tr> 711 712 <tr><td><span class="name">undefbehavior.QsortNonPOD 713 undefbehavior.QsortNonTrivial 714 <br>C++</span><br><br> 715 C++03: Undefined behavior: the objects in the array passed to qsort are of 716 non-POD type<br> 717 C++11: Undefined behavior: the objects in the array passed to qsort are of 718 non-trivial type 719 </td><td><pre> 720 // C++03 721 #include <cstdlib> 722 723 struct non_POD { 724 int i; 725 non_POD(int ii) : i(ii) {} 726 }; 727 728 non_POD values[] = { non_POD(2), non_POD(1) }; 729 730 int compare(const void *a, 731 const void *b) { 732 return ( (*(non_POD*)a).i - 733 (*(non_POD*)b).i ); 734 } 735 736 void test() { 737 qsort(values, 2, sizeof(non_POD), 738 compare); // warn 739 } 740 741 // C++11 742 #include <cstdlib> 743 744 struct S {}; 745 746 struct trivial_non_POD : public S { 747 int i; 748 }; 749 750 struct non_trivial { 751 int i; 752 non_trivial() {} 753 }; 754 755 trivial_non_POD tnp[2]; 756 non_trivial nt[2]; 757 758 int compare1(const void *a, 759 const void *b) { 760 return ( (*(trivial_non_POD *)a).i - 761 (*(trivial_non_POD *)b).i ); 762 } 763 764 int compare2(const void *a, 765 const void *b) { 766 return ( (*(non_trivial *)a).i - 767 (*(non_trivial *)b).i ); 768 } 769 770 void test() { 771 qsort(tnp, 2, sizeof(trivial_non_POD), 772 compare1); // ok 773 qsort(nt, 2, sizeof(non_trivial), 774 compare2); // warn 775 } 776 </pre></td><td class="aligned"></td></tr> 777 778 <tr><td><span class="name">undefbehavior.ThrowWhileCopy 779 <br>C++</span><br><br> 780 Undefined behavior: copy constructor/assignment operator can throw an exception. 781 The effects are undefined if an exception is thrown. 782 </td><td><pre> 783 struct S { 784 int i, j; 785 S (const S &s) { 786 i = s.i; 787 throw 1; // warn 788 j = s.j; 789 }; 790 S &operator=(const S &s) { 791 i = s.i; 792 throw 1; // warn 793 j = s.j; 794 } 795 }; 796 </pre></td><td class="aligned"></td></tr> 797 798 <tr><td><span class="name">undefbehavior.ValarrayArgBound 799 <br>(C++)</span><br><br> 800 Undefined behavior: the value of the second argument is greater than the number 801 of values pointed to by the first argument 802 </td><td><pre> 803 #include <valarray> 804 805 struct S { 806 int i; 807 S(int ii) : i(ii) {}; 808 }; 809 810 void test(void) { 811 S s[] = { S(1), S(2) }; 812 std::valarray<S> v(s,3); // warn 813 } 814 </pre></td><td class="aligned"></td></tr> 815 816 <tr><td><span class="name">undefbehavior.ValarrayLengthDiffer 817 <br>(C++)</span><br><br> 818 Undefined behavior: valarray operands are of different length 819 </td><td><pre> 820 // C++03 821 #include <valarray> 822 823 void test(void) { 824 std::valarray<int> a(0, 1), b(0, 2); 825 std::valarray<bool> c(false, 1); 826 a = b; // warn 827 a *= b; // warn 828 a = a * b; // warn 829 c = a == b; // warn 830 b.resize(1); 831 a = b; // OK 832 } 833 834 // C++11 835 #include <valarray> 836 837 void test(void) { 838 std::valarray<int> a(0, 1), b(0, 2); 839 std::valarray<bool> c(false, 1); 840 a = b; // ok 841 a *= b; // ok 842 a = a * b; // warn 843 c = a == b; // warn 844 b.resize(1); 845 a = b; // OK 846 } 847 </pre></td><td class="aligned"></td></tr> 848 849 <tr><td><span class="name">undefbehavior.ValarrayZeroLength 850 <br>(C++)</span><br><br> 851 Undefined behavior: calling sum()/min()/max() method of an array having zero 852 length, the behavior is undefined 853 </td><td><pre> 854 #include <valarray> 855 856 void test(void) { 857 std::valarray<int> v(0, 0); 858 v.sum(); // warn 859 v.min(); // warn 860 v.max(); // warn 861 } 862 </pre></td><td class="aligned"></td></tr> 863 864 <tr><td><span class="name">undefbehavior.ValarrayBadIndirection 865 <br>(C++)</span><br><br> 866 Undefined behavior: element N is specified more than once in the 867 indirection 868 </td><td><pre> 869 #include <valarray> 870 871 void test() { 872 size_t addr[] = {0, 1, 1}; // N is 1 873 std::valarray<size_t>indirect(addr, 3); 874 std::valarray<int> a(0, 5), b(1, 3); 875 a[indirect] = b; //warn 876 a[indirect] *= b; //warn 877 } 878 </pre></td><td class="aligned"></td></tr> 879 880 <tr><td><span class="name">undefbehavior.IosBaseDestroyedBeforeInit 881 <br>(C++)</span><br> 882 <br>Undefined behavior: ios_base object is destroyed before initialization have 883 taken place. basic_ios::init should be call to initialize ios_base 884 members 885 </td><td><pre> 886 #include <ios> 887 888 using namespace std; 889 template <class T, class Traits = std::char_traits<T>> 890 class my_stream1 : public std::basic_ios<T, Traits> { 891 }; 892 893 template <class T, class Traits = std::char_traits<T>> 894 class my_stream2 : public std::basic_ios<T, Traits> { 895 class my_streambuf : public std::basic_streambuf<T, Traits> { 896 }; 897 public: 898 my_stream2() { 899 this->init(new my_streambuf); 900 } 901 }; 902 903 void test() { 904 my_stream1<char> *p1 = new my_stream1<char> 905 my_stream2<char> *p2 = new my_stream2<char> 906 delete p1; // warn 907 delete p2; // ok 908 } 909 </pre></td><td class="aligned"></td></tr> 910 911 <tr><td><span class="name">undefbehavior.IosBaseUsedBeforeInit 912 <br>(C++11)</span><br><br> 913 Undefined behavior: ios_base object is used before initialization have taken 914 place. basic_ios::init should be call to initialize ios_base members 915 </td><td><pre> 916 #include <ios> 917 918 using namespace std; 919 template <class T, class Traits = std::char_traits<T>> 920 class my_stream1 : public std::basic_ios<T, Traits> { 921 }; 922 923 template <class T, class Traits = std::char_traits<T>> 924 class my_stream2 : public std::basic_ios<T, Traits> { 925 class my_streambuf : public std::basic_streambuf<T, Traits> { 926 }; 927 public: 928 my_stream2() { 929 this->init(new my_streambuf); 930 } 931 }; 932 933 void test() { 934 my_stream1<char> *p1 = new my_stream1<char> 935 my_stream2<char> *p2 = new my_stream2<char> 936 p1->narrow('a', 'b'); // warn 937 p2->narrow('a', 'b'); // ok 938 delete p1; // warn 939 delete p2; // ok 940 } 941 </pre></td><td class="aligned"></td></tr> 942 943 <tr><td><span class="name">undefbehavior.MinusOnePosType 944 <br>(C++)</span><br><br> 945 Undefined behavior: passing -1 to any streambuf/istream/ostream member that 946 accepts a value of type traits::pos_type result in undefined behavior 947 </td><td><pre> 948 #include <fstream> 949 950 class my_streambuf : public std::streambuf { 951 void f() { 952 seekpos(-1); // warn 953 } 954 }; 955 956 void test() { 957 std::filebuf fb; 958 std::istream in(&fb); 959 std::ostream out(&fb); 960 std::filebuf::off_type pos(-1); 961 in.seekg(pos); // warn 962 out.seekp(-1); // warn 963 } 964 </pre></td><td class="aligned"></td></tr> 965 </table> 966 967 <!-- ============================ different ================================ --> 968 <h3>different</h3> 969 <table class="checkers"> 970 <col class="namedescr"><col class="example"><col class="progress"> 971 <thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr> 972 </thead> 973 974 <tr><td><span class="name">different.ArgEvalOrderUndef 975 <br>(C)</span><br><br> 976 Errors because of the order of evaluation of function arguments is undefined 977 </td><td><pre> 978 void f(int, int); 979 980 void test() { 981 int i = 0; 982 int v[1] = {0}; 983 f(v[i], i++); // warn 984 } 985 </pre></td><td class="aligned"></td></tr> 986 987 <tr><td><span class="name">different.IdenticalExprBinOp 988 <br>(C)</span><br><br> 989 There are identical sub-expressions to the left and to the right of the 990 operator 991 </td><td><pre> 992 #define A 1 993 #define B 1 994 995 bool isNan(double d) { 996 return d != d; // ok 997 } 998 999 int f(); 1000 1001 void test() { 1002 int i = 0; 1003 if (i != 0 && i != 0) {} // warn 1004 1005 if(i == A || i == B) {} // ok 1006 1007 if (++i != 0 && ++i != 0) {} // ok 1008 1009 if (f() && f()) {} // ok 1010 } 1011 </pre></td><td class="aligned"></td></tr> 1012 1013 <tr><td><span class="name">different.FuncPtrInsteadOfCall 1014 <br>(C)</span><br><br> 1015 Possibly a function call should be used instead of a pointer to function 1016 </td><td><pre> 1017 int f(); 1018 1019 void test() { 1020 if (f == 0) {} // warn 1021 } 1022 </pre></td><td class="aligned"></td></tr> 1023 1024 <tr><td><span class="name">different.IdenticalCondIfElseIf 1025 <br>(C)</span><br><br> 1026 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a 1027 probability of logical error presence 1028 </td><td><pre> 1029 void test() { 1030 int i = 7; 1031 if (i == 1) {} 1032 else if (i == 1) {} // warn 1033 } 1034 </pre></td><td class="aligned"></td></tr> 1035 1036 <tr><td><span class="name">SuccessiveAssign 1037 <br>(C)</span><br><br> 1038 Successive assign to a variable 1039 </td><td><pre> 1040 void test() { 1041 int i=0; 1042 i=1; 1043 i=2; // warn 1044 } 1045 </pre></td><td class="aligned"></td></tr> 1046 1047 <tr><td><span class="name">different.NullDerefStmtOrder 1048 <br>enhancement to core.NullDereference<br>(C)</span><br><br> 1049 Dereferencing of the null pointer might take place. Checking the pointer for 1050 null should be performed first 1051 </td><td><pre> 1052 struct S { 1053 int x; 1054 }; 1055 1056 S* f(); 1057 1058 void test() { 1059 S *p1 = f(); 1060 int x1 = p1->x; // warn 1061 if (p1) {}; 1062 1063 S *p2 = f(); 1064 int x2 = p2->x; // ok 1065 } 1066 </pre></td><td class="aligned"></td></tr> 1067 1068 <tr><td><span class="name">different.NullDerefCondOrder 1069 <br>enhancement to core.NullDereference<br>(C)</span><br><br> 1070 Dereferencing of the null pointer might take place. Checking the pointer for 1071 null should be performed first 1072 </td><td><pre> 1073 struct S{bool b;}; 1074 1075 S* f(); 1076 1077 void test() { 1078 S *p = f(); 1079 if (p->b && p) {}; // warn 1080 } 1081 </pre></td><td class="aligned"></td></tr> 1082 1083 <tr><td><span class="name">different.IdenticalStmtThenElse 1084 <br>(C)</span><br><br> 1085 The 'else' statement is equivalent to the 'then' statement 1086 </td><td><pre> 1087 void test() { 1088 int i; 1089 if (i==1) { 1090 i++; 1091 } 1092 else { // warn 1093 i++; 1094 } 1095 } 1096 </pre></td><td class="aligned"></td></tr> 1097 1098 <tr><td><span class="name">different.MultipleAccessors 1099 <br>(C++)</span><br><br> 1100 multiple accessors met for 'class::field' 1101 </td><td><pre> 1102 class A { 1103 int i; 1104 int j; 1105 public: 1106 int getI() { return i; } 1107 int getJ() { return i; } // warn 1108 void setI(int& ii) { i = ii; } 1109 void setJ(int& jj) { i = jj; } // warn 1110 }; 1111 </pre></td><td class="aligned"></td></tr> 1112 1113 <tr><td><span class="name">different.AccessorsForPublic 1114 <br>(C++)</span><br><br> 1115 Accessors exist for 'class::field'. Should this field really be public? 1116 </td><td><pre> 1117 class A { 1118 public: 1119 int i; // warn 1120 int getI() { return i; } 1121 void setI(int& ii) { i = ii; } 1122 }; 1123 </pre></td><td class="aligned"></td></tr> 1124 1125 <tr><td><span class="name">different.LibFuncResultUnised 1126 <br>(C, C++)</span><br><br> 1127 Calling 'f' ignoring its return value is of no use (* create the list of known 1128 system/library/API functions falling into this category) 1129 </td><td><pre> 1130 #include <vector> 1131 1132 void test() { 1133 std::vector<int> v; 1134 v.empty(); // warn 1135 } 1136 </pre></td><td class="aligned"></td></tr> 1137 1138 <tr><td><span class="name">different.WrongVarForStmt 1139 <br>(C, C++)</span><br><br> 1140 Possibly wrong variable is used in the loop/cond-expression of the 'for' 1141 statement. Did you mean 'proper_variable_name'? 1142 </td><td><pre> 1143 void test() { 1144 int i; 1145 int j; 1146 for (j=0; j<3; ++i); // warn 1147 for (int j=0; i<3; ++j); // warn 1148 } 1149 </pre></td><td class="aligned"></td></tr> 1150 1151 <tr><td><span class="name">different.FloatingCompare 1152 <br>(C)</span><br><br> 1153 Comparing floating point numbers may be not precise 1154 </td><td><pre> 1155 #include <math.h> 1156 1157 void test() { 1158 double b = sin(M_PI / 6.0); 1159 if (b == 0.5) // warn 1160 b = 0; 1161 } 1162 </pre></td><td class="aligned"></td></tr> 1163 1164 <tr><td><span class="name">different.BoolCompare 1165 <br>maybe merge with experimental.core.BoolAssignment<br>(C, C++)</span><br><br> 1166 Comparing boolean to a value other then 0 or 1 1167 </td><td><pre> 1168 void test() { 1169 int i; 1170 if (0 < i < 3) {}; // warn 1171 bool b; 1172 if (b == 3) {}; // warn 1173 } 1174 </pre></td><td class="aligned"></td></tr> 1175 1176 <tr><td><span class="name">different.BitwiseOpBoolArg 1177 <br>maybe join with experimental.core.BoolAssignment<br>(C, C++)</span><br><br> 1178 bool value is used at the left/right part of the & (|) operator. Did you mean 1179 && (||) ? 1180 </td><td><pre> 1181 int f(); 1182 1183 void test() { 1184 bool b = true; 1185 if (b & f()) {} // warn 1186 } 1187 </pre></td><td class="aligned"></td></tr> 1188 1189 <tr><td><span class="name">different.LabelInsideSwitch 1190 <br>(C)</span><br><br> 1191 Possible misprint: label found inside the switch() statement. (* did you mean 1192 'default'?) 1193 </td><td><pre> 1194 void test() { 1195 int c = 7; 1196 switch(c){ 1197 case 1: 1198 c += 1; break; 1199 defalt: // warn 1200 c -= 1; break; 1201 } 1202 } 1203 </pre></td><td class="aligned"></td></tr> 1204 1205 <tr><td><span class="name">different.IdenticalCondIfIf 1206 <br>(C)</span><br><br> 1207 The conditions of two subsequent 'if' statements are identical 1208 </td><td><pre> 1209 void test() { 1210 int c = 7; 1211 if (c > 5) // <- 1212 c += 1; 1213 if (c > 5) // warn 1214 c -= 1; 1215 } 1216 </pre></td><td class="aligned"></td></tr> 1217 1218 <tr><td><span class="name">different.CondOpIdenticalReturn 1219 <br>(C)</span><br><br> 1220 The return expressions of the '?:' operator are identical 1221 </td><td><pre> 1222 void test() { 1223 unsigned a; 1224 a = a > 5 ? a : a; // warn 1225 } 1226 </pre></td><td class="aligned"></td></tr> 1227 1228 <tr><td><span class="name">different.LogicalOpUselessArg 1229 <br>(C)</span><br><br> 1230 The second operand of the && operator has no impact on expression result 1231 </td><td><pre> 1232 void test() { 1233 unsigned a; 1234 if (a<7 && a<10) {}; // warn 1235 } 1236 </pre></td><td class="aligned"></td></tr> 1237 1238 <tr><td><span class="name">different.SameResLogicalExpr 1239 <br>(C)</span><br><br> 1240 The expression always evaluates to true/false 1241 </td><td><pre> 1242 void test() { 1243 int i=0; 1244 if (i!=0) {}; // warn 1245 if (i==0 && i==1) {}; // warn 1246 if (i<0 || i>=0) {}; // warn 1247 } 1248 </pre></td><td class="aligned"></td></tr> 1249 1250 <tr><td><span class="name">different.SameResUnsignedCmp 1251 <br>(C)</span><br><br> 1252 Comparison of unsigned expression 'op expr' is always true/false 1253 </td><td><pre> 1254 void test() { 1255 unsigned u; 1256 if (u < -1) {}; // warn 1257 if (u >= 0) {}; // warn 1258 } 1259 </pre></td><td class="aligned"></td></tr> 1260 1261 <tr><td><span class="name">different.OpPrecedenceAssignCmp 1262 <br>(C)</span><br><br> 1263 Comparison operation has higher precedence then assignment. Bool value is 1264 assigned to variable of type 'type'. Parenthesis may bee required around an 1265 assignment 1266 </td><td><pre> 1267 int f(); 1268 1269 void test() { 1270 bool b; 1271 int x, y; 1272 if((b = x != y)) {} // ok 1273 if((x = f() != y)) {} // warn 1274 } 1275 </pre></td><td class="aligned"></td></tr> 1276 1277 <tr><td><span class="name">different.OpPrecedenceIifShift 1278 <br>(C)</span><br><br> 1279 ?: has lower precedence then << 1280 </td><td><pre> 1281 #include <iostream> 1282 1283 void test() { 1284 int a; 1285 std::cout << a ? "a" : "b"; // warn 1286 a << a>7 ? 1 : 2; // warn 1287 } 1288 </pre></td><td class="aligned"></td></tr> 1289 1290 <tr><td><span class="name">different.ObjectUnused 1291 <br>(C++)</span><br><br> 1292 The object was created but is not being used<br><br> 1293 The exception object was created but is not being used. Did you mean 1294 'throw std::exception();'? 1295 </td><td><pre> 1296 #include <exception> 1297 1298 struct S { 1299 int x, y; 1300 S(int xx, int yy) : x(xx), y(yy) { 1301 } 1302 S(int xx) { 1303 S(xx, 0); // warn 1304 } 1305 }; 1306 1307 void test() { 1308 S(0, 0); // warn 1309 std::exception(); // warn 1310 } 1311 </pre></td><td class="aligned"></td></tr> 1312 1313 <tr><td><span class="name">different.StaticArrayPtrCompare 1314 <br>(C)</span><br><br> 1315 Pointer to static array is being compared to NULL. May the subscripting is 1316 missing 1317 </td><td><pre> 1318 void test() { 1319 int a1[1]; 1320 if (a1 == 0) {}; // warn 1321 1322 int a2[1][1]; 1323 if (a2[0]) {}; // warn 1324 } 1325 </pre></td><td class="aligned"></td></tr> 1326 1327 <tr><td><span class="name">different.ConversionToBool 1328 <br>maybe join with experimental.core.BoolAssignment<br>(C, C++)</span><br><br> 1329 Odd implicit conversion from 'type' to 'bool' 1330 </td><td><pre> 1331 bool test() { 1332 return 1.; // warn 1333 return ""; // warn 1334 } 1335 </pre></td><td class="aligned"></td></tr> 1336 1337 <tr><td><span class="name">different.ArrayBound 1338 <br>enhancement to experimental.security.ArrayBound[v2]<br>(C, C++)</span><br><br> 1339 Out-of-bound dynamic array access 1340 </td><td><pre> 1341 #include <stdlib.h> 1342 1343 void test() { 1344 int *p2 = new int[1]; 1345 if(p2[1]) {}; // warn 1346 int i = 1; 1347 if(p2[i]) {}; // warn 1348 } 1349 </pre></td><td class="aligned"></td></tr> 1350 1351 <tr><td><span class="name">different.StrcpyInputSize 1352 <BR>enhancement to experimental.unix.cstring.OutOfBounds<br>(C)</span><br><br> 1353 Buffer copy without checking size of input 1354 </td><td><pre> 1355 void test(char* string) { 1356 char buf[24]; 1357 strcpy(buf, string); // warn 1358 } 1359 </pre></td><td class="aligned"></td></tr> 1360 1361 <tr><td><span class="name">different.IntegerOverflow 1362 <br>(C)</span><br><br> 1363 Integer overflow 1364 </td><td><pre> 1365 #include <limits.h> 1366 1367 int f(int x) { 1368 return INT_MAX+1; // warn 1369 } 1370 1371 void test() { 1372 int x = INT_MAX+1; // warn 1373 f(INT_MAX+1); // warn 1374 1375 int y = INT_MAX/2+1; // warn 1376 x = y*2; // warn 1377 } 1378 </pre></td><td class="aligned"></td></tr> 1379 1380 <tr><td><span class="name">different.SignExtension 1381 <br>(C)</span><br><br> 1382 Unexpected sign extension might take place 1383 </td><td><pre> 1384 void f(unsigned int i); 1385 int g(); 1386 1387 unsigned int test() { 1388 long long sll; 1389 unsigned long long ull = sll; // warn 1390 long sl; 1391 unsigned long ul = sl; // warn 1392 int si; 1393 unsigned int ui = si; // warn 1394 short ss; 1395 unsigned short us = ss; // warn 1396 signed char sc; 1397 unsigned char uc = sc; // warn 1398 f(si); // warn 1399 ui = g(); // warn 1400 return si; // warn 1401 } 1402 </pre></td><td class="aligned"></td></tr> 1403 1404 <tr><td><span class="name">different.NumericTruncation 1405 <br>(C)</span><br><br> 1406 Numeric truncation might take place 1407 </td><td><pre> 1408 void f(int i); 1409 int g(); 1410 1411 int test() { 1412 unsigned long long ull; 1413 long long sll; 1414 unsigned long ul = ull; // warn 1415 long sl = sll; // warn 1416 unsigned int ui = ul; // warn 1417 int si = sl; // warn 1418 unsigned short us = ui; // warn 1419 short ss = si; // warn 1420 unsigned char uc = us; // warn 1421 signed char sc = uc; // warn 1422 f(sll); // warn 1423 ss = g(); // warn 1424 return sll; // warn 1425 } 1426 </pre></td><td class="aligned"></td></tr> 1427 1428 <tr><td><span class="name">different.MissingCopyCtorAssignOp 1429 <br>(C, C++)</span><br><br> 1430 The class has dynamically allocated data members but do not define a copy 1431 constructor/assignment operator 1432 </td><td><pre> 1433 class C { // warn 1434 int *p; // <- 1435 public: 1436 C() { p = new int; } 1437 ~C() { delete p; } 1438 }; 1439 </pre></td><td class="aligned"></td></tr> 1440 1441 </table> 1442 1443 <!-- ============================ WinAPI =================================== --> 1444 <h3>WinAPI</h3> 1445 <table class="checkers"> 1446 <col class="namedescr"><col class="example"><col class="progress"> 1447 <thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> 1448 1449 <tr><td><span class="name">WinAPI.CreateProcess 1450 <br>(C)</span><br><br> 1451 After calling CreateProcess(), ensure that process and thread handles get closed 1452 (* for the given example: examine data flow from pi, pi.hProcess and pi.hThread) 1453 </td><td><pre> 1454 #include <windows.h> 1455 1456 void test() { 1457 STARTUPINFO si; 1458 PROCESS_INFORMATION pi; 1459 BOOL fSuccess; 1460 fSuccess = CreateProcess( 1461 NULL, TEXT("MyProgram.exe"), NULL, NULL, 1462 TRUE, 0, NULL, NULL, &si, &pi); 1463 } // warn 1464 </pre></td><td class="aligned"></td></tr> 1465 1466 <tr><td><span class="name">WinAPI.LoadLibrary 1467 <br>(C)</span><br><br> 1468 Calling LoadLibrary without a fully qualified path may allow to load a DLL from 1469 arbitrary location 1470 </td><td><pre> 1471 #include <windows.h> 1472 1473 void test() { 1474 HINSTANCE h = LoadLibrary("X.dll"); // warn 1475 } 1476 </pre></td><td class="aligned"></td></tr> 1477 1478 <tr><td><span class="name">WinAPI.WideCharToMultiByte 1479 <br>(C)</span><br><br> 1480 Buffer overrun while calling WideCharToMultiByte 1481 </td><td><pre> 1482 #include <windows.h> 1483 1484 void test() 1485 { 1486 wchar_t ws[] = L"abc"; 1487 char s[3]; 1488 int res1 = WideCharToMultiByte( 1489 CP_UTF8, 0, ws, -1, s, 1490 3, NULL, NULL); // warn 1491 int res2 = WideCharToMultiByte( 1492 CP_UTF8, 0, ws, -1, s, 1493 3, NULL, NULL); // ok 1494 if (res2 == sizeof(s)) 1495 s[res2-1] = 0; 1496 else 1497 s[res2] = 0; 1498 } 1499 </pre></td><td class="aligned"></td></tr> 1500 1501 </table> 1502 1503 <!-- =========================== optimization ============================== --> 1504 <h3>optimization</h3> 1505 <table class="checkers"> 1506 <col class="namedescr"><col class="example"><col class="progress"> 1507 <thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> 1508 1509 <tr><td><span class="name">optimization.PassConstObjByValue 1510 <br>(C, C++)</span><br><br> 1511 Optimization: It is more effective to pass const n-th parameter by reference to 1512 avoid unnecessary object copying 1513 </td><td><pre> 1514 struct A { 1515 int a[20]; 1516 int b; 1517 }; 1518 1519 bool FirstIsZero(const struct A a) { // warn 1520 return a.a[0] == 0; 1521 } 1522 </pre></td><td class="aligned"></td></tr> 1523 1524 <tr><td><span class="name">optimization.PostfixIncIter 1525 <br>(C++)</span><br><br> 1526 Optimization: It is more effective to use prefix ++ with iterator here 1527 </td><td><pre> 1528 #include <vector> 1529 1530 void test() { 1531 std::vector<int> v; 1532 std::vector<int>::const_iterator it; 1533 for(it = v.begin(); 1534 it != v.end(); it++) {}; // warn 1535 } 1536 </pre></td><td class="aligned"></td></tr> 1537 1538 <tr><td><span class="name">optimization.MultipleCallsStrlen 1539 <br>(C)</span><br><br> 1540 Optimization: multiple calls to strlen for a given string in the given 1541 expression. It is more effective to hold strlen result in a temporary 1542 variable 1543 </td><td><pre> 1544 #include <string.h> 1545 1546 void test() { 1547 const char* s = "abc"; 1548 if (strlen(s) > 0 && 1549 strlen(s) < 7) {}; // warn 1550 } 1551 </pre></td><td class="aligned"></td></tr> 1552 1553 <tr><td><span class="name">optimization.EmptyCstrDetect 1554 <br>(C)</span><br><br> 1555 Optimization: it is more efficient to use "str[0] != '\0'" to identify an empty 1556 string 1557 </td><td><pre> 1558 #include <string.h> 1559 1560 void test() { 1561 const char* s = "abc"; 1562 if (strlen(s) > 0) {}; // warn 1563 } 1564 </pre></td><td class="aligned"></td></tr> 1565 1566 <tr><td><span class="name">optimization.StrLengthCalculation 1567 <br>(C, C++)</span><br><br> 1568 Optimization: it is more efficient to use string::length() method to calculate 1569 string length 1570 </td><td><pre> 1571 #include <string> 1572 #include <string.h> 1573 1574 void test() { 1575 std::string s; 1576 if (strlen(s.c_str()) != 0) {}; // warn 1577 } 1578 </pre></td><td class="aligned"></td></tr> 1579 1580 <tr><td><span class="name">optimization.EmptyContainerDetect 1581 <br>(C, C++)</span><br><br> 1582 Optimization: It is more efficient to use container.empty() to identify an 1583 empty container 1584 </td><td><pre> 1585 #include <list> 1586 1587 void test() { 1588 std::list<int> l; 1589 if (l.size() != 0) {}; // warn 1590 } 1591 </pre></td><td class="aligned"></td></tr> 1592 1593 </table> 1594 1595 <br> 1596 </div> <!-- page --> 1597 </div> <!-- content --> 1598 </body> 1599 </html> 1600