错误:global-buffer-overflow

地址擦除器错误:全局缓冲区溢出

编译器为 .data.bss 部分中的任何变量生成元数据。 这些变量具有全局或文件静态的语言范围。 在 main() 启动之前,它们会分配在内存中。 C 中的全局变量与 C++ 中的处理方式大相径庭。 之所以存在这种差异,是因为链接 C 的复杂规则。

在 C 中,全局变量可以在多个源文件中声明,每个定义可以有不同的类型。 编译器一次看不到所有可能的定义,但链接器可以。 对于 C,链接器默认从所有不同声明中选择最大大小的变量。

在 C++ 中,全局变量由编译器分配。 只能有一个定义,因此每个定义的大小在编译时都是已知的。

示例 -“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

生成的错误

Screenshot of debugger displaying global-buffer-overflow error in example 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

生成的错误 - 简单函数级别静态

Screenshot of debugger displaying global-buffer-overflow error in example 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++ 中的所有全局范围

Screenshot of debugger displaying global-buffer-overflow error in example 3.

另请参阅

AddressSanitizer 概述
AddressSanitizer 已知问题
AddressSanitizer 生成和语言参考
AddressSanitizer 运行时参考
AddressSanitizer 阴影字节
AddressSanitizer 云或分布式测试
AddressSanitizer 调试程序集成
AddressSanitizer 错误示例