CXX.STATIC.OBJ.RECURSION

静的オブジェクトの初期化中に関数を再入力しないでください

C++ 標準には、「静的ストレージ期間またはスレッドストレージ期間があるすべてのブロックスコープ変数のゼロ初期化は、他の初期化が行われる前に実行される」と示されています。関数内の静的オブジェクトの定数を初期化している間にその関数が再入力される場合、プログラムの動作は定義されていません。

脆弱性とリスク

順序付けられていない初期化は、変換単位の境界を越えて特に普及しており、未定義の動作を引き起こします。

軽減と防止

静的オブジェクトの初期化中に再帰を禁止します。

脆弱コード例

コピー
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;
}

上記の例では、キャッシュを使用して効率的な階乗関数を実装しようとしています。静的ローカル配列キャッシュの初期化には再帰が関わっているため、再帰が無限でなくても、関数の動作は未定義です。