From: Ted Kremenek Date: Sat, 6 Oct 2012 05:09:43 +0000 (+0000) Subject: Add list of potential checkers. Provided by Anton Yartsev! X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=41c1c717cf7de6f8f54f6504fe2f6556e9184d0b;p=clang Add list of potential checkers. Provided by Anton Yartsev! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165359 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 @@ + + + + List of potential checkers + + + + + + + +
+ + + + +
+

List of potential checkers

+ + +

allocation/deallocation

+ ++ + + + + + + + + + + + + + + + + + + + +
Name, DescriptionExampleProgress
memory.LeakNeverReleased
+(C, C++)


+Memory may be never released, potential leak of memory +
+
+#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;
+}
+
memory.MismatchedFree +
enhancement to unix.Malloc
(C, C++)


+Mismatched deallocation function is used +
+#include <stdlib.h>
+
+void test() {
+  int *p1 = new int;
+  int *p2 = new int[1];
+
+  free(p1); // warn
+  free(p2); // warn
+}
+
memory.MismatchedDelete +
(C, C++)


+Mismatched deallocation function is used +
+#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
+}
+
memory.MultipleDelete +
(C++)


+Attempt to deallocate released memory +
+#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
+}
+
memory.LeakPtrValChanged +
enhancement to unix.Malloc
(C, C++)


+Potential memory leak: a pointer to newly allocated data loses its original +value +
+#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
+}
+
memory.DeallocateNonPtr +
enhancement to unix.Malloc
(C, C++)


+Deallocation function is applied to non-pointer +
+#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
+}
+
memory.LeakEvalOrder
+(C, C++)


+Potential memory leak: argument evaluation order is undefined, g() may never be called +
+#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);
+}
+
memory.DstBufferTooSmall +
(C, C++)


+Destination buffer too small +
+#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
+}
+
memory.NegativeArraySize +
enhancement to experimental.security.MallocOverflow
(C, C++) +


+‘n’ is used to specify the buffer size may be negative +
+#include <stdlib.h>
+
+void test() {
+  int *p;
+  int n1 = -1;
+  p = new int[n1]; // warn
+}
+
+ + +

constructors/destructors

+ ++ + + + + + +
Name, DescriptionExampleProgress
ctordtor.ExptInsideDtorExplicit
+(C++)


+It is dangerous to let an exception leave a destructor. Using try..catch will +solve the problem. +
+void f();
+
+class A {
+  A() {}
+  ~A() { throw 1; } // warn
+};
+
ctordtor.ExptInsideDtorImplicit
+(C++)


+Calls to functions inside a destructor that are known to throw exceptions is +dangerous. Using try..catch will solve the problem. +
+void f() { throw 1; };
+
+class A {
+  A() {}
+  ~A() { f(); } // warn
+};
+
+ + +

exceptions

+ ++ + + + + + + + +
Name, DescriptionExampleProgress
exceptions.ThrowSpecButNotThrow +
(C++)


+Function prototype has throw(T) specifier but the function do not throw +
+void f() throw(int) { // warn
+}
+
exceptions.NoThrowSpecButThrows +
(C++)


+An exception is throw from a function having the throw() specifier +
+void f() throw() {
+  throw(1); // warn
+}
+
exceptions.ThrownTypeDiffersSpec +
(C++)


+The type of a thrown exception differs from those specified in the throw(T) +specifier +
+struct S{};
+void f() throw(int) {
+  S s;
+  throw (s); // warn
+}
+
+ + +

smart pointers

+ ++ + + + +
Name, DescriptionExampleProgress
smartptr.AutoPtrInit
+(C++03)


+auto_ptr should store a pointer to an object obtained via new as allocated +memory will be cleaned using delete +
+#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
+}
+
+ + +

undefined behavior

+ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name, DescriptionExampleProgress
undefbehavior.ExitInDtor +
(C++)


+Undefined behavior: std::exit is called to end the program during the +destruction of an object with static storage duration +
+#include <cstdlib>
+
+class A {
+public:
+  ~A() {
+    std::exit(1); // warn
+  }
+};
+
+A a;
+
undefbehavior.LocalStaticDestroyed +
(C++)


