Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN [email protected]...

34
Finding Bugs with PC- lint A Static Analysis Tool for C/C++ Philippe CHARMAN [email protected] http://users.polytech.unice.fr/~charman/ Last update: 05- 15-2014

Transcript of Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN [email protected]...

Page 1: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Finding Bugs with PC-lintA Static Analysis Tool for C/C++

Philippe [email protected]

http://users.polytech.unice.fr/~charman/

Last update: 05-15-2014

Page 2: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

PC-lint & FlexeLint

• Check the source code of C/C++ and detect any potential issue: bug, inconsistency, non-portable code, suspicious code, etc.

• The analyse is performed on all files

• Pseudo-execution of the code

• Available on Windows (PC-lint) and Unix (FlexeLint)

• License: About 500$, no trial license

Page 3: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

PC-lint & FlexeLint

• An interactive demo is available here:http://www.gimpel-online.com/OnlineTesting.htmlby clicking on Do-It-Yourself Example (C++)

Page 4: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

PC-lint & FlexeLint

• For each of the following 10 examples: – Without compiling the code, try to find the bug – If you haven’t found the bug, compile the code and

look if the compiler reports a warning– If you still haven’t found the bug, copy-paste the code

in the PC-lint demo window and click on the button « Analyse Code » to see the messages reported by PC-lint.

– Fix the code, compile it and check the execution results and check the fix in the window demo

Page 5: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 1

#include <stdio.h>

int main(){ int i; int a[] = {1,2,3}; int n = sizeof(a)/sizeof(int); for (i=0;i<=n;i++) printf("a[%d]=%d\n",i,a[i]); return 0;}

Page 6: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 1

1  #include <stdio.h>2  3  int main()4  { 5    int i; 6    int a[] = {1,2,3}; 7    int n = sizeof(a)/sizeof(int);8    for (i=0;i<=n;i++)                                       _9      printf("a[%d]=%d\n",i,a[i]); diy.cpp  9  Warning 661:  Possible access of out-of-bounds pointer (1 beyond end of data) by operator '[' [Reference: file diy.cpp: lines 7, 8, 9]10    return 0;11  }12  

Page 7: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of warning 661

661 possible access of out-of-bounds pointer ('Integer' beyond end of data) by operator 'String'

An out-of-bounds pointer may have been accessed. See message 415 for a description of the parameters Integer and String. For example:

int a[10]; if( n <= 10 ) a[n] = 0;

Here the programmer presumably should have written n<10. This message is similar to messages 415 and 796 but differs from them by the degree of probability.

Page 8: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 2

#include <string.h>

class X { int *p; public: X() { p = new int[20]; } void init() { memset( p, 20, 'a' ); } ~X() { delete p; } };

Page 9: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 2 1  #include <string.h> 2   3  class X { 4      int *p; 5    public: 6      X() 7          { p = new int[20]; } 8      void init() 9          { memset( p, 20, 'a'  ); }10      ~X()11          { delete p; }                      _ 7          { p = new int[20]; }diy.cpp  7  Info 1732:  new in constructor for class 'X' which has no assignment operatordiy.cpp  7  Info 1733:  new in constructor for class 'X' which has no copy constructor                                       _ 9          { memset( p, 20, 'a'  ); }diy.cpp  9  Warning 669:  Possible data overrun for function 'memset(void *, int, unsigned int)', argument 3 (size=97) exceeds argument 1 (size=80) [Reference: file diy.cpp: lines 7, 9]                          _11          { delete p; }diy.cpp  11  Warning 424:  Inappropriate deallocation (delete) for 'new[]' data12      };

Page 10: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of warning 669

669 Possible data overrun for function 'Symbol', argument Integer exceeds argument Integer Reference

This message is for data transfer functions such as memcpy, strcpy, fgets, etc. when the size indicated by the first cited argument (or arguments) can possibly exceed the size of the buffer area cited by the second. The message may also be issued for user functions via the -function option See Function Mimicry and Value Tracking.

Page 11: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 3

#include <stdio.h>

int quotient(int *q, int *p) {

if(*p) return *q/*p /* compute ratio */ ;

else return *q;

}

int main() {

int n = 20, m = 4;

int q = quotient( &n, &m );

printf( "%d/%d = %d\n", n, m, q ); // displays 20 instead of 5

return 0;

}

Page 12: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 3

1  #include <stdio.h>2  3  int quotient(int *q, int *p) {                                 _4    if(*p) return *q/*p  /* compute ratio */ ;diy.cpp  4  Warning 602:  Comment within comment5    else return *q;        _6  }diy.cpp  6  Info 818:  Pointer parameter 'p' (line 3) could be declared as pointing to constdiy.cpp  6  Info 818:  Pointer parameter 'q' (line 3) could be declared as pointing to const7  8  int main() {9    int n = 20, m = 4;10    int q = quotient( &n, &m );11    printf( "%d/%d = %d\n", n, m, q );12    return 0;13  }

Page 13: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of warning 602

02 Comment within comment

