jeudi 8 novembre 2012

When compiler act as Static Analyzer

Today i goes through a strange compiler behavior while compiling a source code with GCC/G++. You may or not be aware of the importance of Security and Sanity checking on the code you write, but it's a fact that in the last decade the "Static Code Analysis" come from space, fly, nuclear domain and is now use in game and all professional development.

For a good introduction to "Static Analysis" take a look at http://www.altdevblogaday.com/2011/12/24/static-code-analysis/ where John Carmack present a review of several existing tools.

But here I try to explain why sometimes a good compiler like GCC "can" act as a static code checker. To demonstrate and explain it, lets talk about the code below.


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <string>

//inline int func(int tab[], bool toSwitch) //force inline.
//__attribute__ ((noinline)) int func(int tab[], bool toSwitch)  //prevent inline.
int func(int tab[], int idx) //let compiler inline based on its own logic and optimization parameters.
{
  return tab[idx];
}

int main(int argc, char* argv[])
{
  std::cout << argc << " " << std::string(argv[0]) << std::endl;
  int myTab[4] = {1,2,3,4};
  //int myTab[10] = {1,2,3,4,5,6,7,8,9,10};
  std::cout << func(myTab, 0) << std::endl;
  std::cout << func(myTab, 8) << std::endl;

  //At least the line is detected by VS'12 Static Analyzer....
  std::cout << myTab[8] << std::endl;
  return 0;
}

I mainly code using Visual Studio IDE (08,10 at work and 12 at home for now...) but hopefully i also use GCC and we will see why just below. As you can see, i coded 2 buffer overrun by calling "func(myTab, 8)" and "myTab[8]".
  • Visual Studio 2012 
From VS compiler point of view that code is perfect, no error, no warning. But at least the line 20 is detected by VS'12 Static Analyzer


//At least the line is detected by VS'12 Static Analyzer....
std::cout << myTab[8] << std::endl;

stl_usage.cpp(22): warning : C6201: Index '8' is out of valid index range '0' to '3' for possibly stack allocated buffer 'myTab'.
stl_usage.cpp(22): warning : C6385: Reading invalid data from 'myTab': the readable size is '16' bytes, but '36' bytes may be read.

  • GCC
when i compile that source code with the following line:
g++ -Wall -Wextra -Werror -O3 ./gcc-static-analys.cpp
I got the following error:
./gcc-static-analys.cpp: In function âint main(int, char**)â:
./gcc-static-analys.cpp:17: error: âmyTab[8]â is used uninitialized in this function [-Werror=uninitialized]
./gcc-static-analys.cpp:20: error: âmyTab[8]â is used uninitialized in this function [-Werror=uninitialized]
cc1plus: all warnings being treated as errors

But why GCC can detect these 2 buffer overrun at compile-time. For the direct and invalid access to myTab[8] it should be easy but for "func(8)", it's a bit tricky. In fact if you had a look at the 2 comment line 4 and 5, you may have guess that it's mainly come from the "inlining" of "func".

Depending of the optimization level you used GCC can decide to inline some function by itself and in fact case he can detect some error and act as a Stactic Analyzer  preventing use to let something wrong (a security issue) in our code.


mardi 23 octobre 2012

why you should prefer std::algorithm...

Today i worked on a huge legacy code base when i meet (1x more) the following kind of loop:


std::vector<int> vec;
...
int max_value = 0;
for ( int i=0 ; i<(int)vec.size() ; i++ )
  {
    if (vec[i] > max_value)
    {
      max_value = vec[i];
    }
  }

I was wondering why some developer always try to reinvent the wheel ?

C++ comes with a tons of useful algorithm to do that kind of stuff, and with an explicit name. In example that code can be rewrite with:


#include <algorithm>
...
std::vector<int> vec;
...
int max_value = *std::max_element<std::vector<int>::iterator >(vec.begin(), vec.end());

it's shorter and more explicit...

Note for C++11 users:



auto max_value = *std::max_element<std::vector<int>::iterator >(begin(vec), end(vec));

mercredi 17 octobre 2012

VS - How To Collapse your Solution Explorer.


You may have notice (or maybe not) that VS'08 often expand the whole Solution Explorer  when you open a solution.