+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 +
+void f();
+
+class A {
+public:
+  ~A() {
+    f(); // warn
+  }
+};
+
+class B {};
+
+A a;
+
+void f() {
+  static B b; // <-
+}
+
undefbehavior.UseAfterRelease +
enhancement to unix.Malloc
(C, C++)


+Pointer to deleted object is referenced (The effect of using an invalid pointer +value is undefined) +
+#include <stdlib.h>
+
+void test() {
+  int *p = new int;
+  delete p;
+  int i = *p; // warn
+}
+
+
undefbehavior.ZeroAllocDereference +
enhancement to unix.Malloc
(C, C++)


+The effect of dereferencing a pointer returned as a request for zero size is +undefined +
+#include <stdlib.h>
+
+int *p = new int[0];
+int i = p[0]; // warn
+
undefbehavior.DeadReferenced +
(C++)


+Undefined behavior: the following usage of the pointer to the object whose +lifetime has ended can result in undefined behavior +
+// 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
+}
+
undefbehavior.ObjLocChanges +
(C++)


+Undefined behavior: the program must ensure that an object occupies the same +storage location when the implicit or explicit destructor call takes place +
+#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
+
undefbehavior.ExprEvalOrderUndef +
(C, C++03)


+Undefined behavior: a scalar object shall have its stored value modified at +most once by the evaluation of an expression +
+void test () {
+  int i = 0;
+  int v[1] = {0};
+  i = v[i++]; // warn
+  i = ++i + 1; // warn
+}
+
undefbehavior.StaticInitReentered +
(C)


+Undefined behavior: static declaration is re-entered while the object is being +initialized +
+int test(int i) {
+  static int s = test(2*i); // warn
+  return i+1;
+}
+
undefbehavior.ConstModified +
(C, C++)


+Undefined behavior: const object is being modified +
+#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
+}
+
undefbehavior.DeadDestructed +
(C++)


+Undefined behavior: the destructor is invoked for an object whose lifetime +has ended +
+class A {
+public:
+  void f() {};
+  A() {};
+  ~A() {};
+};
+
+void test() {
+  A a;
+  a.~A();
+} // warn
+
undefbehavior.MethodCallBeforeBaseInit +
(C++)


+Undefined behavior: calls member function but base not yet initialized +
+class A {
+public :
+  A(int );
+};
+class B : public A {
+public :
+  int f();
+  B() : A(f()) {} // warn
+};
+
undefbehavior.MemberOrBaseRefBeforeCtor +
(C++)


+C++ Undefined behavior: non-static member or base class of non-POD class type +is referred before constructor begins execution
+C++11 Undefined behavior: non-static member or base class of a class with a +non-trivial constructor is referred before constructor begins execution +
+// 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
+};
+
undefbehavior.MemberRefAfterDtor +
(C++)


+C++03: Undefined behavior: non-static member of non-POD class type is referred +after destructor ends execution
+C++11: Undefined behavior: non-static member of a class with a non-trivial +destructor is referred after destructor ends execution +
+// 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
+}
+
undefbehavior.CtorForeignCall +
(C++)


+Undefined behavior: call to virtual function of an object under construction +whose type is neither the constructors own class or one of its bases +
+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) {}
+};
+
undefbehavior.CtorForeignCast +undefbehavior.CtorForeignTypeid +
(C++)


+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 +
+#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) {}
+};
+
undefbehavior.MemberRefInCatch +undefbehavior.BaseRefInCatch +
(C++)


+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 +
+class C {
+  int i;
+public :
+  C()
+  try
+  : i(1) {}
+  catch (...)
+  {
+    i=2; // warn
+  }
+};
+
undefbehavior.ReturnAtCatchEnd +
(C++)


+Undefined behavior: a function returns when control reaches the end of a +handler. This results in undefined behavior in a value-returning +function +
+int test() try {
+}
+catch(int) {
+} // warn
+
undefbehavior.AutoptrsOwnSameObj +
(C++03)


+Undefined behavior: if more than one auto_ptr owns the same object at the same +time the behavior of the program is undefined. +
+#include <memory>
+
+void test() {
+  int *data = new int;
+  std::auto_ptr<int> p(data);
+  std::auto_ptr<int> q(data); // warn
+}
+
undefbehavior.BasicStringBoundAccess +
(C++03)