The sequence /* was found within a comment. Was this deliberate? Or was a comment end inadvertently omitted? If you want PC-lint/FlexeLint to recognize nested comments you should set the Nested Comment flag using the +fnc option. Then this warning will not be issued. If it is your practice to use the sequence:

/*

/* */

then use -e602.

Page 14: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 4

#include <stdio.h>#include <stdlib.h>

const char *flowers[] = { "rose", "tulip", "daisy" "petunia", "orchid", "lily" };

int main() { int i; int choice; for( i = 0; i < 25; i++ ) { choice = rand() % 6; printf( "%s\n", flowers[choice] ); } return 0;}

Page 15: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 4

1  #include <stdio.h>     2  #include <stdlib.h>     3       4  const char *flowers[] =  {     5      "rose", "tulip", "daisy"            _     6      "petunia", "orchid", "lily"diy.cpp  6  Info 786:  String concatenation within initializer     7    };     8       9  int main() {    10    int i;    11    int choice;    12        13    for( i = 0; i < 25; i++ ) {    14        choice = rand() % 6;    15        printf( "%s\n", flowers[choice] );    16      }    17    return 0;    18  }

Page 16: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of info 786

786 String concatenation within initializer

Although it is perfectly 'legal' to concatenate string constants within an initializer, this is a frequent source of error. Consider:

char *s[] = { "abc" "def" };

Did the programmer intend to have an array of two strings but forget the comma separator? Or was a single string intended?

Page 17: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 5

The code is supposed to return the sum of all elements of a matrix

#include <stdio.h>

int a[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} };int sum( int a[3][3] ) { int i=0, j=0, k=0; for( i = 0; i < 3; i++ ) { for( i = 0; i < 3; i++ ) {

k += a[i][j]; }

} return k;}

int main() { printf( "The triangular sum is %d\n", sum(a) ); // displays 12 return 0;}

Page 18: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 5 1  #include <stdio.h> 2   3  int a[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} };                               _ 4  int sum( int a[3][3] ) {

diy.cpp  4  Warning 578:  Declaration of symbol 'a' hides symbol 'a' (line 3) 5    int i=0, j=0, k=0;                    _ 6    for( i = 0; i < 3; i++ ) {

diy.cpp  6  Info 838:  Previously assigned value to variable 'i' has not been used                                     _ 7        for( i = 0; i < 3; i++ ) {

diy.cpp  7  Warning 445:  Reuse of for loop variable 'i' at 'line 6' could cause chaos 8     k += a[i][j]; 9    }10    }          _11    return k;

diy.cpp  11  Info 850:  for loop index variable 'i' whose type category is 'integral' is modified in body of the for loop that began at 'line 6'        _12  }

diy.cpp  12  Info 818:  Pointer parameter 'a' (line 4) could be declared as pointing to const13  14  int main() {15    printf( "The triangular sum is %d\n", sum(a) );16    return 0;17  }

Page 19: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of warning 445

445 reuse of for loop variable 'Symbol' at 'Location' could cause chaos

A for loop nested within another for loop employed the same loop variable. For example:

for( i = 0; i < 100; i++ ) { ... for( i = 0; i < n; i++ ) { ... } }

Page 20: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 6

//lint -passes(4)

int f( int n ) { return 10/n; }

int g( int n ) { if( n == -1 ) return 0; return f(n) + g( n - 1 ); }