With VS'12 The VS Team added the solution explorer collapse button, but we can add that functionnality to our old VS using a simple VB Macro.

You have to follow some few step and play! 
  1. unzip SolutionCollapse.zip (in Users\YOU\Documents\Visual Studio 2008\Projects\VSMacros80 for example)  
  2. Open  VS'08 – View – Other windows – Macros Explorer 3)       Dans l’explorateur de macro – Load Macro Project – And select SolutionCollapse  
  3. Now in  Tools –Customize  – Keyboard 
    1.  in "Show command containing" enter « Collapse », Scroll the results to find "Macros.SolutionCollapse.CollapseAll"
    2.  Set a shortcut  (CTRL-M + CTRL-C for example)

Done.


CppCheck VS integration

1st, download and setup CppCheck from http://cppcheck.sourceforge.net/

Next in VS, Open Tools => Extension and Add the following command


argument line: --enable=all --verbose --template=vs "$(ProjectDir)"

Get back and you will see something like that in your Tools menu.



To add a keyboard shortcut, Go to Tools => Customize => click on the "Keyboard" button, "Show commands containing "Tools.Exter", Select the "ExternalCommand1" if you placed "your CppCheck command on the top of the list and define the shortcut you want. For example, i used CTRL+ALT+C.


Now when working on C/C++ Project and source code in VS, just press your shortcut, to see CppCheck message in the "Output" windows. Click on a message to go immediately into the incriminate code.

Good luck.

jeudi 4 octobre 2012

How to map array into a std::vector and display value.

As C++ user, you may have to check if a given value is allow in your software and if not display the list of allowed values.

To do that job, you can write code based on C++/STL and use as few "if"s, "while"s, "for"s and other builtin constructs as possible. In the following  example, I try to demonstrate 3 things:
  1. Init a vector within a array. Note that in the new C++ standard, you can implement that with a single line.
  2. Check if a value is in the vector using the 'find' algorithm.
  3. Display on stdout or format into a string all values using 'copy'.


#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
#include <sstream>

int _tmain(int argc, _TCHAR* argv[])
{

  int tab[5] = {1,2,3,4,5};
  std::vector<int> test(tab, tab+5);

  int valueForChecking = -1;
  std::cin >> valueForChecking;

  if(std::find(test.begin(), test.end(), valueForChecking) == test.end())
  {  
    std::copy(test.begin(), test.end(), std::ostream_iterator<int>(std::cout," ")); 
    std::cout << std::endl;
  }
  else
    std::cout << "is in" << std::endl;

  //or

  if(std::find(test.begin(), test.end(), valueForChecking) == test.end())
  {
    std::ostringstream s;
    std::copy(test.begin(), test.end(), std::ostream_iterator<int>(s," "));
    std::cout << "string from vector : " << s.str() << std::endl;
  }
  else
    std::cout << "is in" << std::endl;

  return 0;
}

mardi 2 octobre 2012

A Simple polymorphism example...

It seems that the term "Polymorphism" is not so clear that it should to some of team member (and sometimes it also a mess to me to understand object design we made !!!)... So every time, every time i will use polymorphism in my own work, i will try to extract a demonstration/example.

Let's start with the following example in which we can show that we can define a function to call the f function of a 'Base' object, but accessing finally the f function implemented by the child....


class A
{
public:
  virtual void f()
  {
    std::cout << "A::f()" <<std::endl;
  }
};

class B : public A
{
public:
  virtual void f()
  {
    std::cout << "B::f()" << std::endl;
  }
};

class AI : public A
{

};

class BI : public B
{

};

void master_f(A& base_ref)
{
  base_ref.f();
}

int _tmain(int argc, _TCHAR* argv[])
{
  AI oAI;
  BI oBI;

  master_f(oAI);
  master_f(oBI);

 return 0;
}

dimanche 2 septembre 2012

New VS'12 IDE but build with your old compiler.


Visual Studio project allow to configure the set of tool you want use to build.

If you setup on the same platform VS'08, 2010 and 2012, you can use all the recent tools and functionality of the VS IDE, but still use the old compiler, and don't have to deal with all the recent change in C++ standard or in the compiler.
Property box of a C++ project.