エラー: global-buffer-overflow

Address Sanitizer エラー: グローバル バッファー オーバーフロー

コンパイラは、任意の変数のメタデータを .data セクションまたは .bss セクション内に生成します。 これらの変数は、グローバルまたはファイルの静的言語のスコープを持ちます。 これらは、main() が開始される前にメモリに割り当てられます。 C のグローバル変数は、C++ とは大きく異なる方法で処理されます。 この違いは、C をリンクするための複雑なルールが原因です。

C では、グローバル変数はいくつかのソース ファイルで宣言できます。また、各定義は異なる型を持つことができます。 コンパイラは、使用可能なすべての定義を一度に見ることはできませんが、リンカーはできます。 C の場合、リンカーは既定で、すべての異なる宣言から最大サイズの変数を選択します。

C++ では、グローバルはコンパイラによって割り当てられます。 定義は 1 つしか存在できないため、コンパイル時に各定義のサイズがわかっています。

例: 複数の型定義を持つ 'C'' のグローバル

// file: a.c
int x;
// file: b.c
char* x;
// file: c.c
float* x[3];
// file: example1-main.c
// global-buffer-overflow error

// AddressSanitizer reports a buffer overflow at the first line
// in function main() in all cases, REGARDLESS of the order in 
// which the object files: a.obj, b.obj, and c.obj are linked.
  
double x[5];
 
int main() { 
    int rc = (int) x[5];  // Boom!
    return rc; 
}

この例をビルドしてテストするには、Visual Studio 2019 バージョン 16.9 以降の開発者コマンド プロンプトで次のコマンドを実行します。

cl a.c b.c c.c example1-main.c /fsanitize=address /Zi
devenv /debugexe example1-main.exe

結果のエラー

例 1 のグローバル バッファー オーバーフロー エラーが表示されているデバッガーのスクリーンショット。

例: 単純な関数レベル静的

// example2.cpp
// global-buffer-overflow error
#include <string.h>

int 
main(int argc, char **argv) {

    static char XXX[10];
    static char YYY[10];
    static char ZZZ[10];

    memset(XXX, 0, 10); memset(YYY, 0, 10); memset(ZZZ, 0, 10);

    int res = YYY[argc * 10];  // Boom!

    res += XXX[argc] + ZZZ[argc];
    return res;
}

この例をビルドしてテストするには、Visual Studio 2019 バージョン 16.9 以降の開発者コマンド プロンプトで次のコマンドを実行します。

cl example2.cpp /fsanitize=address /Zi
devenv /debugexe example2.exe

生成されたエラー: 単純な関数レベル静的

例 2 のグローバル バッファー オーバーフロー エラーが表示されているデバッガーのスクリーンショット。

例: C++ のすべてのグローバル スコープ

// example3.cpp
// global-buffer-overflow error

// Run 4 different ways with the choice of one of these options:
//
// -g : Global
// -c : File static
// -f : Function static
// -l : String literal

#include <string.h>

struct C {
    static int array[10];
};

// normal global
int global[10];

// class static
int C::array[10];

int main(int argc, char **argv) {

    int one = argc - 1;

    switch (argv[1][1]) {
    case 'g': return global[one * 11];     //Boom! simple global
    case 'c': return C::array[one * 11];   //Boom! class static
    case 'f':
    {
        static int array[10] = {};
        return array[one * 11];            //Boom! function static
    }
    case 'l':
        // literal global ptr created by compiler
        const char *str = "0123456789";
        return str[one * 11];              //Boom! .rdata string literal allocated by compiler
    }
    return 0;
}

この例をビルドしてテストするには、Visual Studio 2019 バージョン 16.9 以降の開発者コマンド プロンプトで次のコマンドを実行します。

cl example3.cpp /fsanitize=address /Zi
devenv /debugexe example3.exe -l

結果のエラー: C++ のすべてのグローバル スコープ

例 3 のグローバル バッファー オーバーフロー エラーが表示されているデバッガーのスクリーンショット。

関連項目

AddressSanitizer の概要
AddressSanitizer の既知の問題
AddressSanitizer のビルドと言語リファレンス
AddressSanitizer ランタイム リファレンス
AddressSanitizer シャドウ バイト
AddressSanitizer クラウドまたは分散テスト
AddressSanitizer デバッガーの統合
AddressSanitizer エラーの例