+Undefined behavior: out-of-bound basic_string access +
+void test() {
+  std::basic_string<char> s;
+  char c = s[10]; // warn
+}
+
undefbehavior.BasicStringBoundModification +
(C++)


+Undefined behavior: out-of-bound basic_string modification +
+void test() {
+  std::basic_string<char> s;
+  s[10] = 0; // warn
+}
+
undefbehavior.EosDereference +
(C++)


+Undefined behavior: the result of operator*() on an end of stream is +undefined +
+#include <vector>
+
+void test() {
+  std::vector<int> v;
+  int i = *v.end(); // warn
+  *v.end() = 0; // warn
+}
+
undefbehavior.QsortNonPOD +undefbehavior.QsortNonTrivial +
C++


+C++03: Undefined behavior: the objects in the array passed to qsort are of +non-POD type
+C++11: Undefined behavior: the objects in the array passed to qsort are of +non-trivial type +
+// 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
+}
+
undefbehavior.ThrowWhileCopy +
C++


+Undefined behavior: copy constructor/assignment operator can throw an exception. +The effects are undefined if an exception is thrown. +
+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;
+  }
+};
+
undefbehavior.ValarrayArgBound +
(C++)


+Undefined behavior: the value of the second argument is greater than the number +of values pointed to by the first argument +
+#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
+}
+
undefbehavior.ValarrayLengthDiffer +
(C++)


+Undefined behavior: valarray operands are of different length +
+// 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
+}
+
undefbehavior.ValarrayZeroLength +
(C++)


+Undefined behavior: calling sum()/min()/max() method of an array having zero +length, the behavior is undefined +
+#include <valarray>
+
+void test(void) {
+  std::valarray<int> v(0, 0);
+  v.sum(); // warn
+  v.min(); // warn
+  v.max(); // warn
+}
+
undefbehavior.ValarrayBadIndirection +
(C++)


+Undefined behavior: element N is specified more than once in the +indirection +
+#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
+}
+
undefbehavior.IosBaseDestroyedBeforeInit +
(C++)

+
Undefined behavior: ios_base object is destroyed before initialization have +taken place. basic_ios::init should be call to initialize ios_base +members +
+#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
+}
+
undefbehavior.IosBaseUsedBeforeInit +
(C++11)


+Undefined behavior: ios_base object is used before initialization have taken +place. basic_ios::init should be call to initialize ios_base members +
+#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
+}
+
undefbehavior.MinusOnePosType +
(C++)


+Undefined behavior: passing -1 to any streambuf/istream/ostream member that +accepts a value of type traits::pos_type result in undefined behavior +
+#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
+}
+
+ + +

different

+ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name, DescriptionExampleProgress
different.ArgEvalOrderUndef +
(C)


+Errors because of the order of evaluation of function arguments is undefined +
+void f(int, int);
+
+void test() {
+  int i = 0;
+  int v[1] = {0};
+  f(v[i], i++); // warn
+}
+
different.IdenticalExprBinOp +
(C)


+There are identical sub-expressions to the left and to the right of the +operator +
+#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
+}
+
different.FuncPtrInsteadOfCall +
(C)


+Possibly a function call should be used instead of a pointer to function +
+int f();
+
+void test() {
+  if (f == 0) {} // warn
+}
+
different.IdenticalCondIfElseIf +
(C)


+The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a +probability of logical error presence +
+void test() { 
+  int i = 7;
+  if (i == 1) {}
+  else if (i == 1) {} // warn
+}
+
SuccessiveAssign +
(C)


+Successive assign to a variable +
+void test() { 
+  int i=0;
+  i=1;
+  i=2; // warn
+}
+
different.NullDerefStmtOrder +
enhancement to core.NullDereference
(C)


+Dereferencing of the null pointer might take place. Checking the pointer for +null should be performed first +
+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
+}
+
different.NullDerefCondOrder +
enhancement to core.NullDereference
(C)


+Dereferencing of the null pointer might take place. Checking the pointer for +null should be performed first +
+struct S{bool b;};
+
+S* f();
+
+void test() {
+  S *p = f();
+  if (p->b && p) {}; // warn
+}
+
different.IdenticalStmtThenElse +
(C)


