CXX.STATIC.OBJ.RECURSION

Do not reenter function during initialization of static objects

The C++ Standards states that "The zero-initialization of all block-scope variables with static storage duration or thread storage duration is performed before any other initialization takes place". If a function is reentered during the constant initialization of a static object inside that function, the behavior of the program is undefined.

Vulnerability and risk

Unordered initialization, especially prevalent across translation unit boundaries, results in unspecified behavior.

Mitigation and prevention

Prohibit recursion in the initialisation of static objects.

Vulnerable code example

Copy
int fact(int i) noexcept(false)
{ 
        if (i < 0) {
                // Negative factorials are undefined.
                throw std::domain_error("i must be >= 0");
        }
        
        static const int cache[] = {
                fact(0), fact(1), fact(2), fact(3), fact(4), fact(5),
                fact(6), fact(7), fact(8), fact(9), fact(10), fact(11),
                fact(12), fact(13), fact(14), fact(15), fact(16)
        };
        
        if (i < (sizeof(cache) / sizeof(int)))
        { 
                return cache[i];
        }
        
        return i > 0 ? i * fact(i - 1) : 1;
}

This above example attempts to implement an efficient factorial function using caching. Because the initialization of the static local array cache involves recursion, the behavior of the function is undefined, even though the recursion is not infinite.