Main Content

CERT C++: DCL60-CPP

Obey the one-definition rule

Description

Rule Definition

Obey the one-definition rule.1

Polyspace Implementation

This checker checks for:

  • Inline constraint not respected

  • Nonidentical definitions of function or object across modules

Examples

expand all

Issue

Inline constraint not respected occurs when you refer to a file scope modifiable static variable in a nonstatic inlined function. The checker considers a variable as modifiable if it is not const-qualified.

For instance, var is a variable defined in an inline function func. g_step is a file scope modifiable static variable referred to in the same inlined function.

static int g_step;
inline void func (void) {
    int var = g_step++; // Violation
}

Risk

When you modify a static variable in multiple function calls, you expect to modify the same variable in each call. For instance, it is expected that each time func is called in the preceding code, the same instance of g_step is incremented.

If a function has an inlined and a noninlined definition in separate files, when you call the function, the C++ standard allows compilers to use either the inlined or the noninlined form (see ISO®/IEC 9899:2011, sec. 6.7.4). If your compiler uses an inlined definition in one call and the noninlined definition in another, you are no longer modifying the same variable in both calls. This behavior defies the expectations from a static variable and violates the one definition rule.

Fix

Use one of these fixes:

  • If you do not intend to modify the variable, declare it as const.

    If you do not modify the variable, there is no question of unexpected modification.

  • Make the variable non-static. Remove the static qualifier from the declaration.

    If the variable is defined in the function, it becomes a regular local variable. If defined at file scope, it becomes an extern variable. Make sure that this change in behavior is what you intend.

  • Make the function static. Add a static qualifier to the function definition.

    If you make the function static, the file with the inlined definition always uses the inlined definition when the function is called. Other files use another definition of the function. The question of which function definition gets used is not left to the compiler.

Example — File Scope static Variable Modified in inline Function

In this example, the inline function foo() increments the file scope static variable var and passes it by reference to myFunc. Polyspace® reports violations of this rule on these operations.

typedef int int32_t;
typedef const int cint32_t;
static int32_t var = 42;

int32_t myFunc(cint32_t &arg1, cint32_t &arg2);

inline int32_t foo(int32_t num)
{
  var++; //Noncompliant
  return myFunc(num, var);  //Noncompliant
}
Correction — Declare inline Function as static

To fix the violations of this rule, declare foo() as a static function. This clarification resolves ambiguity regarding the use of static variable.

typedef int int32_t;
typedef const int cint32_t;
static int32_t var = 42;

int32_t myFunc(cint32_t &arg1, cint32_t &arg2);

static inline int32_t foo(int32_t num)
{
  var++; // Compliant
  return myFunc(num, var);  // Compliant
}

Issue

Nonidentical definitions of function or object across modules occurs when a function or object is defined in multiple modules, but with differences in tokens like identifiers, keywords, literals, operators, punctuators, and other separators. The checker is not raised on unused code such as

  • Noninstantiated templates

  • Uncalled static or extern functions

  • Uncalled and undefined local functions

  • Unused types and variables

The checker does not flag this issue in a default Polyspace as You Code analysis. See Checkers Deactivated in Polyspace as You Code Analysis (Polyspace Access).

Risk

Having different definitions of the same object or noninlined function in different modules results in unexpected behavior. The program might crash and leak memory depending on the software and hardware that you use.

Fix

Define objects and noninlined functions without any differences in tokens. Use the same sequence and types of tokens in the definitions of objects and noninline functions across modules.

Example: Definition of Object Has Token Difference

This example uses two files:

  • file1.cpp:

    typedef struct S //Noncompliant
    {
       int x;
       int y;
    }S; 
    void foo(S& s){
    //...
    }
  • file2.cpp:

    typedef struct S 
    {
       int y;
       int x;
    }S ; 
    void bar(S& s){
    //...
    }

In this example, both file1.cpp and file2.cpp define the structure S. The definitions switch the order of the structure fields.

Correction: Use Identical Definition Across Modules

One possible correction is to define the structure S in a header file and include the header in the two modules.

  • S.h:

    struct S //Compliant
    {
       int x;
       int y;
    }; 
  • file1.cpp:

    #include"S.h" 
    void foo(S& s){
    //...
    }
  • file2.cpp:

    #include"S.h" 
    void bar(S& s){
    //...
    }

Check Information

Group: 01. Declarations and Initialization (DCL)

Version History

Introduced in R2019a

expand all


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.