C++ code analysis in Visual Studio 2012

Lire cet article en français

lots-of-crashes_thumb1

The problem with this kind of message is that it does not make your customers very found of your application. And what if it happens during trial period?

Good news is, code analysis is one answer to this kind of problem.

Code analysis examines source code at compilation time, and finds bugs before they even happen. It is one of the debugging tools a developer can use. It complements the usual test procedures (functional testing, unit testing …) Its secret is to find unsafe code patterns in source code. And it is efficient.

Code analysis is one of the tools that can be used to create safer applications. It is part of Microsoft SDL methodology (Security Development Lifecycle).

I’m sorry to inform you that Code analysis knows which bugs you create. Hence, it can find them in your code:

  • dereferencing null pointer
  • buffer overrun
  • uninitialized variable
  • memory leak
  • concurrent access problem

Code Analysis in Visual C++ 2012 (VS11) and MFC

 

The team which has created Code analysis for C++ used the huge code base of Windows. They know what type of code is safe, and what type of code can cause a crash!

Code analysis in Visual Studio 2010 is only available in Visual Studio Ultimate and Premium. But Microsoft decided it is important for every C++ developer to have this tool handy. So, a light version of C++ code analysis is included in Visual Studio 11 Express, and all of the 200+ rules are in Visual Studio 11 Professional (from Code Analysis talk at Build Conference)

Code analysis has been improved in Visual Studio 11 in many ways: it is easier to use, thanks to the new Code Analysis window, and it is more powerful, more readable (more explicit messages) and reported problems are more relevant. Code analysis uses rules to find unsafe code patterns. The rules are improved, and cover a wider range of code, including multitasking, and soon 64-bit compilation.

Visual Studio 11 Developer Preview, a pre-release version of Visual Studio vNext, allows everyone to use C++ code analysis and its bug traps, under Windows 7 (Visual Studio 11 is temporary name of next release of Visual Studio.)

When you use C++ MFC application wizard (menu File/New project/MFC Application), a SDL checks checkbox can activate Code analysis:

MFC-app-wizard-11-SDL-check_thumb3

When the project is created, Code analysis can be run very easily:

Visual--studio-2010-build-menu-code-

Code analysis must recompile the project. It is slightly longer than a simple compilation.

Note : for non-MFC C++ projects, code analysis can also be activated in the project properties (menu Project/Properties), in C/C++ general tab.

 

A few bugs detected by Code Analysis

 

All indices of arrays are scrutinized by Code analysis to detect potential overflow, especially in the loops. If an array index goes out of the array boundaries, the problem will be reported.

For example, in CDocument class, let’s create an array and use it like this:

