C++ code analysis: configure rules from the command line

This post written by Sunny Chatterjee and Andrew Pardoe

Visual Studio version 15.7 Preview 3 introduces a new MSVC compiler switch, /analyze:ruleset, that configures code analysis runs. The primary motivation for this switch is to enable developers who are using C++ Code Analysis without using MSBuild to filter rules. But developers who are using code analysis with MSBuild also benefit from this switch: code analysis runs are faster, increasing your compilation throughput.

What are code analysis rulesets?

Code analysis rulesets allow you to choose what code analysis results you see when you analyze your code. Code analysis rulesets are found in Project > Properties > Code Analysis > General. A new C++ project by default has the ruleset “Microsoft Native Recommended Rules” selected.

You can select from rulesets you wish to apply to your project with the highlighted dropdown.

Visual Studio comes with a handful of built-in rulesets you can choose from. They’re located in %VSINSTALLDIR%\Team Tools\Static Analysis Tools\Rule Sets. We’re increasing this set of rules—stay tuned to the VC Blog for more information on this.

You can also create your own custom ruleset and apply that for your project. To create a custom ruleset, go to File > New > File > General > Code Analysis Rule Set.

Prior to Visual Studio 2017 version 15.7 Preview 3, all rules are run every time you run C++ code analysis. When you run code analysis for a given project, checkers like C++ Core Check generate a list of defects. After code analysis finishes, there’s an MSBuild task which merges the list of defects together and filters them according to the ruleset selected for the project. You’re only shown the warnings that apply to your currently selected code analysis ruleset.

While the old mechanism works great if you are building inside VS environment, there are a couple of areas where it falls short. First, if you are using the VS compiler toolset in your custom build environment, you don’t get any configuration options through rulesets. You must write your own tool for filtering defects as per your needs. Second, inside the current VS environment itself, the ruleset filtering mechanism is essentially a post processing tool – the checkers do all the work to generate the defect, which then gets filtered out in the end. We added /analyze:ruleset in the MSVC compiler toolset to overcome these shortcomings in the code analysis experience.

How does /analyze:ruleset work?

The new /analyze:ruleset option can be used with any build configuration: inside or outside of VS, using MSBuild, Ninja, or a custom build system. This new option allows the compiler to directly filter out defects based on the set of rules specified in the ruleset. Now that the compiler has knowledge of what rules are active, it can pass on that knowledge to the individual checkers, so they can make smart decisions. For example, if the ruleset only specifies rules for type safety, more expensive checks like lifetimes can turn themselves off, so you only pay for what you need in terms of analysis cost. Not having to run unselected rules means that your code analysis experience is faster and more fluid.

Using /analyze:ruleset

Taking advantage of this new switch is simple: just define your own ruleset files and pass that option to the compiler when running code analysis. This is best illustrated with a step-by-step example. In this example, we’ll detect all the defects related to uninitialized variables in our program.

  1. First, we need to identify the set of rules which will detect uninitialized variables and memory. For this example, we pick two rules that’ll help us, C6001 and C26494.
  2. Now need to create a ruleset file which contains the set of rules you selected. We can do this in Visual Studio as shown above or we can manually create a ruleset by authoring a simple XML.
  3. Now we have a ruleset file that looks like below that we’ve saved as UninitVariable.ruleset.
    <?xml version="1.0" encoding="utf-8"?>
    <RuleSet Name="New Rule Set" Description=" " ToolsVersion="15.0">
      <Rules AnalyzerId="Microsoft.Analyzers.NativeCodeAnalysis" RuleNamespace="Microsoft.Rules.Native">
        <Rule Id="C6001" Action="Warning" />
        <Rule Id="C26494" Action="Warning" />
      </Rules>
    </RuleSet>
    
  4. For this example, our test file looks like below. We name it test.cpp.
    int f( bool b )
    {
       int i;
       if ( b )
       {
          i = 0;
       }
       return i; // i is unintialized if b is false
    }
    
  5. We run code analysis without any configuration option and observe the following warnings:
    E:\test>cl.exe /c test.cpp /analyze:plugin EspXEngine.dll
    
    Microsoft (R) C/C++ Optimizing Compiler Version 19.14.26329 for x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    test.cpp
    e:\test\test.cpp(8) : warning C6001: Using uninitialized memory 'i'.: Lines: 3, 4, 8
    e:\test\test.cpp(3) : warning C26494: Variable 'i' is uninitialized. Always initialize an object (type.5).
    e:\test\test.cpp(1) : warning C26497: The function 'f' could be marked constexpr if compile-time evaluation is desired (f.4).
    e:\test\test.cpp(1) : warning C26440: Function 'f' can be declared 'noexcept' (f.6).
    
  6. Next, we pass the additional compiler option to specify our custom ruleset for identifying uninitialized variables: /analyze:ruleset UninitVariable.ruleset.
    E:\test>cl.exe /c test.cpp /analyze:plugin EspXEngine.dll /analyze:ruleset UninitVariable.ruleset
    
    Microsoft (R) C/C++ Optimizing Compiler Version 19.14.26329 for x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    test.cpp
    e:\test\test.cpp(8) : warning C6001: Using uninitialized memory 'i'.: Lines: 3, 4, 8
    e:\test\test.cpp(3) : warning C26494: Variable 'i' is uninitialized. Always initialize an object (type.5).
    

With the /analyze:ruleset option, code analysis only runs the rules for uninitialized variables and the additional warnings which were not related to these rules don’t show up anymore.

In closing

We hope that you’ll find /analyze:ruleset option useful for configuring code analysis runs in your private build environments. We’ve started taking advantage of it already! For example, our code analysis targets file in Visual Studio now passes the /analyze:ruleset option to the compiler when running code analysis. This way we can optimize our checks based on the selected ruleset. We’ll be introducing new default rulesets in the future as well as providing support in Visual Studio to run C++ code analysis in build environments like CMake for Ninja and Visual Studio.

As always, we welcome your feedback. We can be reached via the comments below or via email (visualcpp@microsoft.com).

If you encounter other problems with MSVC in Visual Studio 2017 please let us know through Help > Report A Problem in the product, or via Developer Community. Let us know your suggestions through UserVoice. You can also find us on Twitter (@VisualC) and Facebook (msftvisualcpp).