AddressSanitizer

Visão geral

As linguagens C e C++ são poderosas, mas podem sofrer de uma classe de bugs que afetam a correção do programa e a segurança do programa. A partir do Visual Studio versão 16.9 de 2019, o compilador Microsoft C/C++ (MSVC) e o IDE dão suporte ao AddressSanitizer sanitizer. AddressSanitizer (ASan) é um compilador e uma tecnologia de runtime que expõe muitos bugs difíceis de localizar com falsos positivos zero:

Por que usar AddressSanitizer

Use AddressSanitizer para reduzir o tempo gasto em:

  • Correção básica
  • Portabilidade entre plataformas
  • Segurança
  • testes de estresse
  • Integrando novo código

O AddressSanitizer, originalmente introduzido pelo Google, fornece tecnologias de detecção de bugs em tempo de execução que usam seus sistemas de compilação existentes e ativos de teste existentes diretamente.

Integração e compatibilidade de build

O AddressSanitizer é integrado ao sistema de projetos do Visual Studio, ao sistema de build CMake e ao IDE. Os projetos podem habilitar o AddressSanitizer definindo uma propriedade de projeto ou usando uma opção de compilador extra: /fsanitize=address. Essa opção é compatível com todos os níveis de otimização e configurações de x86 e x64. No entanto, ele não é compatível com editar-e-continuar, linkagem incremental e /RTC.

Suporte a despejo de memória

A partir do Visual Studio 2019 versão 16.9, a tecnologia AddressSanitizer da Microsoft permite a integração com o IDE do Visual Studio. A funcionalidade pode, opcionalmente, criar um arquivo de despejo de falha quando o desinfetante encontrar um bug no runtime. Se você definir a variável de ambiente ASAN_SAVE_DUMPS=MyFileName.dmp antes de executar o programa, um arquivo de despejo será criado com metadados extras para depuração eficiente post-mortem de bugs precisamente diagnosticados. Esses arquivos de despejo facilitam o uso estendido do AddressSanitizer para:

  • Teste de máquina local
  • Testes distribuídos no local
  • Fluxos de trabalho baseados em nuvem para testes

Instalar o AddressSanitizer

As cargas de trabalho do C++ no Instalador do Visual Studio instalam as bibliotecas AddressSanitizer e a integração do IDE por padrão. No entanto, se você estiver atualizando de uma versão mais antiga do Visual Studio 2019, use o Instalador para habilitar o suporte ao ASan após a atualização. Você pode abrir o instalador no menu principal do Visual Studio selecionando Tools>Get Tools and Features. Escolha Modify na instalação de Visual Studio existente do instalador do Visual Studio para acessar a tela a seguir.

Captura de tela mostrando o Instalador do Visual Studio com o componente C++ AddressSanitizer, na seção Opcionais, destacado.

Observação

Se você executar Visual Studio na nova atualização, mas não tiver instalado o ASan, receberá um erro ao executar seu código:

LNK1356: não foi possível localiar a biblioteca 'clang_rt.asan_dynamic-i386.lib'

Usar o AddressSanitizer

Comece a criar seus executáveis com a opção /fsanitize=address do compilador usando qualquer um desses métodos comuns de desenvolvimento:

  • Compilações de linha de comando
  • Sistema de projeto do Visual Studio
  • Integração do CMake com o Visual Studio

Recompile seu código e execute seu programa normalmente para expor muitos tipos de bugs diagnosticados com precisão. Você pode analisar os problemas na IDE do depurador, na linha de comando ou no arquivo de dump.

A Microsoft recomenda que você use o AddressSanitizer nestes três fluxos de trabalho padrão:

Este artigo aborda as informações necessárias para habilitar os três fluxos de trabalho listados anteriormente. As informações são específicas para a implementação do AddressSanitizer, que é dependente da plataforma Windows 10 (e posterior). Esta documentação complementa a documentação do Google, apple e GCC.

Observação

O suporte é limitado a x86 e x64 no Windows 10 e posterior. Envie-nos comentários sobre o que você gostaria de ver em versões futuras. Seus comentários nos ajudam a priorizar outros sanitizers para o futuro, como /fsanitize=thread, /fsanitize=leak, /fsanitize=memory, /fsanitize=undefined ou /fsanitize=hwaddress. Você pode relatar bugs aqui se tiver problemas.

Usar o AddressSanitizer em um prompt de comando do desenvolvedor