class CMFCApplication1Doc : public CDocument
{
    // ... static const int m_size = 100;
    char m_tab[m_size];
    // ... };
void CMFCApplication1Doc::ShiftArray()
{
    for (int i=0; i< m_size; i++)
    {
        m_tab[i] = m_tab[i+1];
    }
}

Of course there is a problem. It may not be caught by a code review anyway, especially if the code is not as simple as here. Code analysis finds the bug, and notices that valid indices for m_tab array range from 0 to 99, while index 100 is used.:

visual-studio-2012-code-analysis_thu

The code analysis window has a search field. Results can be filtered. Above, only the results for files whose names contain « doc » are displayed.

Here is another unsafe code sample:

void CMFCApplication1Doc::SetDelay(int delay)
{
    CDelayHolder *pObj = nullptr;
    bool isFound = false;
    for (int index = 0; index <10; index++)
    {
        if (index >= delay)
        {
            pObj = new CDelayHolder();
        }
        else {
            if (!isFound)
                isFound = WaitDelay(delay);
            else pObj->Wait(delay);
        }
    }
}

This code is a bit weird but I have seen even stranger code! Code analysis finds the problem and explains it. It occurs during the second time through the loop:

visual-studio-2012-code-analysis-loo

 

Buffer overrun, invalid pointers, memory leaks, and many other problems are sought in the code. Code analysis uses more than 200 rules to check code safety.

 

Customizing Code analysis

 

You can customize the rules of the code analyzer as needed. Create a new rule file (menu File/New File/Code Analysis rule set), and you can disable, enable, or treat certain rules as error or warning.

visual-studio-2012-code-analysis-lis

Code Analysis tab in the Project properties let you select a Code analysis rule set.

Code analysis behavior can also be customized in C++ code, using #pragma warning :

#pragma warning(suppress: 6011) #pragma warning (error: 6001) 

 

Semantic code annotation

 

It is very easy to get a diagnostic on code quality with Visual Studio 11 Code analysis. It is possible to get even more accurate diagnostics if you help the code parser to do its job. SAL (Source code Annotation Language) is a list of keywords you can add in your source code. SAL keywords are recognized by the Code analysis parser, to make the results more accurate.

SAL can be seen as semantic comments in code. They are used by the analyzer to make verifications. SAL keywords are defined in the file sal.h. This is the file you want to check if you want to know how it works.

_In_ and _Out_ are the most used SAL keywords, in a function declaration. For example:

void GetTextProperty(_In_ LPCTSTR szPropertyName,
                    _Out_ LPTSTR szOutBuffer,
                    _In_ int nBufferSize);

_In_ means the function will only read from the buffer. The caller must provide the buffer and initialize it.

_Out_ means the function will only write to the buffer. The caller must provide the buffer, and the function will initialize it.

Code analysis will check that szPropertyName is correctly initialized before the function is called.

Microsoft Windows development team uses SAL, and more than 3 millions SAL annotations have been added to Windows source code. Thus, Windows include files contain useful annotations for our applications. For example, GlobalLock Win32 function is defined in winbase.h:

_Ret_maybenull_ LPVOID WINAPI GlobalLock (_In_ HGLOBAL hMem); 

This is quite explicit: hMem parameter must be initialized before function call and must not be null, while the return value might be null.

Thus, Code analysis will display two messages with following sample code:

HGLOBAL hMem = nullptr;
char *p = (char *)GlobalLock(hMem);
*p = 'a';

visual-studio-2012-code-analysis-glo

The first message indicates that you must not pass a null pointer to GlobalLock. The second says that, since GlobalLock can return a null pointer, it is illegal to dereference it without testing if it is not null.

MFC code also uses SAL. For example, CWnd::GetWindowText is declared as follow:

int GetWindowText(_Out_writes_to_(nMaxCount, return + 1) LPTSTR lpszStrBuf,
    _In_ int nMaxCount) const;

So, Code analysis checks that lpszStrBuf is an array of at least nMaxCount bytes, and nMaxCount must not be null.

A buffer overrun problem is detected in this code sample:

TCHAR buffer[80];
AfxGetMainWnd()->GetWindowText(buffer, 100);

visual-studio-2012-code-analysis-get

 

Parallel code analysis

 

C++ Code analysis can help finding bugs in parallel code. More than 100 rules are particularly relevant on this topic.

One of the common problems of parallel code is avoiding concurrent access to a variable. An error at this level can cause a crash or an application dead lock.

Following code sample uses an integer count, protected by a critical section cs.

_Garded_by_ is a new SAL keyword indicating that a variable must be protected by a lock. Here, cs is the lock which avoids concurrent access on count. Code analysis can now detect any access to count which is not guarded by cs.

typedef struct {
    _Garded_by_(cs) int count;
    CRITICAL_SECTION cs;
}COUNT; 

bool CMFCApplication1Doc::UpdateCount(_In_ COUNT *p, _In_ int diff)
{
    EnterCriticalSection(&p->cs);
    if (p->count < diff)
        return false;
    p->count -= diff;
    LeaveCriticalSection(&p->cs);
    return !p->count;
}

Two problems are detected by Code analysis: a return inside the critical section, and an unprotected access to count at the end of the function:

visual-studio-2012-code-analysis-cri[2]

 

C++ Code analysis – conclusion

 

These last samples impress me. For decades, we were debugging code to find memory overflow in code! And these examples only demonstrate a part of the awesome power of the C++ Code analyzer of Visual Studio 2012. The analyzer will be included in all Visual Studio 2012 versions, including Visual C++ 2012 express, as explained in the Code Analysis talk at Build conference.

One of the conclusions we can draw is you must not use * pointers, operators new and delete anymore, but use C++11 smart pointers . If you are not using shared_ptr or unique_ptr  today, it is essential for you to get started. Smart pointers are really safer than C-style * pointers.

With the new features of C++11 and this new C++ Code analysis feature, it will be very difficult to write unsafe C++ code!

7 thoughts on “C++ code analysis in Visual Studio 2012

  1. Pingback: L’analyse de code C++ dans Visual Studio 2012 : un outil puissant | BlogMFC

  2. Pingback: Windows Client Developer Roundup 085 for 11/28/2011 - Pete Brown's 10rem.net

  3. Comparing VS2010 and PVS studio is very interesting. Maybe a new comparison with VS2012 ?

  4. Why do you say that code analysis is only available with VS 2010 Ultimate? I think that it is also available in VS 2010 Premium. What I really asking is what does Ultimate add in the area of code analysis?

  5. You are right, code analysis is available in VS2010 premium as well. I fixed that in the article, thanks for your comment. I’m not sure there is a difference in code analysis between VS2010 premium and Ultimate, if this is what you are asking.