Main Content

CERT C: Rule MSC40-C

Do not violate constraints

Description

Rule Definition

Do not violate constraints.1

Polyspace Implementation

The rule checker checks for Inline constraint not respected.

Examples

expand all

Issue

Inline constraint not respected occurs when you refer to a file scope modifiable static variable or define a local 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 modifiable static 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) {
   static int var = 0;
   var += g_step;
}

Risk

When you modify a static variable in multiple function calls, you expect to modify the same variable in each call. For instance, each time you call func, the same instance of var1 is incremented but a separate instance of var2 is incremented.

void func(void) {
   static var1 = 0;
   var2 = 0;
   var1++;
   var2++;
}

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

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 - Static Variable Use in Inlined and External Definition
/* file1. c  : contains inline definition of get_random()*/

inline unsigned int get_random(void) 
{

    static unsigned int m_z = 0xdeadbeef;  //Noncompliant
    static unsigned int m_w = 0xbaddecaf;  //Noncompliant

    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16); 
    m_w = 18000 * (m_w & 65535) + (m_w >> 16); 
    return (m_z << 16) + m_w;   
}


int call_get_random(void)
{
    unsigned int rand_no;
    int ii;
    for (ii = 0; ii < 100; ii++) {
         rand_no = get_random();
    }
    rand_no = get_random();
    return 0;
}
/* file2. c  : contains external definition of get_random()*/

extern unsigned int get_random(void)
{
    /* Initialize seeds */
    static unsigned int m_z = 0xdeadbeef;
    static unsigned int m_w = 0xbaddecaf;
    
    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;
}

In this example, get_random() has an inline definition in file1.c and an external definition in file2.c. When get_random is called in file1.c, compilers are free to choose whether to use the inline or the external definition.

Depending on the definition used, you might or might not modify the version of m_z and m_w in the inlined version of get_random(). This behavior contradicts the usual expectations from a static variable. When you call get_random(), you expect to always modify the same m_z and m_w.

Correction — Make Inlined Function Static

One possible correction is to make the inlined get_random() static. Irrespective of your compiler, calls to get_random() in file1.c then use the inlined definition. Calls to get_random() in other files use the external definition. This fix removes the ambiguity about which definition is used and whether the static variables in that definition are modified.

/* file1. c  : contains inline definition of get_random()*/

static inline unsigned int get_random(void) 
{

    static unsigned int m_z = 0xdeadbeef; 
    static unsigned int m_w = 0xbaddecaf; 

    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16); 
    m_w = 18000 * (m_w & 65535) + (m_w >> 16); 
    return (m_z << 16) + m_w;   
}


int call_get_random(void)
{
    unsigned int rand_no;
    int ii;
    for (ii = 0; ii < 100; ii++) {
         rand_no = get_random();
    }
    rand_no = get_random();
    return 0;
}
/* file2. c  : contains external definition of get_random()*/

extern unsigned int get_random(void)
{
    /* Initialize seeds */
    static unsigned int m_z = 0xdeadbeef;
    static unsigned int m_w = 0xbaddecaf;
    
    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;
}

Check Information

Group: Rule 48. Miscellaneous (MSC)

Version History

Introduced in R2019a


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.