Use a opção de compilador /fsanitize=address em um prompt de comando do desenvolvedor para habilitar a compilação para o runtime do AddressSanitizer. A /fsanitize=address opção é compatível com os níveis de otimização C++ ou C existentes, por exemplo, /Od, e /O1/O2/O2 /GL. A opção funciona com CRTs estáticos e dinâmicos (por exemplo, /MD, /MDd, /MT e /MTd). Ele funciona se você criar um EXE ou um DLL. As informações de depuração são necessárias para a formatação ideal das pilhas de chamadas. No exemplo a seguir, cl /fsanitize=address /Zi é passado na linha de comando.

Observação

O AddressSanitizer não dá suporte à PGO (otimização guiada por perfil). AddressSanitizer não deve ser usado na produção.

As bibliotecas do AddressSanitizer (arquivos .lib) são vinculadas automaticamente. Para mais informações, consulte AddressSanitizer: referência de linguagem, build e depuração.

Exemplo: estouro de buffer global básico

// basic-global-overflow.cpp
#include <stdio.h>
int x[100];
int main() {
    printf("Hello!\n");
    x[100] = 5; // Boom!
    return 0;
}

Usando um prompt de comando do desenvolvedor para Visual Studio 2019, compile basic-global-overflow.cpp usando /fsanitize=address /Zi.

Captura de tela mostrando um prompt de comando com o comando 'cl basic-global-overflow.cpp /fsanitize=address /Zi'.

Quando você executa o resultado basic-global-overflow.exe na linha de comando, ele cria o relatório de erro formatado a seguir.

Considere as caixas vermelhas sobrepostas que realçam sete partes principais de informações:

Captura de tela do depurador mostrando um erro de estouro global básico.

Destaques em vermelho, de cima para baixo

  1. O erro de segurança de memória é um estouro de buffer global.
  2. Havia 4 bytes (32 bits) armazenados fora de qualquer variável definida pelo usuário.
  3. A ação de armazenamento foi executada na função main() definida no arquivo basic-global-overflow.cpp na linha 7.
  4. A variável nomeada x é definida em basic-global-overflow.cpp na linha 3, começando na coluna 8.
  5. Essa variável x global tem tamanho de 400 bytes.
  6. O byte de sombra exato que descreve o endereço direcionado pelo repositório tinha um valor igual 0xf9a .
  7. A legenda do byte sombreado indica que 0xf9 é uma área de preenchimento à direita de int x[100].

Observação

Quando o AddressSanitizer relata um erro, o ambiente de execução do ASan invoca o simbolizador LLVM para gerar os nomes das funções na pilha de chamadas.

Usar o AddressSanitizer no Visual Studio

AddressSanitizer é integrado ao IDE do Visual Studio. Para ativar o AddressSanitizer para um projeto do MSBuild, clique com o botão direito do mouse no projeto no Gerenciador de Soluções e escolha Propriedades. Na caixa de diálogo Páginas de Propriedades, selecione Propriedades de Configuração>C/C++>Geral e, em seguida, modifique a propriedade Habilitar AddressSanitizer. Escolha OK para salvar suas alterações.

Captura de tela da caixa de diálogo das Páginas de Propriedade mostrando a propriedade Habilitar o AddressSanitizer.

Para compilar a partir do IDE, evite quaisquer opções incompatíveis. Para um projeto existente compilado usando /Od (ou modo de depuração), talvez seja necessário desativar estas opções:

Para compilar e executar o depurador, pressione F5. Uma janela Exceção Lançada aparece no Visual Studio:

Captura de tela de um depurador mostrando um erro de estouro de buffer global.

Use o AddressSanitizer do Visual Studio: CMake