int main() { return g( 3 ); // a crash appears }

Page 21: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 6

/// Start of Pass 4 ///

--- Module: diy.cpp (C++)     1  //lint -passes(4)     2       3  int f( int n )     4      {     5      return 10/n;

During Specific Walk:diy.cpp  16  g(3) #2diy.cpp  11  g(2) #3diy.cpp  11  g(1) #4diy.cpp  11  g(0) #5diy.cpp  11  f(0) #5diy.cpp  5  Warning 414:  Possible division by 0 [Reference: file diy.cpp: lines 11, 16]     6      }     7       8  int g( int n )     9      {    10      if( n == -1 ) return 0;    11      return f(n) + g( n - 1 );    12      }    13      14  int main()    15      {    16      return g( 3 );    17      }

Page 22: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of warning 414

414 Possible division by 0

The second argument to either the division operator (/) or the modulus operator (%) may be zero. Information is taken from earlier statements including assignments, initialization and tests.

Page 23: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 7

#include <stdio.h>

struct { int bit:1; } s;

bool f() {

if( s.bit > 0 ) return true;

else return false;

}

int main() {

s.bit = 1;

if( f() ) printf( "the bit is ON\n" );

else printf( "the bit is OFF\n" ); // this is what is displayed

return 0;

}

Page 24: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 7

1  #include <stdio.h>     2                          _     3  struct { int bit:1; } s;diy.cpp  3  Info 846:  Signedness of bit-field is implementation defineddiy.cpp  3  Info 806:  Small bit field is signed rather than unsigned     4       5  bool f() {                        _     6    if( s.bit > 0 ) return true;diy.cpp  6  Warning 685:  Relational operator '>' always evaluates to 'false'     7    else return false;     8  }     9      10  int main() {                   _    11    s.bit = 1;diy.cpp  11  Warning 542:  Excessive size for bit field    12    if( f() ) printf( "the bit is ON\n" );    13    else printf( "the bit is OFF\n" );    14    return 0;    15  }

Page 25: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of info 846846 Signedness of bit-field is implementation defined

A bit-field was detected having the form:

int a:5;

Most bit fields are more useful when they are unsigned. If you want to have a signed bit field you must explicitly indicate this as follows:

signed int a:5;

The same also holds for typedef's. For example,

typedef int INT; typedef signed int SINT; struct {

INT a:16; // Info 846 SINT b:16; // OK

}:

It is very unusual in C or C++ to distinguish between signed int and just plain int. This is one of those rare cases.

Page 26: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 8

#include <stdio.h>

struct { int a[3], b; } w[] = { { 1, 2, 3 }, 2 };

int main()

{

printf( "w[0].b = %d\n", w[0].b ); // displays 0

return 0;

}

Page 27: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 8

1  #include <stdio.h>2                                           3  struct { int a[3], b; } w[] = { { 1, 2, 3 }, 2 };diy.cpp  3  Warning 651:  Potentially confusing initializerdiy.cpp  3  Info 785:  Too few initializers for aggregate 'unknown-name‘ of type '{...}‘diy.cpp  3  Info 785:  Too few initializers for aggregate 'unknown-name‘ of type 'int [3]‘diy.cpp  3  Info 785:  Too few initializers for aggregate 'unknown-name‘ of type '{...}4  5  int main()6  {7    printf( "w[0].b = %d\n", w[0].b );8    return 0;9  }

Page 28: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of warning 651

651 Potentially confusing initializer

An initializer for a complex aggregate is being processed that contains some subaggregates that are bracketed and some that are not. ANSI recommends either "minimally bracketed" initializers in which there are no interior braces or "fully bracketed" initializers in which all interior aggregates are bracketed.

Page 29: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 9

class X

{

public:

int upper;

int lower;

X( int init ) : lower( init ), upper( lower+1 )

{}

};

X x(1); // x.upper is equal to 1 instead of 2

Page 30: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 9

1  class X2  {3  public:4    int upper;5    int lower;6    X( int init ) : lower( init ), upper( lower+1 )7    {}                                              _6    X( int init ) : lower( init ), upper( lower+1 )diy.cpp  6  Info 1729:  Initializer inversion detected for member 'X::upper'        _8  };diy.cpp  8  Info 1712:  default constructor not defined for class 'X'9  10  X x(1);

Page 31: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of info 1729

1729 Initializer inversion detected for member 'Symbol‘

In a constructor initializer the order of evaluation is determined by the member order not the order in which the initializers are given. At least one of the initializers was given out of order. Was there a reason for this? Did the programmer think that by changing the order that he/she would affect the order of evaluation? Place the initializers in the order of their occurrence within the class so that there can be no mistaken assumptions.

Page 32: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Example 10

#include <iostream>

using namespace std;

struct WhiteHouse {

int *p;

WhiteHouse(int n) { p = new int; *p = n; }

~WhiteHouse() { delete p; }

};

WhiteHouse ww(1912);

void f() { WhiteHouse fdr(1932); fdr = ww; }

int main() {

f();

WhiteHouse gwb(2000);

cout << *ww.p; // crash or displays 2000

return 0;

}

Page 33: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Analysing example 10

  1  #include <iostream>2  using namespace std;3  4  struct WhiteHouse {5    int *p;6    WhiteHouse(int n) { p = new int; *p = n; }7    ~WhiteHouse() { delete p; }                                  _6    WhiteHouse(int n) { p = new int; *p = n; }diy.cpp  6  Info 1732:  new in constructor for class 'WhiteHouse' which has no assignment operatordiy.cpp  6  Info 1733:  new in constructor for class 'WhiteHouse' which has no copy constructor        _8  };diy.cpp  8  Info 1712:  default constructor not defined for class 'WhiteHouse'9  10  WhiteHouse ww(1912);11  12  void f() { WhiteHouse fdr(1932); fdr = ww; }13  14  int main() {15    f();16    WhiteHouse gwb(2000);17    cout << *ww.p;         // crash or displays 200018    return 0;        _19  }diy.cpp  19  Info 1788:  Variable 'gwb' (line 16) (type 'WhiteHouse') is referenced only by its constructor or destructor

Page 34: Finding Bugs with PC-lint A Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com charman/ Last update: 05-15-2014.

Explanation of info 1732

1732 new in constructor for class 'Name' which has no assignment operator

Within a constructor for the cited class, there appeared a new. However, no assignment operator was declared for this class. Presumably some class member (or members) points to dynamically allocated memory. Such memory is not treated properly by the default assignment operator. Normally a custom assignment operator would be needed. Thus, if x and y are both of type Name

x = y;

will result in pointer duplication. A later delete would create chaos.