C++ Core Check improvements in Visual Studio 2017 15.5


This post was written by Sergiy Oryekhov.

In Visual Studio 2017 version 15.5 Preview 4 we have refreshed our C++ Core Guidelines Check extension for native code static analysis tools. Most of the work since 15.3 has been focused on new rules that will help developers starting new projects write safer C++ and those with legacy projects move toward safer, modern C++. For those who are new to the core guidelines checks, we recommend to review the latest version of the working draft: “C++ Core Guidelines“.

This article provides an overview of the changes in VS2017 15.5. For more information about the current release, please see the list of supported rule sets on docs.microsoft.com.

Note that some of the links to docs.microsoft.com do not yet resolve. Not all of the official documentation has yet been written for this topic.

New rule sets

In the previous release we introduced several rule sets to allow customers to narrow code analysis results. The rules implemented for 15.5 extended some of the existing rule sets (Raw Pointer, Owner Pointer, Unique Pointer, Type), and also introduced a few new categories:

  • Class rules: This section includes a few rules mostly focused on proper use of special methods and virtual specifications. This is a subset of checks recommended for classes and class hierarchies.
  • Concurrency rules: This currently includes a single rule which catches badly declared guard objects. For more information see Core Guidelines related to concurrency.
  • Declaration rules: Here are a couple of rules from the interfaces guidelines which focus on how global variables are declared.
  • Function rules: These are two checks that help with adoption of the noexcept specifier. This is a part of the guidelines for clear function design and implementation.
  • Shared pointer rules: As a part of resource management guidelines enforcement, we added a few rules specific to how shared pointers are passed into functions or used locally.
  • Style rules: In this release we have one simple but important check which bans use of goto. This is the first step in improving of coding style and use of expressions and statements in C++. While there are exceptions in the C++ Core Guideline about goto, proper use of the construct is rare enough that it deserves review.

New rules in each set

  • Class rules

    • C26432 DEFINE_OR_DELETE_SPECIAL_OPS Special operations (e.g. destructors or copy constructors) imply special behavior and should come in complete sets to define such behavior clearly.
    • C26436 NEED_VIRTUAL_DTOR Having virtual methods suggests polymorphic behavior which requires more careful management of object cleanups.
    • C26434 DONT_HIDE_METHODS Hiding methods by names is like hiding variables. Naming should not lead to ambiguity.
  • Concurrency rules

  • Declaration rules

    • C26426 NO_GLOBAL_INIT_CALLS Calling a function from the initializer for a global variable may lead to unexpected results due to undefined order of initialization.
    • C26427 NO_GLOBAL_INIT_EXTERNS Global variables should not refer to external symbols to avoid initialization order problems.
  • Function rules

    • C26439 SPECIAL_NOEXCEPT Some of the special functions (like destructors) should avoid throwing exceptions.
    • C26440 DECLARE_NOEXCEPT If a function neither throws nor calls other functions that can throw, it should be marked as noexcept.
  • Resource management rules

    • C26416 NO_RVALUE_REF_SHARED_PTR Passing shared pointers by rvalue-reference is unnecessary and usually indicates a misuse of shared pointers. Shared pointers are safe and inexpensive to pass by value.
    • C26417 NO_LVALUE_REF_SHARED_PTR A shared pointer passed by reference acts as an output parameter, and it is expected that its ownership will be updated in the function (e.g. by calling reset()). If the shared pointer is only used to access its contained object, a plain reference or pointer to the contained object should be passed instead.
    • C26418 NO_VALUE_OR_CONST_REF_SHARED_PTR When a shared pointer is passed by value or reference to const, it indicates to the caller that the function needs to control the lifetime of its contained object without affecting the calling code. However, if the smart pointer is never copied, moved, or otherwise modified in a way that will affect the contained object’s lifetime, a plain reference or pointer to the contained object should be passed instead.
    • C26415 SMART_PTR_NOT_NEEDED Smart pointers are convenient for resource management, but when they are used only to access the contained object, the code may be simplified by passing plain references or pointers to the contained object instead.
    • C26414 RESET_LOCAL_SMART_PTR Using a local smart pointer implies the function needs to control the lifetime of the contained object. If a function does not use the smart pointer to pass ownership outside of the function and has no explicit calls to change ownership, a stack-allocated local variable should be used instead to avoid an unnecessary heap allocation.
    • C26429 USE_NOTNULL If a pointer is dereferenced but never tested for nullness, it may be useful to use gsl::not_null so that assumptions about its validity are properly asserted.
    • C26430 TEST_ON_ALL_PATHS If a pointer is dereferenced and tested in at least one path, the code should ensure it is tested on all paths since testing implies possibility that the pointer is null.
    • C26431 DONT_TEST_NOTNULL Testing for nullness of expressions of type gsl::not_null is obviously unnecessary.
  • Style rules

    • C26438 NO_GOTO Modern C++ should never use goto in user-written code.
  • Type rules

    • C26437 DONT_SLICE Even though compiler allows implicit slicing, it is usually unsafe and unmaintainable.
    • C26472 NO_CASTS_FOR_ARITHMETIC_CONVERSION Static casts can silently discard data which doesn’t fit into an arithmetic type.
    • C26473 NO_IDENTITY_CAST Casting between pointers of exactly same type is obviously unnecessary.
    • C26474 NO_IMPLICIT_CAST Casting should be omitted in cases where pointer conversion is done implicitly. Note, the rule ID is a bit misleading: it should be interpreted as “implicit cast is not used where it is acceptable”.
    • C26475 NO_FUNCTION_STYLE_CASTS Function-style cast is another form of a C-style cast and can lead to silent data truncation.

Warnings that were rearranged

Some warning numbers found in the VS2017 version 15.3 release are no longer available in VS2017 version 15.5. These warnings did not disappear, but were rather replaced with more specific checks. The primary goal was to separate particularly common patterns within a warning into separate warnings.

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 expanded C++ Core Guidelines Checker in Visual Studio 2017 version 15.5 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).