1 / 34

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

Finding Bugs with PC-lint A Static Analysis Tool for C/C++. Philippe CHARMAN charman@fr.ibm.com http://users.polytech.unice.fr/~charman/. Last update: 05-15-2014. PC-lint & FlexeLint.

tfriesen
Télécharger la présentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Finding Bugs with PC-lintA Static Analysis Tool for C/C++ Philippe CHARMAN charman@fr.ibm.com http://users.polytech.unice.fr/~charman/ Last update: 05-15-2014

  2. 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 isperformed on all files • Pseudo-execution of the code • Available on Windows (PC-lint) and Unix (FlexeLint) • License: About 500$, no trial license

  3. PC-lint & FlexeLint • An interactive demoisavailablehere: http://www.gimpel-online.com/OnlineTesting.html by clicking on Do-It-YourselfExample (C++)

  4. 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

  5. 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; }

  6. 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  

  7. 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.

  8. Example 2 #include <string.h> class X { int *p; public: X() { p = new int[20]; } void init() { memset( p, 20, 'a' ); } ~X() { delete p; } };

  9. 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      };

  10. Explanation of warning 669 669 Possible data overrun for function 'Symbol', argument Integer exceeds argument IntegerReference 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.

  11. 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; }

  12. 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  }

  13. 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.

  14. 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; }

  15. 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  }

  16. 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?

  17. 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; }

  18. 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  }

  19. 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++ ) { ... } }

  20. 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 }

  21. 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      }

  22. 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.

  23. 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; }

  24. 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  }

  25. Explanation of info 846 846 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.

  26. 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; }

  27. 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 initializer diy.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  }

  28. 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.

  29. 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

  30. 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);

  31. 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.

  32. 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; }

  33. 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

  34. 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.

More Related