+The 'else' statement is equivalent to the 'then' statement +
+void test() {
+  int i;
+  if (i==1) {
+    i++;
+  }
+  else { // warn
+    i++;
+  }
+}
+
different.MultipleAccessors +
(C++)


+multiple accessors met for 'class::field' +
+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
+};
+
different.AccessorsForPublic +
(C++)


+Accessors exist for 'class::field'. Should this field really be public? +
+class A {
+public:
+  int i; // warn
+  int getI() { return i; }
+  void setI(int& ii) { i = ii; }
+};
+
different.LibFuncResultUnised +
(C, C++)


+Calling 'f' ignoring its return value is of no use (* create the list of known +system/library/API functions falling into this category) +
+#include <vector>
+
+void test() {
+  std::vector<int> v;
+  v.empty(); // warn
+}
+
different.WrongVarForStmt +
(C, C++)


+Possibly wrong variable is used in the loop/cond-expression of the ‘for’ +statement. Did you mean ‘proper_variable_name’? +
+void test() {
+  int i;
+  int j;
+  for (j=0; j<3; ++i); // warn
+  for (int j=0; i<3; ++j); // warn
+}
+
different.FloatingCompare +
(C)


+Comparing floating point numbers may be not precise +
+#include <math.h>
+
+void test() {
+  double b = sin(M_PI / 6.0);
+  if (b == 0.5) // warn
+    b = 0;
+}
+
different.BoolCompare +
maybe merge with experimental.core.BoolAssignment
(C, C++)


+Comparing boolean to a value other then 0 or 1 +
+void test() {
+  int i;
+  if (0 < i < 3) {}; // warn
+  bool b;
+  if (b == 3) {}; // warn
+}
+
different.BitwiseOpBoolArg +
maybe join with experimental.core.BoolAssignment
(C, C++)


+bool value is used at the left/right part of the & (|) operator. Did you mean +&& (||) ? +
+int f();
+
+void test() {
+  bool b = true;
+  if (b & f()) {} // warn
+}
+
different.LabelInsideSwitch +
(C)


+Possible misprint: label found inside the switch() statement. (* did you mean +‘default’?) +
+void test() {
+  int c = 7;
+  switch(c){
+  case 1:
+    c += 1; break;
+  defalt: // warn
+    c -= 1; break;
+  }
+}
+
different.IdenticalCondIfIf +
(C)


+The conditions of two subsequent ‘if’ statements are identical +
+void test() {
+  int c = 7;
+  if (c > 5) // <-
+    c += 1;
+  if (c > 5) // warn
+    c -= 1;
+}
+
different.CondOpIdenticalReturn +
(C)


+The return expressions of the ‘?:’ operator are identical +
+void test() {
+  unsigned a;
+  a = a > 5 ? a : a; // warn
+}
+
different.UnaryPlusWithUnsigned +
(C)


+Using ‘unary +’ with unsigned is meaningless +
+void test() {
+  unsigned a;
+  a = +a; // warn
+}
+
different.LogicalOpUselessArg +
(C)


+The second operand of the && operator has no impact on expression result +
+void test() {
+  unsigned a;
+  if (a<7 && a<10) {}; // warn
+}
+
different.SameResLogicalExpr +
(C)


+The expression always evaluates to true/false +
+void test() {
+  int i=0;
+  if (i!=0) {}; // warn
+  if (i==0 && i==1) {}; // warn
+  if (i<0 || i>=0) {}; // warn
+}
+
different.SameResUnsignedCmp +
(C)


+Comparison of unsigned expression ‘op expr’ is always true/false +
+void test() {
+  unsigned u;
+  if (u < -1) {}; // warn
+  if (u >= 0) {}; // warn
+}
+
different.OpPrecedenceAssignCmp +
(C)


+Comparison operation has higher precedence then assignment. Bool value is +assigned to variable of type ‘type’. Parenthesis may bee required around an +assignment +
+int f();
+
+void test() {
+  bool b;
+  int x, y;
+  if((b = x != y)) {} // ok
+  if((x = f() != y)) {} // warn
+}
+
different.OpPrecedenceIifShift +
(C)


+?: has lower precedence then << +
+#include <iostream>
+
+void test() {
+  int a;
+  std::cout << a ? "a" : "b"; // warn
+  a << a>7 ? 1 : 2; // warn
+}
+
different.ObjectUnused +
(C++)