Para habilitar o AddressSanitizer para um projeto do CMake criado para o Windows de destino, siga estas etapas:

  1. Abra o menu suspenso Configurações na barra de ferramentas na parte superior do IDE e selecione Gerenciar Configurações.

    Captura de tela mostrando o menu suspenso de configuração do CMake, que exibe opções como x64 Debug e x64 Release e, na parte inferior da lista, a opção Gerenciar Configurações..., que está destacada.

    Essa ação abre o editor de Configurações do Projeto do CMake, que reflete o conteúdo do arquivo CMakeSettings.json do seu projeto.

  2. Selecione o link Editar JSON. Essa seleção alterna o modo de exibição para JSON bruto.

  3. Para ativar o AddressSanitizer, adicione o trecho de código a seguir à predefinição "windows-base", dentro de "configurePresets":.

    "environment": {
      "CFLAGS": "/fsanitize=address",
      "CXXFLAGS": "/fsanitize=address"
    }
    

    "configurePresets" fica mais ou menos assim, depois:

        "configurePresets": [
          {
            "name": "windows-base",
            "hidden": true,
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "installDir": "${sourceDir}/out/install/${presetName}",
            "cacheVariables": {
              "CMAKE_C_COMPILER": "cl.exe",
              "CMAKE_CXX_COMPILER": "cl.exe"
            },
            "condition": {
              "type": "equals",
              "lhs": "${hostSystemName}",
              "rhs": "Windows"
            },
            "environment": {
              "CFLAGS": "/fsanitize=address",
              "CXXFLAGS": "/fsanitize=address"
            }
          },
    
  4. AddressSanitizer não funcionará se editar e continuar for especificado (/ZI), que está habilitado por padrão para novos projetos do CMake. Em CMakeLists.txt, comente (adicione o prefixo #) a linha que começa com set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT". Essa linha tem esta aparência:

    # set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
    
  5. Use Ctrl+S para salvar este arquivo JSON.

  6. Limpe o diretório de cache do CMake e reconfigure escolhendo no menu do Visual Studio: Excluir cache do projeto>e Reconfigurar. Escolha Sim quando o prompt aparecer para limpar o diretório de cache e reconfigurar.

  7. Substitua o conteúdo do arquivo de origem, por exemplo, CMakeProject1.cpppelo seguinte código:

    // CMakeProject1.cpp : Defines the entry point for the application
    
    #include <stdio.h>
    
    int x[100];
    
    int main()
    {
        printf("Hello!\n");
        x[100] = 5; // Boom!
        return 0;
    }
    
  8. Escolha F5 para recompilar e executar no depurador.

    Esta captura de tela mostra o erro gerado pelo CMake durante a compilação.

    Captura de tela mostrando uma exceção que diz: Erro do Address Sanitizer: estouro de buffer global.

Relatórios de falha do AddressSanitizer

O AddressSanitizer inclui funcionalidade para uso com fluxos de trabalho distribuídos e de nuvem. Essa funcionalidade permite a exibição offline de um erro AddressSanitizer na IDE. O erro é sobreposto à sua fonte, assim como você veria em uma sessão de depuração ao vivo.

Esses arquivos de despejo podem aumentar a eficiência ao analisar um bug. Você não precisa executar novamente, encontrar dados remotos ou procurar um computador que ficou offline.

Para produzir um arquivo de despejo que você pode exibir em Visual Studio em outro computador em uma data posterior:

set ASAN_SAVE_DUMPS=MyFileName.dmp

A partir do Visual Studio 16.9, você pode exibir a erro diagnosticado com precisão, armazenado em seu arquivo *.dmp, além do código-fonte.

Essa funcionalidade de dump de falha permite fluxos de trabalho baseados em nuvem ou testes distribuídos. Ele também pode ser usado para arquivar um bug detalhado e acionável em qualquer cenário.

Erros de exemplo

O AddressSanitizer pode detectar vários tipos de erros de uso indevido de memória. Aqui estão muitos dos erros de runtime relatados quando você executa seus binários compilados usando a opção do compilador AddressSanitizer (/fsanitize=address):

Para obter mais informações sobre os exemplos, consulte exemplos de erro do AddressSanitizer.

Diferenças com o Clang 12.0

O MSVC atualmente é diferente do Clang 12.0 em duas áreas funcionais:

  • stack-use-after-scope: essa configuração está ativada por padrão e não pode ser desativada.
  • stack-use-after-return: essa funcionalidade requer uma opção de compilador extra e não está disponível apenas pela configuração ASAN_OPTIONS.

Essas decisões foram tomadas para reduzir a matriz de teste necessária para entregar essa primeira versão.

Recursos que poderiam levar a falsos positivos no Visual Studio 2019 16.9 não foram incluídos. Essa disciplina impôs a integridade de teste efetiva necessária ao considerar a interoperabilidade com décadas de código existente. Mais recursos podem ser considerados em versões posteriores:

Para obter mais informações, consulte Compilando com AddressSanitizer no MSVC.

Documentação do setor

Existe uma documentação abrangente para essas implementações dependentes de linguagem e plataforma da tecnologia AddressSanitizer.

Este artigo seminal sobre o AddressSanitizer (externo) descreve a implementação.

Confira também