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

Compare with Current View Page History

« Previous Version 18 Next »

If a function is reentered during the initialization of a static object inside that function, the behavior of the program is undefined. Please note that this problem is not the same as infinite recursion. For this problem to occur, a function only needs to recurse once.

[ISO/IEC 14882-2003] Section 6.7, "Declaration Statement" describes the initialization of static and thread storage duration objects. The direct quote is as follows:

The zero-initialization of all local objects with static storage duration or thread storage duration is performed before any other initialization takes place. Constant initialization of a local entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other local objects with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize an object with static or thread storage duration in namespace scope. Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the object is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the object is being initialized, the behavior is undefined.

Noncompliant Code Example

This noncompliant code example declares the variable y as a static int. The value of test( x) is assigned to y within the test(int x) function. However, when test(int x) is called with an input that results in reaching the initialization of y more than once, such as the value 12, undefined behavior occurs. Note that this code does not present an infinite recursion and still causes the undefined behavior mentioned.

int test (int x) {
  x--;
  if (x < 0 || x > 10) {
    return 0;
  }
  else {
    static int y = test(x);  //<--undefined behavior occurs here
    return y;
  }
}

Implementation-Specific Details

In the GCC Version 3 compiler, this code will recurse as if y were a non-static variable.

In the GCC Version 4 compiler, upon reaching the initialization of y for the second time, the program will terminate with the following message:

terminate called after throwing an instance of
'__gnu_cxx::recursive_init'
  what():  N9__gnu_cxx14recursive_initE
Aborted (core dumped)

Compliant Solution

In this compliant solution, y is declared before being assigned a value. According to [ISO/IEC 14882-2003] Section 6.7.4, the initialization of y will have been completed at the end of the declaration and before the assignment of a value, consequently removing the possibility of undefined behavior.

int test (int x) {
  x--;
  if (x < 0 || x > 10) {
    return 0;
  }
  else {
    static int y;
    y = test(x);  
    return y;
  }
}

Risk Assessment

Recursively reentering a function during the initialization of one of its static objects can result in an attacker being able to cause a crash or denial of service.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

DCL38-CPP

low

unlikely

medium

P2

L3

Related Vulnerabilities

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

Bibliography

[ISO/IEC 14882-2003] Section 6.7, "Declaration Statement"


DCL37-CPP. Overloaded postfix operators should return const      02. Declarations and Initialization (DCL)      03. Expressions (EXP)

  • No labels