• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &lt;stdlib.h&gt;
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 &lt;stdlib.h&gt;
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 &lt;stdlib.h&gt;
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 &lt;stdlib.h&gt;
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 &lt;string.h&gt;
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 &lt;stdlib.h&gt;
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&lt;T[]&gt; 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 &lt;stdlib.h&gt;
239#include &lt;memory&gt;
240
241void test() {
242  std::auto_ptr&lt;int&gt; p1(new int); // Ok
243  std::auto_ptr&lt;int&gt; p2(new int[3]); // warn
244  std::auto_ptr&lt;int&gt;
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 &lt;cstdlib&gt;
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; // &lt;-
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 &lt;stdlib.h&gt;
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 &lt;stdlib.h&gt;
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 &lt;new&gt;
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&lt;A*&gt;(b); // warn
348  dynamic_cast&lt;A*&gt;(b); // warn
349  delete b; // warn
350}
351
352// C++11
353#include &lt;new&gt;
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&lt;A*&gt;(b); // warn
376  dynamic_cast&lt;A*&gt;(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 &lt;new&gt;
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 (&amp;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 &lt;stdlib.h&gt;
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&lt;int *&gt;(ciq);
447  *iq = 1; // warn
448
449  const Y y;
450  Y* p = const_cast&lt;Y*&gt;(&amp;y);
451  p-&gt;x.i = 1; // ok
452  p-&gt;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 = &amp;non_pod.j; // warn
510int *p2 = &amp;non_pod.pod.i; // warn
511int *p3 = &amp;pod.i; // ok
512POD *p4 = &amp;non_pod; // warn
513
514POD a;
515non_POD b;
516
517struct S {
518  int *k;
519  non_POD non_pod;
520  S() : k(&amp;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 = &amp;nt.j; // warn
538int *p2 = &amp;nt.i; // warn
539int *p3 = &amp;t.i; // ok
540trivial *p4 = &amp;nt;
541
542trivial t;
543non_trivial nt;
544
545struct S {
546  int *k;
547  non_trivial nt;
548  S() : k(&amp;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-&gt;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 &lt;typeinfo&gt;
612
613class A {
614public:
615  virtual void f() {};
616};
617
618class B {
619public:
620  B(A* a) {
621    typeid(*a); // warn
622    dynamic_cast&lt;B*&gt;(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 &lt;memory&gt;
670
671void test() {
672  int *data = new int;
673  std::auto_ptr&lt;int&gt; p(data);
674  std::auto_ptr&lt;int&gt; 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&lt;char&gt; 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&lt;char&gt; 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 &lt;vector&gt;
704
705void test() {
706  std::vector&lt;int&gt; 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 &lt;cstdlib&gt;
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 &lt;cstdlib&gt;
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 &amp;s) {
786    i = s.i;
787    throw 1; // warn
788    j = s.j;
789  };
790  S &amp;operator=(const S &amp;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 &lt;valarray&gt;
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&lt;S&gt; 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 &lt;valarray&gt;
822
823void test(void) {
824  std::valarray&lt;int&gt; a(0, 1), b(0, 2);
825  std::valarray&lt;bool&gt; 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 &lt;valarray&gt;
836
837void test(void) {
838  std::valarray&lt;int&gt; a(0, 1), b(0, 2);
839  std::valarray&lt;bool&gt; 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 &lt;valarray&gt;
855
856void test(void) {
857  std::valarray&lt;int&gt; 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 &lt;valarray&gt;
870
871void test() {
872  size_t addr[] = {0, 1, 1}; // N is 1
873  std::valarray&lt;size_t&gt;indirect(addr, 3);
874  std::valarray&lt;int&gt; 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 &lt;ios&gt;
887
888using namespace std;
889template &lt;class T, class Traits = std::char_traits&lt;T&gt;&gt;
890class my_stream1 : public std::basic_ios&lt;T, Traits&gt; {
891};
892
893template &lt;class T, class Traits = std::char_traits&lt;T&gt;&gt;
894class my_stream2 : public std::basic_ios&lt;T, Traits&gt; {
895  class my_streambuf : public std::basic_streambuf&lt;T, Traits&gt; {
896  };
897public:
898  my_stream2() {
899    this->init(new my_streambuf);
900  }
901};
902
903void test() {
904  my_stream1&lt;char&gt; *p1 = new my_stream1&lt;char&gt;
905  my_stream2&lt;char&gt; *p2 = new my_stream2&lt;char&gt;
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 &lt;ios&gt;
917
918using namespace std;
919template &lt;class T, class Traits = std::char_traits&lt;T&gt;&gt;
920class my_stream1 : public std::basic_ios&lt;T, Traits&gt; {
921};
922
923template &lt;class T, class Traits = std::char_traits&lt;T&gt;&gt;
924class my_stream2 : public std::basic_ios&lt;T, Traits&gt; {
925  class my_streambuf : public std::basic_streambuf&lt;T, Traits&gt; {
926  };
927public:
928  my_stream2() {
929    this->init(new my_streambuf);
930  }
931};
932
933void test() {
934  my_stream1&lt;char&gt; *p1 = new my_stream1&lt;char&gt;
935  my_stream2&lt;char&gt; *p2 = new my_stream2&lt;char&gt;
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 &lt;fstream&gt;
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(&amp;fb);
959  std::ostream out(&amp;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-&gt;x; // warn
1061  if (p1) {};
1062
1063  S *p2 = f();
1064  int x2 = p2-&gt;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-&gt;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 &lt;vector&gt;
1131
1132void test() {
1133  std::vector&lt;int&gt; 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&lt;3; ++i); // warn
1147  for (int j=0; i&lt;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 &lt;math.h&gt;
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 &amp; (|) operator. Did you mean
1179&amp;&amp; (||) ?
1180</td><td><pre>
1181int f();
1182
1183void test() {
1184  bool b = true;
1185  if (b &amp; 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 &gt; 5) // &lt;-
1212    c += 1;
1213  if (c &gt; 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 &amp;&amp; operator has no impact on expression result
1231</td><td><pre>
1232void test() {
1233  unsigned a;
1234  if (a&lt;7 &amp;&amp; a&lt;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 &amp;&amp; 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 &lt; -1) {}; // warn
1257  if (u &gt;= 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 &lt;&lt;
1280</td><td><pre>
1281#include &lt;iostream&gt;
1282
1283void test() {
1284  int a;
1285  std::cout &lt;&lt; a ? "a" : "b"; // warn
1286  a &lt;&lt; a&gt;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 &lt;exception&gt;
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 &lt;stdlib.h&gt;
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 &lt;limits.h&gt;
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; // &lt;-
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 &lt;windows.h&gt;
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, &amp;si, &amp;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 &lt;windows.h&gt;
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 &lt;windows.h&gt;
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 &lt;vector&gt;
1529
1530void test() {
1531  std::vector&lt;int&gt; v;
1532  std::vector&lt;int&gt;::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 &lt;string.h&gt;
1545
1546void test() {
1547  const char* s = "abc";
1548  if (strlen(s) &gt; 0 &amp;&amp;
1549      strlen(s) &lt; 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 &lt;string.h&gt;
1559
1560void test() {
1561  const char* s = "abc";
1562  if (strlen(s) &gt; 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 &lt;string&gt;
1572#include &lt;string.h&gt;
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 &lt;list&gt;
1586
1587void test() {
1588  std::list&lt;int&gt; 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