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> 31Memory may be never released, potential leak of memory 32</td><td> 33<pre> 34#include <stdlib.h> 35 36int f() {}; 37 38void 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> 51Mismatched deallocation function is used 52</td><td><pre> 53#include <stdlib.h> 54 55void 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> 67Potential memory leak: a pointer to newly allocated data loses its original 68value 69</td><td><pre> 70#include <stdlib.h> 71 72void f(const int *); 73void g(int *); 74 75void 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> 92Potential memory leak: argument evaluation order is undefined, g() may never be called 93</td><td><pre> 94#include <stdlib.h> 95 96void f1(int, int); 97void f2(int*, int*); 98int g(int *) { throw 1; }; 99int h(); 100 101void 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> 110Destination buffer too small 111</td><td><pre> 112#include <string.h> 113 114void 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 132void 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> 149It is dangerous to let an exception leave a destructor. Using try..catch will 150solve the problem. 151</td><td><pre> 152void f(); 153 154class 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> 162Calls to functions inside a destructor that are known to throw exceptions is 163dangerous. Using try..catch will solve the problem. 164</td><td><pre> 165void f() { throw 1; }; 166 167class 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> 175For 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> 177class A {}; 178 179void 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> 194Function prototype has throw(T) specifier but the function do not throw 195</td><td><pre> 196void 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> 202An exception is throw from a function having the throw() specifier 203</td><td><pre> 204void 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> 211The type of a thrown exception differs from those specified in the throw(T) 212specifier 213</td><td><pre> 214struct S{}; 215void 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> 231C++03: auto_ptr should store a pointer to an object obtained via new as allocated 232memory will be cleaned using delete<br> 233C++11: one should use unique_ptr<T[]> to keep a pointer to memory 234allocated by new[]<br> 235C++11: to keep a pointer to memory allocated by new[] in a shared_ptr one 236should use a custom deleter that calls delete[] 237</td><td><pre> 238#include <stdlib.h> 239#include <memory> 240 241void 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> 259Undefined behavior: std::exit is called to end the program during the 260destruction of an object with static storage duration 261</td><td><pre> 262#include <cstdlib> 263 264class A { 265public: 266 ~A() { 267 std::exit(1); // warn 268 } 269}; 270 271A a; 272</pre></td><td class="aligned"></td></tr> 273 274<tr><td><span class="name">undefbehavior.LocalStaticDestroyed 275<br>(C++)</span><br><br> 276Undefined behavior: function containing a definition of static local object is 277called during the destruction of an object with static storage duration so that 278flow of control passes through the definition of the previously destroyed 279static local object 280</td><td><pre> 281void f(); 282 283class A { 284public: 285 ~A() { 286 f(); // warn 287 } 288}; 289 290class B {}; 291 292A a; 293 294void 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> 301Pointer to deleted object is referenced (The effect of using an invalid pointer 302value is undefined) 303</td><td><pre> 304#include <stdlib.h> 305 306void 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> 316The effect of dereferencing a pointer returned as a request for zero size is 317undefined 318</td><td><pre> 319#include <stdlib.h> 320 321int *p = new int[0]; 322int 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> 327Undefined behavior: the following usage of the pointer to the object whose 328lifetime has ended can result in undefined behavior 329</td><td><pre> 330// C++03 331#include <new> 332 333class A { 334public: 335 int i; 336 void f() {}; 337}; 338 339class B : public A { 340}; 341 342void 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 355class A { 356public: 357 int i; 358 void f() {}; 359}; 360 361class B : public A { 362public: 363 ~B() {}; 364}; 365 366void 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> 383Undefined behavior: the program must ensure that an object occupies the same 384storage location when the implicit or explicit destructor call takes place 385</td><td><pre> 386#include <new> 387 388class T { }; 389struct B { 390 ~B(); 391}; 392 393void 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> 404Undefined behavior: a scalar object shall have its stored value modified at 405most once by the evaluation of an expression 406</td><td><pre> 407void 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> 417Undefined behavior: static declaration is re-entered while the object is being 418initialized 419</td><td><pre> 420int 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> 428Undefined behavior: const object is being modified 429</td><td><pre> 430#include <stdlib.h> 431 432class X { 433public : 434 mutable int i; 435 int j; 436}; 437class Y { 438public : 439 X x; 440 Y(); 441}; 442 443void 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> 458Undefined behavior: the destructor is invoked for an object whose lifetime 459has ended 460</td><td><pre> 461class A { 462public: 463 void f() {}; 464 A() {}; 465 ~A() {}; 466}; 467 468void 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> 476Undefined behavior: calls member function but base not yet initialized 477</td><td><pre> 478class A { 479public : 480 A(int ); 481}; 482class B : public A { 483public : 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> 491C++ Undefined behavior: non-static member or base class of non-POD class type 492is referred before constructor begins execution<br> 493C++11 Undefined behavior: non-static member or base class of a class with a 494non-trivial constructor is referred before constructor begins execution 495</td><td><pre> 496// C++03 497struct POD { 498 int i; 499}; 500 501struct non_POD : public POD { 502 int j; 503 POD pod; 504}; 505 506extern POD pod; 507extern non_POD non_pod; 508 509int *p1 = &non_pod.j; // warn 510int *p2 = &non_pod.pod.i; // warn 511int *p3 = &pod.i; // ok 512POD *p4 = &non_pod; // warn 513 514POD a; 515non_POD b; 516 517struct S { 518 int *k; 519 non_POD non_pod; 520 S() : k(&non_pod.j) {} // warn 521}; 522 523// C++11 524struct trivial { 525 int i; 526}; 527 528struct non_trivial: public trivial { 529 non_trivial() {}; 530 int j; 531 trivial pod; 532}; 533 534extern trivial t; 535extern non_trivial nt; 536 537int *p1 = &nt.j; // warn 538int *p2 = &nt.i; // warn 539int *p3 = &t.i; // ok 540trivial *p4 = &nt; 541 542trivial t; 543non_trivial nt; 544 545struct 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> 554C++03: Undefined behavior: non-static member of non-POD class type is referred 555after destructor ends execution<br> 556C++11: Undefined behavior: non-static member of a class with a non-trivial 557destructor is referred after destructor ends execution 558</td><td><pre> 559// C++03 560struct non_POD { 561 virtual void f() {}; 562}; 563 564void test() { 565 non_POD *non_pod = new non_POD(); 566 non_pod->~non_POD(); 567 non_pod->f(); // warn 568} 569 570// C++11 571struct S { 572 ~S() {}; 573 void f() {}; 574}; 575 576void 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> 585Undefined behavior: call to virtual function of an object under construction 586whose type is neither the constructors own class or one of its bases 587</td><td><pre> 588class A { 589public: 590 virtual void f() {}; 591}; 592 593class B { 594public: 595 B(A* a) { a->f(); } // warn 596}; 597 598class C : public A, B { 599public: 600 C() : B((A*)this) {} 601}; 602</pre></td><td class="aligned"></td></tr> 603 604<tr><td><span class="name">undefbehavior.CtorForeignCast 605undefbehavior.CtorForeignTypeid 606<br>(C++)</span><br><br> 607Undefined behavior: the operand of typeid/dynamic_cast is an object under 608construction whose type is neither the constructors own class or one of its 609bases 610</td><td><pre> 611#include <typeinfo> 612 613class A { 614public: 615 virtual void f() {}; 616}; 617 618class B { 619public: 620 B(A* a) { 621 typeid(*a); // warn 622 dynamic_cast<B*>(a); //warn 623 } 624}; 625 626class C : public A, B { 627public: 628 C() : B((A*)this) {} 629}; 630</pre></td><td class="aligned"></td></tr> 631 632<tr><td><span class="name">undefbehavior.MemberRefInCatch 633undefbehavior.BaseRefInCatch 634<br>(C++)</span><br><br> 635Undefined behavior: referring to any non-static member or base class of an 636object in the handler for a function-try-block of a constructor or destructor 637for that object results in undefined behavior 638</td><td><pre> 639class C { 640 int i; 641public : 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> 654Undefined behavior: a function returns when control reaches the end of a 655handler. This results in undefined behavior in a value-returning 656function 657</td><td><pre> 658int test() try { 659} 660catch(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> 666Undefined behavior: if more than one auto_ptr owns the same object at the same 667time the behavior of the program is undefined. 668</td><td><pre> 669#include <memory> 670 671void 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> 680Undefined behavior: out-of-bound basic_string access 681</td><td><pre> 682void 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> 690Undefined behavior: out-of-bound basic_string modification 691</td><td><pre> 692void 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> 700Undefined behavior: the result of operator*() on an end of stream is 701undefined 702</td><td><pre> 703#include <vector> 704 705void 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 713undefbehavior.QsortNonTrivial 714<br>C++</span><br><br> 715C++03: Undefined behavior: the objects in the array passed to qsort are of 716non-POD type<br> 717C++11: Undefined behavior: the objects in the array passed to qsort are of 718non-trivial type 719</td><td><pre> 720// C++03 721#include <cstdlib> 722 723struct non_POD { 724 int i; 725 non_POD(int ii) : i(ii) {} 726}; 727 728non_POD values[] = { non_POD(2), non_POD(1) }; 729 730int compare(const void *a, 731 const void *b) { 732 return ( (*(non_POD*)a).i - 733 (*(non_POD*)b).i ); 734} 735 736void test() { 737 qsort(values, 2, sizeof(non_POD), 738 compare); // warn 739} 740 741// C++11 742#include <cstdlib> 743 744struct S {}; 745 746struct trivial_non_POD : public S { 747 int i; 748}; 749 750struct non_trivial { 751 int i; 752 non_trivial() {} 753}; 754 755trivial_non_POD tnp[2]; 756non_trivial nt[2]; 757 758int compare1(const void *a, 759 const void *b) { 760 return ( (*(trivial_non_POD *)a).i - 761 (*(trivial_non_POD *)b).i ); 762} 763 764int compare2(const void *a, 765 const void *b) { 766 return ( (*(non_trivial *)a).i - 767 (*(non_trivial *)b).i ); 768} 769 770void 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> 780Undefined behavior: copy constructor/assignment operator can throw an exception. 781The effects are undefined if an exception is thrown. 782</td><td><pre> 783struct 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> 800Undefined behavior: the value of the second argument is greater than the number 801of values pointed to by the first argument 802</td><td><pre> 803#include <valarray> 804 805struct S { 806 int i; 807 S(int ii) : i(ii) {}; 808}; 809 810void 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> 818Undefined behavior: valarray operands are of different length 819</td><td><pre> 820// C++03 821#include <valarray> 822 823void 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 837void 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> 851Undefined behavior: calling sum()/min()/max() method of an array having zero 852length, the behavior is undefined 853</td><td><pre> 854#include <valarray> 855 856void 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> 866Undefined behavior: element N is specified more than once in the 867indirection 868</td><td><pre> 869#include <valarray> 870 871void 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 883taken place. basic_ios::init should be call to initialize ios_base 884members 885</td><td><pre> 886#include <ios> 887 888using namespace std; 889template <class T, class Traits = std::char_traits<T>> 890class my_stream1 : public std::basic_ios<T, Traits> { 891}; 892 893template <class T, class Traits = std::char_traits<T>> 894class my_stream2 : public std::basic_ios<T, Traits> { 895 class my_streambuf : public std::basic_streambuf<T, Traits> { 896 }; 897public: 898 my_stream2() { 899 this->init(new my_streambuf); 900 } 901}; 902 903void 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> 913Undefined behavior: ios_base object is used before initialization have taken 914place. basic_ios::init should be call to initialize ios_base members 915</td><td><pre> 916#include <ios> 917 918using namespace std; 919template <class T, class Traits = std::char_traits<T>> 920class my_stream1 : public std::basic_ios<T, Traits> { 921}; 922 923template <class T, class Traits = std::char_traits<T>> 924class my_stream2 : public std::basic_ios<T, Traits> { 925 class my_streambuf : public std::basic_streambuf<T, Traits> { 926 }; 927public: 928 my_stream2() { 929 this->init(new my_streambuf); 930 } 931}; 932 933void 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> 945Undefined behavior: passing -1 to any streambuf/istream/ostream member that 946accepts a value of type traits::pos_type result in undefined behavior 947</td><td><pre> 948#include <fstream> 949 950class my_streambuf : public std::streambuf { 951 void f() { 952 seekpos(-1); // warn 953 } 954}; 955 956void 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> 976Errors because of the order of evaluation of function arguments is undefined 977</td><td><pre> 978void f(int, int); 979 980void 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> 989There are identical sub-expressions to the left and to the right of the 990operator 991</td><td><pre> 992#define A 1 993#define B 1 994 995bool isNan(double d) { 996 return d != d; // ok 997} 998 999int f(); 1000 1001void 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> 1015Possibly a function call should be used instead of a pointer to function 1016</td><td><pre> 1017int f(); 1018 1019void 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> 1026The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a 1027probability of logical error presence 1028</td><td><pre> 1029void 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> 1038Successive assign to a variable 1039</td><td><pre> 1040void 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> 1049Dereferencing of the null pointer might take place. Checking the pointer for 1050null should be performed first 1051</td><td><pre> 1052struct S { 1053 int x; 1054}; 1055 1056S* f(); 1057 1058void 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> 1070Dereferencing of the null pointer might take place. Checking the pointer for 1071null should be performed first 1072</td><td><pre> 1073struct S{bool b;}; 1074 1075S* f(); 1076 1077void 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> 1085The 'else' statement is equivalent to the 'then' statement 1086</td><td><pre> 1087void 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> 1100multiple accessors met for 'class::field' 1101</td><td><pre> 1102class A { 1103 int i; 1104 int j; 1105public: 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> 1115Accessors exist for 'class::field'. Should this field really be public? 1116</td><td><pre> 1117class A { 1118public: 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> 1127Calling 'f' ignoring its return value is of no use (* create the list of known 1128system/library/API functions falling into this category) 1129</td><td><pre> 1130#include <vector> 1131 1132void 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> 1140Possibly wrong variable is used in the loop/cond-expression of the 'for' 1141statement. Did you mean 'proper_variable_name'? 1142</td><td><pre> 1143void 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> 1153Comparing floating point numbers may be not precise 1154</td><td><pre> 1155#include <math.h> 1156 1157void 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> 1166Comparing boolean to a value other then 0 or 1 1167</td><td><pre> 1168void 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> 1178bool value is used at the left/right part of the & (|) operator. Did you mean 1179&& (||) ? 1180</td><td><pre> 1181int f(); 1182 1183void 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> 1191Possible misprint: label found inside the switch() statement. (* did you mean 1192'default'?) 1193</td><td><pre> 1194void 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> 1207The conditions of two subsequent 'if' statements are identical 1208</td><td><pre> 1209void 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> 1220The return expressions of the '?:' operator are identical 1221</td><td><pre> 1222void 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> 1230The second operand of the && operator has no impact on expression result 1231</td><td><pre> 1232void 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> 1240The expression always evaluates to true/false 1241</td><td><pre> 1242void 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> 1252Comparison of unsigned expression 'op expr' is always true/false 1253</td><td><pre> 1254void 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> 1263Comparison operation has higher precedence then assignment. Bool value is 1264assigned to variable of type 'type'. Parenthesis may bee required around an 1265assignment 1266</td><td><pre> 1267int f(); 1268 1269void 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 1283void 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> 1292The object was created but is not being used<br><br> 1293The exception object was created but is not being used. Did you mean 1294'throw std::exception();'? 1295</td><td><pre> 1296#include <exception> 1297 1298struct 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 1307void 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> 1315Pointer to static array is being compared to NULL. May the subscripting is 1316missing 1317</td><td><pre> 1318void 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> 1329Odd implicit conversion from 'type' to 'bool' 1330</td><td><pre> 1331bool 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> 1339Out-of-bound dynamic array access 1340</td><td><pre> 1341#include <stdlib.h> 1342 1343void 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> 1353Buffer copy without checking size of input 1354</td><td><pre> 1355void 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> 1363Integer overflow 1364</td><td><pre> 1365#include <limits.h> 1366 1367int f(int x) { 1368 return INT_MAX+1; // warn 1369} 1370 1371void 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> 1382Unexpected sign extension might take place 1383</td><td><pre> 1384void f(unsigned int i); 1385int g(); 1386 1387unsigned 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> 1406Numeric truncation might take place 1407</td><td><pre> 1408void f(int i); 1409int g(); 1410 1411int 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> 1430The class has dynamically allocated data members but do not define a copy 1431constructor/assignment operator 1432</td><td><pre> 1433class C { // warn 1434 int *p; // <- 1435public: 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> 1451After 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 1456void 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> 1468Calling LoadLibrary without a fully qualified path may allow to load a DLL from 1469arbitrary location 1470</td><td><pre> 1471#include <windows.h> 1472 1473void 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> 1480Buffer overrun while calling WideCharToMultiByte 1481</td><td><pre> 1482#include <windows.h> 1483 1484void 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> 1511Optimization: It is more effective to pass const n-th parameter by reference to 1512avoid unnecessary object copying 1513</td><td><pre> 1514struct A { 1515 int a[20]; 1516 int b; 1517}; 1518 1519bool 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> 1526Optimization: It is more effective to use prefix ++ with iterator here 1527</td><td><pre> 1528#include <vector> 1529 1530void 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> 1540Optimization: multiple calls to strlen for a given string in the given 1541expression. It is more effective to hold strlen result in a temporary 1542variable 1543</td><td><pre> 1544#include <string.h> 1545 1546void 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> 1555Optimization: it is more efficient to use "str[0] != '\0'" to identify an empty 1556string 1557</td><td><pre> 1558#include <string.h> 1559 1560void 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> 1568Optimization: it is more efficient to use string::length() method to calculate 1569string length 1570</td><td><pre> 1571#include <string> 1572#include <string.h> 1573 1574void 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> 1582Optimization: It is more efficient to use container.empty() to identify an 1583empty container 1584</td><td><pre> 1585#include <list> 1586 1587void 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