+The object was created but is not being used

+The exception object was created but is not being used. Did you mean +‘throw std::exception();’ ? +
+#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
+}
+
different.StaticArrayPtrCompare +
(C)


+Pointer to static array is being compared to NULL. May the subscripting is +missing +
+void test() {
+  int a1[1];
+  if (a1 == 0) {}; // warn
+
+  int a2[1][1];
+  if (a2[0]) {}; // warn
+}
+
different.ConversionToBool +
maybe join with experimental.core.BoolAssignment
(C, C++)


+Odd implicit conversion from ‘type’ to ‘bool’ +
+bool test() {
+  return 1.; // warn
+  return ""; // warn
+}
+
different.ArrayBound +
enhancement to experimental.security.ArrayBound[v2]
(C, C++)


+Out-of-bound dynamic array access +
+#include <stdlib.h>
+
+void test() {
+  int *p2 = new int[1];
+  if(p2[1]) {}; // warn
+  int i = 1;
+  if(p2[i]) {}; // warn
+}
+
different.StrcpyInputSize +
enhancement to experimental.unix.cstring.OutOfBounds
(C)


+Buffer copy without checking size of input +
+void test(char* string) {
+  char buf[24];
+  strcpy(buf, string); // warn
+}
+
different.IntegerOverflow +
(C)


+Integer overflow +
+#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
+}
+
different.SignExtension +
(C)


+Unexpected sign extension might take place +
+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
+}
+
different.NumericTruncation +
(C)


+Numeric truncation might take place +
+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
+}
+
different.MissingCopyCtorAssignOp +
(C, C++)


+The class has dynamically allocated data members but do not define a copy +constructor/assignment operator +
+class C { // warn
+  int *p; // <-
+public:
+  C() { p = new int; }
+  ~C() { delete p; }
+};
+
+ + +

WinAPI

+ ++ + + + + + + + +
Name, DescriptionExampleProgress
WinAPI.CreateProcess +
(C)


+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) +
+#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
+
WinAPI.LoadLibrary +
(C)


+Calling LoadLibrary without a fully qualified path may allow to load a DLL from +arbitrary location +
+#include <windows.h>
+
+void test() {
+  HINSTANCE h = LoadLibrary("X.dll"); // warn
+}
+
WinAPI.WideCharToMultiByte +
(C)


+Buffer overrun while calling WideCharToMultiByte +
+#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;
+}
+
+ + +

optimization

+ ++ + + + + + + + + + + + + + +
Name, DescriptionExampleProgress
optimization.PassConstObjByValue +
(C, C++)


+Optimization: It is more effective to pass const n-th parameter by reference to +avoid unnecessary object copying +
+struct A {
+  int a[20];
+  int b;
+};
+
+bool FirstIsZero(const struct A a) { // warn
+  return a.a[0] == 0;
+}
+
optimization.PostfixIncIter +
(C++)


+Optimization: It is more effective to use prefix ++ with iterator here +
+#include <vector>
+
+void test() {
+  std::vector<int> v;
+  std::vector<int>::const_iterator it;
+  for(it = v.begin(); 
+      it != v.end(); it++) {}; // warn
+}
+
optimization.MultipleCallsStrlen +
(C)


+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 +
+#include <string.h>
+
+void test() {
+  const char* s = "abc";
+  if (strlen(s) > 0 && 
+      strlen(s) < 7) {}; // warn
+}
+
optimization.EmptyCstrDetect +
(C)


+Optimization: it is more efficient to use “str[0] != ‘\0’” to identify an empty +string +
+#include <string.h>
+
+void test() {
+  const char* s = "abc";
+  if (strlen(s) > 0) {}; // warn
+}
+
optimization.StrLengthCalculation +
(C, C++)


+Optimization: it is more efficient to use string::length() method to calculate +string length +
+#include <string>
+#include <string.h>
+
+void test() {
+  std::string s;
+  if (strlen(s.c_str()) != 0) {}; // warn
+}
+
optimization.EmptyContainerDetect +
(C, C++)


+Optimization: It is more efficient to use container.empty() to identify an +empty container +
+#include <list>
+
+void test() {
+  std::list<int> l;
+  if (l.size() != 0) {}; // warn
+}
+
+ +
+
+
+ +