C++ Core Guidelines Checker in Visual Studio 2017

This post written by Sergiy Oryekhov and Andrew Pardoe

The C++ Core Guidelines can help improve your code and decrease your cost of maintenance by offering a wide range of recommendations: encouraging use of the standard library, avoiding use of unsafe practices whenever possible, maintaining a consistent style, and helping you to enforce reasonable design decisions. The number of Core Guidelines recommendations may look discouraging for those who own legacy code, but even a gradual cleanup process will provide immediate improvements to your code without requiring a total rewrite.

We’ve implemented a set of code analysis checks in Visual Studio that should help you to start moving towards safer code. We are continuing to improve these checks and add more checks specific to the C++ Core Guidelines, but the current set allows you to start today on the work of making existing code better and adopting new standards of writing modern C++.

The C++ Core Guidelines Checker is not new: it was released as a NuGet package first, and it is included in Visual Studio 2017.  It’s built on top of the C++ code analysis tools that are included in all editions of Visual Studio.

In Visual Studio 2017 15.3 we added more checks and fixed several bugs. We’ll provide more details about these checks in future blog posts. In this post we’ll take a quick look at how to use the tool and the kind of problems it can catch.

Running the C++ Core Guidelines Checker

The checker is a part of the C++ code analysis tools. Let’s assume we have a native C++ project. To enable code analysis, we can use the IDE:

  • Select the project and in the context menu choose ‘Properties’.
  • In the ‘Configuration Properties’ tree expand the ‘Code Analysis’ node.
  • On the ‘General’ tab check ‘Enable Code Analysis on Build’.

Enable Code Analysis on Build

  • Switch to the ‘Extensions’ node and enable ‘C++ Core Check (Released)’.

Select C++ Core Check (Released)

  • Save properties.
  • Now, each effective build of the project (when there is any change) should run code analysis with extended checks.

Filtering rules

If you are interested in viewing a subset of rules you can use rulesets to manage the warnings you will see for a project. Use the same ‘General’ tab (see “How to run C++ Core Check”) to pick an appropriate ruleset and then rebuild your project:

Select C++ Core Check Type Rules

You can also get more granular control over the rules by using macros in combination with #pragma warning. For example, here’s how to enable only the type-safety rules:

#include <CppCoreCheck/Warnings.h>
#pragma warning(disable: ALL_CPPCORECHECK_WARNINGS)
#pragma warning(default: CPPCORECHECK_CONST_WARNINGS)

You can also enable individual rules to make it easier to handle when code produces a lot of results:

#pragma warning(default: WARNING_NO_REINTERPRET_CAST)

Problems detected by the C++ Core Guidelines Checker

What kind of problems can be detected by the C++ Core Guidelines Checker? Here’s a sample of rules that are available in the checker. The issues detected by these rules are usually scoped and can be fixed without large code churn. You can focus on one kind of warnings and resolve them one file at a time.

Some of the following fixes make use of a small library of facilities, known as the Guidelines Support Library, designed to support the C++ Core Guidelines.

  • Unsafe type conversions:
    // Don't use reinterpret_cast. It is hard to maintain safely.
    auto data = reinterpret_cast<char*>(buffer);
    

    The following fix can be applied here:

    // To avoid buffer overruns use gsl::as_writeable_bytes which returns gsl::span.
    auto data = gsl::as_writeable_bytes<int>(gsl::make_span(buffer));
    
  • Unsafe low-level resource management:
    // Avoid calling new and delete explicitly. Unique pointers are safer.
    auto buffer = new int[buffer_size];
    if (read_data(buffer, buffer_size) == read_status::insufficient_space)
        // Likely leaking memory here unless read_data deallocates it.
        buffer = new int[max_buffer_size];
    if (read_data(buffer, max_buffer_size) == read_status::insufficient_space)
    {
        delete[] buffer;
        return nullptr;
    }
    

    To avoid problems with memory management we can rewrite this code:

    // std::unique_pointer will own and manage this object and dispose of it
    auto buffer = std::make_unique<int[]>(buffer_size);
    if (read_data(buffer.get(), buffer_size) == read_status::insufficient_space)
        buffer = std::make_unique<int[]>(max_buffer_size);
    if (read_data(buffer.get(), max_buffer_size) == read_status::insufficient_space)
        return nullptr;
    
  • Missing constness specifications which may lead to unexpected data modifications with later code changes:
    // If variable is assigned only once, mark it as const.
    auto buffer_size = count * sizeof(data_packet);
    auto actual_size = align(buffer_size);
    if (use_extension)
        actual_size += extension_size;
    encrypt_bytes(buffer, actual_size);
    

    The fix is trivial:

    // Now buffer_size is protected from unintentional modifications.
    const auto buffer_size = count * sizeof(data_packet);
    
  • C++ Core Guidelines Checker can even detect many complex problems such as this code that is missing resource cleanup in one of the code paths. In this example the code is using a gsl::owner type from the C++ Core Guidelines GSL.
    gsl::owner<int*> sequence = GetRandomSequence(); // This is not released.
    try
    {
        StartSimulation(sequence);
    }
    catch (const std::exception& e)
    {
        if (KnownException(e))
            return;                                  // Skipping resource cleanup here.
    
        ReportException(e);
    }
    delete [] sequence;
    

    In this case GetRandomSequence() should be redesigned to return a smart pointer instead of gsl::owner so that it is automatically released when it goes out of scope.

In closing

Good tools can help you to maintain and upgrade your code. The C++ Core Guidelines are a great place to start, and the C++ Core Guidelines Checker can help you to clean up your code and keep it clean. Try out the C++ Core Guidelines Checker in Visual Studio 2017 and let us know what you think!

If you have any feedback or suggestions for us, let us know. We can be reached via the comments below, via email (visualcpp@microsoft.com) and you can provide feedback via Help > Report A Problem in the product, or via Developer Community. You can also find us on Twitter (@VisualC) and Facebook (msftvisualcpp).