diff options
-rw-r--r-- | www/analyzer/content.css | 32 | ||||
-rw-r--r-- | www/analyzer/potential_checkers.html | 1645 |
2 files changed, 1677 insertions, 0 deletions
diff --git a/www/analyzer/content.css b/www/analyzer/content.css index ea75fbabd1..c2fa294d79 100644 --- a/www/analyzer/content.css +++ b/www/analyzer/content.css @@ -63,6 +63,38 @@ table.options td { border-bottom: 1px #cccccc dotted } table.options td { padding:5px; padding-left:8px; padding-right:8px } table.options td { text-align:left; font-size:9pt } +table.checkers { + border: 1px #cccccc solid; + border-collapse: collapse; + margin:0px; margin-top:20px; margin-bottom:20px; + text-align:left; + table-layout: fixed; + width: 100%; + word-wrap :break-word; + font-size: 100%; +} + +table.checkers thead { + background-color:#eee; color:#666666; + border-top: 2px solid #cccccc; + border-bottom: 2px solid #cccccc; + font-weight: bold; font-family: Verdana; +} + +table.checkers td { + padding:5px; padding-left:8px; padding-right:8px; + border-right: 1px #cccccc dotted; + border-bottom: 1px #cccccc dotted; +} + +table.checkers col.namedescr { width: 45% } +table.checkers col.example { width: 55% } +table.checkers col.progress { width: 84px } +table.checkers pre { margin:1px; font-size: 100%; word-wrap :break-word; } +table.checkers .name { font-weight:bold; } +table.checkers .checked { background-color:#81F781; } +table.checkers .commented { color:#909090; } + /* Collapsing Trees: http://dbtree.megalingo.com/web/demo/simple-collapsible-tree.cfm */ #collapsetree, #collapsetree a:link, #collapsetree li a:link, #collapsetree a:visited, #collapsetree li a:visited{color:#000;text-decoration:none} #collapsetree,#collapsetree ul{list-style-type:none; width:auto; margin:0; padding:0} diff --git a/www/analyzer/potential_checkers.html b/www/analyzer/potential_checkers.html new file mode 100644 index 0000000000..3da3c66f52 --- /dev/null +++ b/www/analyzer/potential_checkers.html @@ -0,0 +1,1645 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> + <title>List of potential checkers</title> + <link type="text/css" rel="stylesheet" href="content.css"> + <link type="text/css" rel="stylesheet" href="menu.css"> + <script type="text/javascript" src="scripts/menu.js"></script> + <script type="text/javascript" src="scripts/dbtree.js"></script> +</head> +<body> + +<div id="page"> + +<!-- menu --> +<!--#include virtual="menu.html.incl"--> +<!-- page content --> +<div id="content"> +<h1>List of potential checkers</h1> + +<!---------------------------- allocation/deallocation --------------------------> +<h3>allocation/deallocation</h3> +<table class="checkers"> +<col class="namedescr"><col class="example"><col class="progress"> +<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> + +<tr><td><span class="name">memory.LeakNeverReleased<br> +(C, C++)</span><br><br> +Memory may be never released, potential leak of memory +</td><td> +<pre> +#include <stdlib.h> + +int f() {}; + +void test() { + int *p1 = (int*)malloc(sizeof(int)); // warn + int *p2 = new int; // warn + int x = f(); + if (x==1) + return; + delete p2; +} +</pre></td><td></td></tr> + +<tr><td><span class="name">memory.MismatchedFree +<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> +Mismatched deallocation function is used +</td><td><pre> +#include <stdlib.h> + +void test() { + int *p1 = new int; + int *p2 = new int[1]; + + free(p1); // warn + free(p2); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">memory.MismatchedDelete +<br>(C, C++)</span><br><br> +Mismatched deallocation function is used +</td><td><pre> +#include <stdlib.h> + +void test() { + int *p1 = new int; + int *p2 = new int[1]; + int *p3 = (int*)malloc(sizeof(int)); + + delete[] p1; // warn + delete p2; // warn + delete p3; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">memory.MultipleDelete +<br>(C++)</span><br><br> +Attempt to deallocate released memory +</td><td><pre> +#include <new> + +void test() { + int *p1 = new int; + int *p2 = new(p1) int; + int *p3 = p1; + delete p1; + delete p1; // warn + delete p2; // warn + delete p3; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">memory.LeakPtrValChanged +<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> +Potential memory leak: a pointer to newly allocated data loses its original +value +</td><td><pre> +#include <stdlib.h> + +void f(const int *); +void g(int *); + +void test() { + int *p1 = new int; + p1++; // warn + int *p2 = (int *)malloc(sizeof(int)); + p2 = p1; // warn + int *p3 = new int; + f(p3); + p3++; // warn + int *p4 = new int; + f(p4); + p4++; // ok +} +</pre></td><td></td></tr> + +<tr><td><span class="name">memory.DeallocateNonPtr +<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> +Deallocation function is applied to non-pointer +</td><td><pre> +#include <stdlib.h> + +class A { + int *p; +public: + operator int *() { return p; } +}; + +void test() { + A a; + delete a; // warn + free(a); // warn + const char *s = "text"; + delete s; // warn + free(s); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">memory.LeakEvalOrder<br> +(C, C++)</span><br><br> +Potential memory leak: argument evaluation order is undefined, g() may never be called +</td><td><pre> +#include <stdlib.h> + +void f1(int, int); +void f2(int*, int*); +int g(int *) { throw 1; }; +int h(); + +void test() { + f1(g(new int), h()); // warn + f1(g((int *)malloc(sizeof(int))), h()); // warn + f2(new int, new int); +} +</pre></td><td></td></tr> + +<tr><td><span class="name">memory.DstBufferTooSmall +<br>(C, C++)</span><br><br> +Destination buffer too small +</td><td><pre> +#include <string.h> + +void test() { + const char* s1 = "abc"; + char *s2 = new char; + strcpy(s2, s1); // warn + + int* p1 = new int[3]; + int* p2 = new int; + memcpy(p2, p1, 3); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">memory.NegativeArraySize +<br>enhancement to experimental.security.MallocOverflow<br>(C, C++) +</span><br><br> +‘n’ is used to specify the buffer size may be negative +</td><td><pre> +#include <stdlib.h> + +void test() { + int *p; + int n1 = -1; + p = new int[n1]; // warn +} +</pre></td><td></td></tr> + +</table> + +<!-------------------------- constructors/destructors -------------------------> +<h3>constructors/destructors</h3> +<table class="checkers"> +<col class="namedescr"><col class="example"><col class="progress"> +<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> + +<tr><td><span class="name">ctordtor.ExptInsideDtorExplicit<br> +(C++)</span><br><br> +It is dangerous to let an exception leave a destructor. Using try..catch will +solve the problem. +</td><td><pre> +void f(); + +class A { + A() {} + ~A() { throw 1; } // warn +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">ctordtor.ExptInsideDtorImplicit<br> +(C++)</span><br><br> +Calls to functions inside a destructor that are known to throw exceptions is +dangerous. Using try..catch will solve the problem. +</td><td><pre> +void f() { throw 1; }; + +class A { + A() {} + ~A() { f(); } // warn +}; +</pre></td><td></td></tr> + +</table> + +<!--------------------------------- exceptions --------------------------------> +<h3>exceptions</h3> +<table class="checkers"> +<col class="namedescr"><col class="example"><col class="progress"> +<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> + +<tr><td><span class="name">exceptions.ThrowSpecButNotThrow +<br>(C++)</span><br><br> +Function prototype has throw(T) specifier but the function do not throw +</td><td><pre> +void f() throw(int) { // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">exceptions.NoThrowSpecButThrows +<br>(C++)</span><br><br> +An exception is throw from a function having the throw() specifier +</td><td><pre> +void f() throw() { + throw(1); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">exceptions.ThrownTypeDiffersSpec +<br>(C++)</span><br><br> +The type of a thrown exception differs from those specified in the throw(T) +specifier +</td><td><pre> +struct S{}; +void f() throw(int) { + S s; + throw (s); // warn +} +</pre></td><td></td></tr> + +</table> + +<!---------------------------- smart pointers ---------------------------------> +<h3>smart pointers</h3> +<table class="checkers"> +<col class="namedescr"><col class="example"><col class="progress"> +<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> + +<tr><td><span class="name">smartptr.AutoPtrInit<br> +(C++03)</span><br><br> +auto_ptr should store a pointer to an object obtained via new as allocated +memory will be cleaned using delete +</td><td><pre> +#include <stdlib.h> +#include <memory> + +void test() { + std::auto_ptr<int> p1(new int); // Ok + std::auto_ptr<int> p2(new int[3]); // warn + std::auto_ptr<int> + p3((int *)malloc(sizeof(int))); // warn +} +</pre></td><td></td></tr> + +</table> + +<!---------------------------- undefined behavior -----------------------------> +<h3>undefined behavior</h3> +<table class="checkers"> +<col class="namedescr"><col class="example"><col class="progress"> +<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> + +<tr><td><span class="name">undefbehavior.ExitInDtor +<br>(C++)</span><br><br> +Undefined behavior: std::exit is called to end the program during the +destruction of an object with static storage duration +</td><td><pre> +#include <cstdlib> + +class A { +public: + ~A() { + std::exit(1); // warn + } +}; + +A a; +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.LocalStaticDestroyed +<br>(C++)</span><br><br> +Undefined behavior: function containing a definition of static local object is +called during the destruction of an object with static storage duration so that +flow of control passes through the definition of the previously destroyed +static local object +</td><td><pre> +void f(); + +class A { +public: + ~A() { + f(); // warn + } +}; + +class B {}; + +A a; + +void f() { + static B b; // <- +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.UseAfterRelease +<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> +Pointer to deleted object is referenced (The effect of using an invalid pointer +value is undefined) +</td><td><pre> +#include <stdlib.h> + +void test() { + int *p = new int; + delete p; + int i = *p; // warn +} + +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ZeroAllocDereference +<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br> +The effect of dereferencing a pointer returned as a request for zero size is +undefined +</td><td><pre> +#include <stdlib.h> + +int *p = new int[0]; +int i = p[0]; // warn +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.DeadReferenced +<br>(C++)</span><br><br> +Undefined behavior: the following usage of the pointer to the object whose +lifetime has ended can result in undefined behavior +</td><td><pre> +// C++03 +#include <new> + +class A { +public: + int i; + void f() {}; +}; + +class B : public A { +}; + +void test() { + B *b = new B; + new(b) A; + b->i; // warn + b->f(); // warn + static_cast<A*>(b); // warn + dynamic_cast<A*>(b); // warn + delete b; // warn +} + +// C++11 +#include <new> + +class A { +public: + int i; + void f() {}; +}; + +class B : public A { +public: + ~B() {}; +}; + +void test() { + A *a = new A; + new(a) B; + a->i; // warn + a->f(); // warn + B *b = new B; + new(b) A; + b->i; // warn + b->f(); // warn + static_cast<A*>(b); // warn + dynamic_cast<A*>(b); // warn + delete b; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ObjLocChanges +<br>(C++)</span><br><br> +Undefined behavior: the program must ensure that an object occupies the same +storage location when the implicit or explicit destructor call takes place +</td><td><pre> +#include <new> + +class T { }; +struct B { + ~B(); +}; + +void test() { + B *b1 = new B; + B b2; + new (b1) T; + new (&b2) T; + delete b1; // warn +} // warn +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ExprEvalOrderUndef +<br>(C, C++03)</span><br><br> +Undefined behavior: a scalar object shall have its stored value modified at +most once by the evaluation of an expression +</td><td><pre> +void test () { + int i = 0; + int v[1] = {0}; + i = v[i++]; // warn + i = ++i + 1; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.StaticInitReentered +<br>(C)</span><br><br> +Undefined behavior: static declaration is re-entered while the object is being +initialized +</td><td><pre> +int test(int i) { + static int s = test(2*i); // warn + return i+1; +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ConstModified +<br>(C, C++)</span><br><br> +Undefined behavior: const object is being modified +</td><td><pre> +#include <stdlib.h> + +class X { +public : + mutable int i; + int j; +}; +class Y { +public : + X x; + Y(); +}; + +void test() { + const int *ciq = + (int *)malloc(sizeof(int)); + int *iq = const_cast<int *>(ciq); + *iq = 1; // warn + + const Y y; + Y* p = const_cast<Y*>(&y); + p->x.i = 1; // ok + p->x.j = 1; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.DeadDestructed +<br>(C++)</span><br><br> +Undefined behavior: the destructor is invoked for an object whose lifetime +has ended +</td><td><pre> +class A { +public: + void f() {}; + A() {}; + ~A() {}; +}; + +void test() { + A a; + a.~A(); +} // warn +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.MethodCallBeforeBaseInit +<br>(C++)</span><br><br> +Undefined behavior: calls member function but base not yet initialized +</td><td><pre> +class A { +public : + A(int ); +}; +class B : public A { +public : + int f(); + B() : A(f()) {} // warn +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.MemberOrBaseRefBeforeCtor +<br>(C++)</span><br><br> +C++ Undefined behavior: non-static member or base class of non-POD class type +is referred before constructor begins execution<br> +C++11 Undefined behavior: non-static member or base class of a class with a +non-trivial constructor is referred before constructor begins execution +</td><td><pre> +// C++03 +struct POD { + int i; +}; + +struct non_POD : public POD { + int j; + POD pod; +}; + +extern POD pod; +extern non_POD non_pod; + +int *p1 = &non_pod.j; // warn +int *p2 = &non_pod.pod.i; // warn +int *p3 = &pod.i; // ok +POD *p4 = & non_pod; // warn + +POD a; +non_POD b; + +struct S { + int *k; + non_POD non_pod; + S() : k(&non_pod.j) {} // warn +}; + +// C++11 +struct trivial { + int i; +}; + +struct non_trivial: public trivial { + non_trivial() {}; + int j; + trivial pod; +}; + +extern trivial t; +extern non_trivial nt; + +int *p1 = &nt.j; // warn +int *p2 = &nt.i; // warn +int *p3 = &t.i; // ok +trivial *p4 = &nt; + +trivial t; +non_trivial nt; + +struct S { + int *k; + non_trivial nt; + S() : k(&nt.j) {} // warn +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.MemberRefAfterDtor +<br>(C++)</span><br><br> +C++03: Undefined behavior: non-static member of non-POD class type is referred +after destructor ends execution<br> +C++11: Undefined behavior: non-static member of a class with a non-trivial +destructor is referred after destructor ends execution +</td><td><pre> +// C++03 +struct non_POD { + virtual void f() {}; +}; + +void test() { + non_POD *non_pod = new non_POD(); + non_pod->~non_POD(); + non_pod->f(); // warn +} + +// C++11 +struct S { + ~S() {}; + void f() {}; +}; + +void test() { + S *s = new S(); + s->~S(); + s->f(); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.CtorForeignCall +<br>(C++)</span><br><br> +Undefined behavior: call to virtual function of an object under construction +whose type is neither the constructors own class or one of its bases +</td><td><pre> +class A { +public: + virtual void f() {}; +}; + +class B { +public: + B(A* a) { a->f(); } // warn +}; + +class C : public A, B { +public: + C() : B((A*)this) {} +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.CtorForeignCast +undefbehavior.CtorForeignTypeid +<br>(C++)</span><br><br> +Undefined behavior: the operand of typeid/dynamic_cast is an object under +construction whose type is neither the constructors own class or one of its +bases +</td><td><pre> +#include <typeinfo> + +class A { +public: + virtual void f() {}; +}; + +class B { +public: + B(A* a) { + typeid(*a); // warn + dynamic_cast<B*>(a); //warn + } +}; + +class C : public A, B { +public: + C() : B((A*)this) {} +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.MemberRefInCatch +undefbehavior.BaseRefInCatch +<br>(C++)</span><br><br> +Undefined behavior: referring to any non-static member or base class of an +object in the handler for a function-try-block of a constructor or destructor +for that object results in undefined behavior +</td><td><pre> +class C { + int i; +public : + C() + try + : i(1) {} + catch (...) + { + i=2; // warn + } +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ReturnAtCatchEnd +<br>(C++)</span><br><br> +Undefined behavior: a function returns when control reaches the end of a +handler. This results in undefined behavior in a value-returning +function +</td><td><pre> +int test() try { +} +catch(int) { +} // warn +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.AutoptrsOwnSameObj +<br>(C++03)</span><br><br> +Undefined behavior: if more than one auto_ptr owns the same object at the same +time the behavior of the program is undefined. +</td><td><pre> +#include <memory> + +void test() { + int *data = new int; + std::auto_ptr<int> p(data); + std::auto_ptr<int> q(data); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.BasicStringBoundAccess +<br>(C++03)</span><br><br> +Undefined behavior: out-of-bound basic_string access +</td><td><pre> +void test() { + std::basic_string<char> s; + char c = s[10]; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.BasicStringBoundModification +<br>(C++)</span><br><br> +Undefined behavior: out-of-bound basic_string modification +</td><td><pre> +void test() { + std::basic_string<char> s; + s[10] = 0; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.EosDereference +<br>(C++)</span><br><br> +Undefined behavior: the result of operator*() on an end of stream is +undefined +</td><td><pre> +#include <vector> + +void test() { + std::vector<int> v; + int i = *v.end(); // warn + *v.end() = 0; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.QsortNonPOD +undefbehavior.QsortNonTrivial +<br>C++</span><br><br> +C++03: Undefined behavior: the objects in the array passed to qsort are of +non-POD type<br> +C++11: Undefined behavior: the objects in the array passed to qsort are of +non-trivial type +</td><td><pre> +// C++03 +#include <cstdlib> + +struct non_POD { + int i; + non_POD(int ii) : i(ii) {} +}; + +non_POD values[] = { non_POD(2), non_POD(1) }; + +int compare(const void *a, + const void *b) { + return ( (*(non_POD*)a).i - + (*(non_POD*)b).i ); +} + +void test() { + qsort(values, 2, sizeof(non_POD), + compare); // warn +} + +// C++11 +#include <cstdlib> + +struct S {}; + +struct trivial_non_POD : public S { + int i; +}; + +struct non_trivial { + int i; + non_trivial() {} +}; + +trivial_non_POD tnp[2]; +non_trivial nt[2]; + +int compare1(const void *a, + const void *b) { + return ( (*(trivial_non_POD *)a).i - + (*(trivial_non_POD *)b).i ); +} + +int compare2(const void *a, + const void *b) { + return ( (*(non_trivial *)a).i - + (*(non_trivial *)b).i ); +} + +void test() { + qsort(tnp, 2, sizeof(trivial_non_POD), + compare1); // ok + qsort(nt, 2, sizeof(non_trivial), + compare2); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ThrowWhileCopy +<br>C++</span><br><br> +Undefined behavior: copy constructor/assignment operator can throw an exception. +The effects are undefined if an exception is thrown. +</td><td><pre> +struct S { + int i, j; + S (const S &s) { + i = s.i; + throw 1; // warn + j = s.j; + }; + S& operator=(const S &s) { + i = s.i; + throw 1; // warn + j = s.j; + } +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ValarrayArgBound +<br>(C++)</span><br><br> +Undefined behavior: the value of the second argument is greater than the number +of values pointed to by the first argument +</td><td><pre> +#include <valarray> + +struct S { + int i; + S(int ii) : i(ii) {}; +}; + +void test(void) { + S s[] = { S(1), S(2) }; + std::valarray<S> v(s,3); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ValarrayLengthDiffer +<br>(C++)</span><br><br> +Undefined behavior: valarray operands are of different length +</td><td><pre> +// C++03 +#include <valarray> + +void test(void) { + std::valarray<int> a(0, 1), b(0, 2); + std::valarray<bool> c(false, 1); + a = b; // warn + a *= b; // warn + a = a * b; // warn + c = a == b; // warn + b.resize(1); + a = b; // OK +} + +// C++11 +#include <valarray> + +void test(void) { + std::valarray<int> a(0, 1), b(0, 2); + std::valarray<bool> c(false, 1); + a = b; // ok + a *= b; // ok + a = a * b; // warn + c = a == b; // warn + b.resize(1); + a = b; // OK +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ValarrayZeroLength +<br>(C++)</span><br><br> +Undefined behavior: calling sum()/min()/max() method of an array having zero +length, the behavior is undefined +</td><td><pre> +#include <valarray> + +void test(void) { + std::valarray<int> v(0, 0); + v.sum(); // warn + v.min(); // warn + v.max(); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.ValarrayBadIndirection +<br>(C++)</span><br><br> +Undefined behavior: element N is specified more than once in the +indirection +</td><td><pre> +#include <valarray> + +void test() { + size_t addr[] = {0, 1, 1}; // N is 1 + std::valarray<size_t>indirect(addr, 3); + std::valarray<int> a(0, 5), b(1, 3); + a[indirect] = b; //warn + a[indirect] *= b; //warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.IosBaseDestroyedBeforeInit +<br>(C++)</span><br> +<br>Undefined behavior: ios_base object is destroyed before initialization have +taken place. basic_ios::init should be call to initialize ios_base +members +</td><td><pre> +#include <ios> + +using namespace std; +template <class T, class Traits = std::char_traits<T>> +class my_stream1 : public std::basic_ios<T, Traits> { +}; + +template <class T, class Traits = std::char_traits<T>> +class my_stream2 : public std::basic_ios<T, Traits> { + class my_streambuf : public std::basic_streambuf<T, Traits> { + }; +public: + my_stream2() { + this->init(new my_streambuf); + } +}; + +void test() { + my_stream1<char> *p1 = new my_stream1<char> + my_stream2<char> *p2 = new my_stream2<char> + delete p1; // warn + delete p2; // ok +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.IosBaseUsedBeforeInit +<br>(C++11)</span><br><br> +Undefined behavior: ios_base object is used before initialization have taken +place. basic_ios::init should be call to initialize ios_base members +</td><td><pre> +#include <ios> + +using namespace std; +template <class T, class Traits = std::char_traits<T>> +class my_stream1 : public std::basic_ios<T, Traits> { +}; + +template <class T, class Traits = std::char_traits<T>> +class my_stream2 : public std::basic_ios<T, Traits> { + class my_streambuf : public std::basic_streambuf<T, Traits> { + }; +public: + my_stream2() { + this->init(new my_streambuf); + } +}; + +void test() { + my_stream1<char> *p1 = new my_stream1<char> + my_stream2<char> *p2 = new my_stream2<char> + p1->narrow('a', 'b'); // warn + p2->narrow('a', 'b'); // ok + delete p1; // warn + delete p2; // ok +} +</pre></td><td></td></tr> + +<tr><td><span class="name">undefbehavior.MinusOnePosType +<br>(C++)</span><br><br> +Undefined behavior: passing -1 to any streambuf/istream/ostream member that +accepts a value of type traits::pos_type result in undefined behavior +</td><td><pre> +#include <fstream> + +class my_streambuf : public std::streambuf { + void f() { + seekpos(-1); // warn + } +}; + +void test() { + std::filebuf fb; + std::istream in(&fb); + std::ostream out(&fb); + std::filebuf::off_type pos(-1); + in.seekg(pos); // warn + out.seekp(-1); // warn +} +</pre></td><td></td></tr> +</table> + +<!------------------------------- different -----------------------------------> +<h3>different</h3> +<table class="checkers"> +<col class="namedescr"><col class="example"><col class="progress"> +<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr> +</thead> + +<tr><td><span class="name">different.ArgEvalOrderUndef +<br>(C)</span><br><br> +Errors because of the order of evaluation of function arguments is undefined +</td><td><pre> +void f(int, int); + +void test() { + int i = 0; + int v[1] = {0}; + f(v[i], i++); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.IdenticalExprBinOp +<br>(C)</span><br><br> +There are identical sub-expressions to the left and to the right of the +operator +</td><td><pre> +#define A 1 +#define B 1 + +bool isNan(double d) { + return d != d; // ok +} + +int f(); + +void test() { + int i = 0; + if (i != 0 && i != 0) {} // warn + + if(i == A || i == B) {} // ok + + if (++i != 0 && ++i != 0) {} // ok + + if (f() && f()) {} // ok +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.FuncPtrInsteadOfCall +<br>(C)</span><br><br> +Possibly a function call should be used instead of a pointer to function +</td><td><pre> +int f(); + +void test() { + if (f == 0) {} // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.IdenticalCondIfElseIf +<br>(C)</span><br><br> +The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a +probability of logical error presence +</td><td><pre> +void test() { + int i = 7; + if (i == 1) {} + else if (i == 1) {} // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">SuccessiveAssign +<br>(C)</span><br><br> +Successive assign to a variable +</td><td><pre> +void test() { + int i=0; + i=1; + i=2; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.NullDerefStmtOrder +<br>enhancement to core.NullDereference<br>(C)</span><br><br> +Dereferencing of the null pointer might take place. Checking the pointer for +null should be performed first +</td><td><pre> +struct S { + int x; +}; + +S* f(); + +void test() { + S *p1 = f(); + int x1 = p1->x; // warn + if (p1) {}; + + S *p2 = f(); + int x2 = p2->x; // ok +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.NullDerefCondOrder +<br>enhancement to core.NullDereference<br>(C)</span><br><br> +Dereferencing of the null pointer might take place. Checking the pointer for +null should be performed first +</td><td><pre> +struct S{bool b;}; + +S* f(); + +void test() { + S *p = f(); + if (p->b && p) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.IdenticalStmtThenElse +<br>(C)</span><br><br> +The 'else' statement is equivalent to the 'then' statement +</td><td><pre> +void test() { + int i; + if (i==1) { + i++; + } + else { // warn + i++; + } +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.MultipleAccessors +<br>(C++)</span><br><br> +multiple accessors met for 'class::field' +</td><td><pre> +class A { + int i; + int j; +public: + int getI() { return i; } + int getJ() { return i; } // warn + void setI(int& ii) { i = ii; } + void setJ(int& jj) { i = jj; } // warn +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">different.AccessorsForPublic +<br>(C++)</span><br><br> +Accessors exist for 'class::field'. Should this field really be public? +</td><td><pre> +class A { +public: + int i; // warn + int getI() { return i; } + void setI(int& ii) { i = ii; } +}; +</pre></td><td></td></tr> + +<tr><td><span class="name">different.LibFuncResultUnised +<br>(C, C++)</span><br><br> +Calling 'f' ignoring its return value is of no use (* create the list of known +system/library/API functions falling into this category) +</td><td><pre> +#include <vector> + +void test() { + std::vector<int> v; + v.empty(); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.WrongVarForStmt +<br>(C, C++)</span><br><br> +Possibly wrong variable is used in the loop/cond-expression of the ‘for’ +statement. Did you mean ‘proper_variable_name’? +</td><td><pre> +void test() { + int i; + int j; + for (j=0; j<3; ++i); // warn + for (int j=0; i<3; ++j); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.FloatingCompare +<br>(C)</span><br><br> +Comparing floating point numbers may be not precise +</td><td><pre> +#include <math.h> + +void test() { + double b = sin(M_PI / 6.0); + if (b == 0.5) // warn + b = 0; +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.BoolCompare +<br>maybe merge with experimental.core.BoolAssignment<br>(C, C++)</span><br><br> +Comparing boolean to a value other then 0 or 1 +</td><td><pre> +void test() { + int i; + if (0 < i < 3) {}; // warn + bool b; + if (b == 3) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.BitwiseOpBoolArg +<br>maybe join with experimental.core.BoolAssignment<br>(C, C++)</span><br><br> +bool value is used at the left/right part of the & (|) operator. Did you mean +&& (||) ? +</td><td><pre> +int f(); + +void test() { + bool b = true; + if (b & f()) {} // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.LabelInsideSwitch +<br>(C)</span><br><br> +Possible misprint: label found inside the switch() statement. (* did you mean +‘default’?) +</td><td><pre> +void test() { + int c = 7; + switch(c){ + case 1: + c += 1; break; + defalt: // warn + c -= 1; break; + } +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.IdenticalCondIfIf +<br>(C)</span><br><br> +The conditions of two subsequent ‘if’ statements are identical +</td><td><pre> +void test() { + int c = 7; + if (c > 5) // <- + c += 1; + if (c > 5) // warn + c -= 1; +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.CondOpIdenticalReturn +<br>(C)</span><br><br> +The return expressions of the ‘?:’ operator are identical +</td><td><pre> +void test() { + unsigned a; + a = a > 5 ? a : a; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.UnaryPlusWithUnsigned +<br>(C)</span><br><br> +Using ‘unary +’ with unsigned is meaningless +</td><td><pre> +void test() { + unsigned a; + a = +a; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.LogicalOpUselessArg +<br>(C)</span><br><br> +The second operand of the && operator has no impact on expression result +</td><td><pre> +void test() { + unsigned a; + if (a<7 && a<10) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.SameResLogicalExpr +<br>(C)</span><br><br> +The expression always evaluates to true/false +</td><td><pre> +void test() { + int i=0; + if (i!=0) {}; // warn + if (i==0 && i==1) {}; // warn + if (i<0 || i>=0) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.SameResUnsignedCmp +<br>(C)</span><br><br> +Comparison of unsigned expression ‘op expr’ is always true/false +</td><td><pre> +void test() { + unsigned u; + if (u < -1) {}; // warn + if (u >= 0) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.OpPrecedenceAssignCmp +<br>(C)</span><br><br> +Comparison operation has higher precedence then assignment. Bool value is +assigned to variable of type ‘type’. Parenthesis may bee required around an +assignment +</td><td><pre> +int f(); + +void test() { + bool b; + int x, y; + if((b = x != y)) {} // ok + if((x = f() != y)) {} // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.OpPrecedenceIifShift +<br>(C)</span><br><br> +?: has lower precedence then << +</td><td><pre> +#include <iostream> + +void test() { + int a; + std::cout << a ? "a" : "b"; // warn + a << a>7 ? 1 : 2; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.ObjectUnused +<br>(C++)</span><br><br> +The object was created but is not being used<br><br> +The exception object was created but is not being used. Did you mean +‘throw std::exception();’ ? +</td><td><pre> +#include <exception> + +struct S { + int x, y; + S(int xx, int yy) : x(xx), y(yy) { + } + S(int xx) { + S(xx, 0); // warn + } +}; + +void test() { + S(0, 0); // warn + std::exception(); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.StaticArrayPtrCompare +<br>(C)</span><br><br> +Pointer to static array is being compared to NULL. May the subscripting is +missing +</td><td><pre> +void test() { + int a1[1]; + if (a1 == 0) {}; // warn + + int a2[1][1]; + if (a2[0]) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.ConversionToBool +<br>maybe join with experimental.core.BoolAssignment<br>(C, C++)</span><br><br> +Odd implicit conversion from ‘type’ to ‘bool’ +</td><td><pre> +bool test() { + return 1.; // warn + return ""; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.ArrayBound +<br>enhancement to experimental.security.ArrayBound[v2]<br>(C, C++)</span><br><br> +Out-of-bound dynamic array access +</td><td><pre> +#include <stdlib.h> + +void test() { + int *p2 = new int[1]; + if(p2[1]) {}; // warn + int i = 1; + if(p2[i]) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.StrcpyInputSize +<BR>enhancement to experimental.unix.cstring.OutOfBounds<br>(C)</span><br><br> +Buffer copy without checking size of input +</td><td><pre> +void test(char* string) { + char buf[24]; + strcpy(buf, string); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.IntegerOverflow +<br>(C)</span><br><br> +Integer overflow +</td><td><pre> +#include <limits.h> + +int f(int x) { + return INT_MAX+1; // warn +} + +void test() { + int x = INT_MAX+1; // warn + f(INT_MAX+1); // warn + + int y = INT_MAX/2+1; // warn + x = y*2; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.SignExtension +<br>(C)</span><br><br> +Unexpected sign extension might take place +</td><td><pre> +void f(unsigned int i); +int g(); + +unsigned int test() { + long long sll; + unsigned long long ull = sll; // warn + long sl; + unsigned long ul = sl; // warn + int si; + unsigned int ui = si; // warn + short ss; + unsigned short us = ss; // warn + signed char sc; + unsigned char uc = sc; // warn + f(si); // warn + ui = g(); // warn + return si; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.NumericTruncation +<br>(C)</span><br><br> +Numeric truncation might take place +</td><td><pre> +void f(int i); +int g(); + +int test() { + unsigned long long ull; + long long sll; + unsigned long ul = ull; // warn + long sl = sll; // warn + unsigned int ui = ul; // warn + int si = sl; // warn + unsigned short us = ui; // warn + short ss = si; // warn + unsigned char uc = us; // warn + signed char sc = uc; // warn + f(sll); // warn + ss = g(); // warn + return sll; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">different.MissingCopyCtorAssignOp +<br>(C, C++)</span><br><br> +The class has dynamically allocated data members but do not define a copy +constructor/assignment operator +</td><td><pre> +class C { // warn + int *p; // <- +public: + C() { p = new int; } + ~C() { delete p; } +}; +</pre></td><td></td></tr> + +</table> + +<!------------------------------- WinAPI --------------------------------------> +<h3>WinAPI</h3> +<table class="checkers"> +<col class="namedescr"><col class="example"><col class="progress"> +<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> + +<tr><td><span class="name">WinAPI.CreateProcess +<br>(C)</span><br><br> +After calling CreateProcess(), ensure that process and thread handles get closed +(* for the given example: examine data flow from pi, pi.hProcess and pi.hThread) +</td><td><pre> +#include <windows.h> + +void test() { + STARTUPINFO si; + PROCESS_INFORMATION pi; + BOOL fSuccess; + fSuccess = CreateProcess( + NULL, TEXT("MyProgram.exe"), NULL, NULL, + TRUE, 0, NULL, NULL, &si, &pi); +} // warn +</pre></td><td></td></tr> + +<tr><td><span class="name">WinAPI.LoadLibrary +<br>(C)</span><br><br> +Calling LoadLibrary without a fully qualified path may allow to load a DLL from +arbitrary location +</td><td><pre> +#include <windows.h> + +void test() { + HINSTANCE h = LoadLibrary("X.dll"); // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">WinAPI.WideCharToMultiByte +<br>(C)</span><br><br> +Buffer overrun while calling WideCharToMultiByte +</td><td><pre> +#include <windows.h> + +void test() +{ + wchar_t ws[] = L"abc"; + char s[3]; + int res1 = WideCharToMultiByte( + CP_UTF8, 0, ws, -1, s, + 3, NULL, NULL); // warn + int res2 = WideCharToMultiByte( + CP_UTF8, 0, ws, -1, s, + 3, NULL, NULL); // ok + if (res2 == sizeof(s)) + s[res2-1] = 0; + else + s[res2] = 0; +} +</pre></td><td></td></tr> + +</table> + +<!------------------------------ optimization ---------------------------------> +<h3>optimization</h3> +<table class="checkers"> +<col class="namedescr"><col class="example"><col class="progress"> +<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead> + +<tr><td><span class="name">optimization.PassConstObjByValue +<br>(C, C++)</span><br><br> +Optimization: It is more effective to pass const n-th parameter by reference to +avoid unnecessary object copying +</td><td><pre> +struct A { + int a[20]; + int b; +}; + +bool FirstIsZero(const struct A a) { // warn + return a.a[0] == 0; +} +</pre></td><td></td></tr> + +<tr><td><span class="name">optimization.PostfixIncIter +<br>(C++)</span><br><br> +Optimization: It is more effective to use prefix ++ with iterator here +</td><td><pre> +#include <vector> + +void test() { + std::vector<int> v; + std::vector<int>::const_iterator it; + for(it = v.begin(); + it != v.end(); it++) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">optimization.MultipleCallsStrlen +<br>(C)</span><br><br> +Optimization: multiple calls to strlen for a given string in the given +expression. It is more effective to hold strlen result in a temporary +variable +</td><td><pre> +#include <string.h> + +void test() { + const char* s = "abc"; + if (strlen(s) > 0 && + strlen(s) < 7) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">optimization.EmptyCstrDetect +<br>(C)</span><br><br> +Optimization: it is more efficient to use “str[0] != ‘\0’” to identify an empty +string +</td><td><pre> +#include <string.h> + +void test() { + const char* s = "abc"; + if (strlen(s) > 0) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">optimization.StrLengthCalculation +<br>(C, C++)</span><br><br> +Optimization: it is more efficient to use string::length() method to calculate +string length +</td><td><pre> +#include <string> +#include <string.h> + +void test() { + std::string s; + if (strlen(s.c_str()) != 0) {}; // warn +} +</pre></td><td></td></tr> + +<tr><td><span class="name">optimization.EmptyContainerDetect +<br>(C, C++)</span><br><br> +Optimization: It is more efficient to use container.empty() to identify an +empty container +</td><td><pre> +#include <list> + +void test() { + std::list<int> l; + if (l.size() != 0) {}; // warn +} +</pre></td><td></td></tr> + +</table> + +<br> +</div> <!-- page --> +</div> <!-- content --> +</body> +</html> |