You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 15 Next »

Do not define a modifiable object with static or thread storage duration in an external inline function, or reference an identifier with internal linkage.  The C Standard, subclause 6.7.4 paragraph 3, says:

An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage.

The motivation behind this constraint lies in the semantics of inline definitions. Paragraph 7 of 6.7.4 reads, in part:

An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.

That is, if a function has an external and inline definition, implementations are free to choose which definition to invoke (two distinct invocations of the function may call different definitions, one the external definition, the other the inline definition). Therefore, issues can arise when these definitions reference internally linked objects, or mutable objects with static/thread storage duration.

Noncompliant Code Example (Internal Linkage)

This code refers to a file scope static variable, which has internal linkage, inside an external inline function:

static int I = 12;
extern inline void func(int a) {
  int b = a * I;
  /* ... */
}

Compliant Solution (Internal Linkage)

This compliant solution omits the static qualifier;  consequently,  the variable I has external linkage by default.

int I = 12;
extern inline void func(int a) {
  int b = a * I;
  /* ... */
}

Noncompliant Code Example (Modifiable Static)

This noncompliant code example defines a modifiable static variable within an extern inline function.

extern inline void func(void) {
  static int I = 12;
  /* Perform calculations which may modify I */
}

Compliant Solution (Modifiable Static)

This compliant solution removes the static keyword from the local variable definition. If the modifications to I must be retained between invocations of func(), it must be declared at file scope so that it will be defined with external linkage.

extern inline void func(void) {
  int I = 12;
  /* Perform calculations which may modify I */
}

Noncompliant Code Example (Modifiable static)

In this code example, we have two translation units, file1.c and file2.c. file1.c defines a random number generation function. A programmer creates file2.c and opts to define an inline version of this function, and simply copies and pastes the function body. However, the function references mutable static objects, namely objects that maintain the state of the random number generator. Separate invocations of the get_random() function may call different definitions, resulting in a faulty random number generator (because each definition operates on separate static objects).

/* file1.c */

/* Externally linked definition of the function get_random */
extern unsigned int get_random() {
  /* Initialize the seeds */
  static unsigned int m_z = 0xdeadbeef;
  static unsigned int m_w = 0xbaddecaf;

  /* Compute the next random value and update the 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;
}
/* file2.c */

/* Inline definition of get_random function */
inline unsigned int get_random() {
  /* Initialize the seeds 
     Constraint violation: static duration storage referenced
     in non-static inline definition */
  static unsigned int m_z = 0xdeadbeef;
  static unsigned int m_w = 0xbaddecaf;

  /* Compute the next random value and update the 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 main() {
  unsigned int rand_no;
  for (int ii = 0; ii < 100; ii++) {
  /* Get a random number.  Implementation defined whether the
     inline definition in this file or the external definition  
     in file2.c is called. */
    rand_no = get_random();
    /* Use rand_no... */
  }

  /* ... */

  /* Get another random number.  Same comment from above applies here. */
  rand_no = get_random();
  /* Use rand_no... */
  return 0;
}

Compliant Solution (Modifiable static)

This compliant solution adds the static modifier to the inline function definition in file2.c, thus internally linking this definition. Now all references to get_random() in file.2.c will reference the internally linked definition.

/* file1.c */

/* Externally linked definition of the function get_random. */
extern unsigned int get_random() {
  /* Initialize the seeds */
  static unsigned int m_z = 0xdeadbeef;
  static unsigned int m_w = 0xbaddecaf;

  /* Compute the next random value and update the 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;
}
/* file2.c */

/* Static inline definition of get_random function */
static inline unsigned int get_random() {
  /* Initialize the seeds 
     No more constraint violation, our inline function is now 
     internally linked. */
  static unsigned int m_z = 0xdeadbeef;
  static unsigned int m_w = 0xbaddecaf;

  /* Compute the next random value and update the 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 main() {
  /* Generate a bunch of random numbers using get_random()... */
  return 0;
}

Risk Assessment

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

DCL41-C

Low

Unlikely

Medium

P2

L3

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Bibliography

[ISO/IEC 9899:2011]Subclause 6.7.4, "Function Specifiers"

 


  

  • No labels