Compartilhar via


Erro: global-buffer-overflow

Erro do Sanitizador de Endereço: estouro de buffer global

O compilador gera metadados para qualquer variável nas seções .data ou .bss. Essas variáveis têm escopo de linguagem de estático global ou de arquivo. Eles são alocados na memória antes main() de começar. As variáveis globais em C são tratadas de forma muito diferente da do C++. Essa diferença ocorre devido às regras complexas para vincular C.

Em C, uma variável global pode ser declarada em vários arquivos de origem e cada definição pode ter tipos diferentes. O compilador não pode ver todas as definições possíveis de uma só vez, mas o vinculador pode. Para C, o vinculador usa como padrão selecionar a variável de maior tamanho de todas as diferentes declarações.

No C++, um global é alocado pelo compilador. Só pode haver uma definição, portanto, o tamanho de cada definição é conhecido no tempo de compilação.

Exemplo: globais em 'C' com várias definições de tipo

// 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; 
}

Para compilar e testar esse exemplo, execute estes comandos em um prompt de comando do desenvolvedor do Visual Studio 2019 versão 16.9 ou posterior:

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

Erro resultante

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

Exemplo: estático no nível de função simples

// 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;
}

Para compilar e testar esse exemplo, execute estes comandos em um prompt de comando do desenvolvedor do Visual Studio 2019 versão 16.9 ou posterior:

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

Erro resultante: estático no nível de função simples

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

Exemplo: todos os escopos globais no 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;
}

Para compilar e testar esse exemplo, execute estes comandos em um prompt de comando do desenvolvedor do Visual Studio 2019 versão 16.9 ou posterior:

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

Erro resultante: todos os escopos globais no C++

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

Confira também

Visão geral do AddressSanitizer
Problemas conhecidos do AddressSanitizer
Referência de linguagem e build do AddressSanitizer
Referência de runtime do AddressSanitizer
Bytes de sombra de AddressSanitizer
Nuvem do AddressSanitizer ou teste distribuído
Integração do depurador do AddressSanitizer
Exemplos de erro do AddressSanitizer