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 e segurança dos programas. A partir de Visual Studio versão 16.9 de 2019, o compilador Microsoft C/C++ (MSVC) e o IDE suportam o desinfetador AddressSanitizer. AddressSanitizer (ASan) é um compilador e tecnologia de tempo de execução que expõe muitos bugs difíceis de encontrar com zero falsos positivos:

Por que usar o AddressSanitizer

Use o AddressSanitizer para reduzir o tempo gasto em:

  • Correção básica
  • Portabilidade multiplataforma
  • Segurança
  • Testes de esforço
  • Integração de novo código

O AddressSanitizer, originalmente introduzido pelo Google, fornece tecnologias de deteçã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 builds

AddressSanitizer é integrado com o sistema de projeto Visual Studio, o sistema de compilação CMake e o IDE. Os projetos podem ativar o AddressSanitizer definindo uma propriedade de projeto ou usando uma opção adicional de compilador: /fsanitize=address. Esta 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 edição e continuação, vinculação incremental e /RTC.

Suporte para despejo de falhas

A partir da versão 16.9 do Visual Studio 2019, 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 memória quando o sanitizer encontrar um bug no tempo de execução. Se definires a variável de ambiente ASAN_SAVE_DUMPS=MyFileName.dmp antes de executares o teu programa, será criado um ficheiro de despejo com metadados extra para uma depuração post-mortem eficiente de bugs diagnosticados com precisão. Esses arquivos de despejo tornam o uso estendido de AddressSanitizer mais fácil para:

  • Testes de máquinas locais
  • Testes distribuídos no local
  • Fluxos de trabalho baseados na nuvem para testes

Instalar AddressSanitizer

As cargas de trabalho C++ no Visual Studio Installer instalam as bibliotecas AddressSanitizer e a integração 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 a ASan após a atualização. Pode abrir o instalador a partir do menu principal Visual Studio selecionando Tools>Get Tools and Features. Escolha Modificar na sua instalação de Visual Studio existente a partir do Instalador Visual Studio para aceder ao ecrã seguinte.

Captura de ecrã que mostra o Instalador do Visual Studio com o componente C++ AddressSanitizer, na secção Opcional, destacado.

Observação

Se executares o Visual Studio na nova atualização mas ainda não instalares o ASan, recebes um erro quando executas o teu código:

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

Utilize o AddressSanitizer

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

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

Recompile o seu código e depois execute o seu programa normalmente para expor muitos tipos de bugs diagnosticados com precisão. Pode consultar os problemas no IDE do depurador, na linha de comandos ou no ficheiro de despejo.

A Microsoft recomenda que você use 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 dependente da plataforma Windows 10 (e posterior) do AddressSanitizer. Esta documentação complementa a documentação da Google, Apple e GCC.

Observação

O suporte é limitado a x86 e x64 no Windows 10 e posterior. Envie-nos feedback sobre o que você gostaria de ver em versões futuras. Seu feedback nos ajuda a priorizar outros sanitizantes para o futuro, como /fsanitize=thread, /fsanitize=leak, /fsanitize=memory, /fsanitize=undefinedou /fsanitize=hwaddress. Você pode relatar bugs aqui se tiver problemas.

Use AddressSanitizer em um prompt de comando do desenvolvedor

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

Observação

O AddressSanitizer não suporta otimização guiada por perfil (PGO). AddressSanitizer não deve ser usado na produção.

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

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 comandos de programador para Visual Studio 2019, compila basic-global-overflow.cpp usando /fsanitize=address /Zi.

Captura de ecrã que mostra uma linha de comandos com o comando `cl basic-global-overflow.cpp /fsanitize=address /Zi`.

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

Considere as caixas vermelhas sobrepostas que destacam sete informações-chave:

Captura de ecrã do depurador a mostrar um erro básico de overflow global.

Destaques vermelhos, de cima para baixo

  1. O bug 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. O armazenamento ocorreu na função main() definida no ficheiro 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. Esta variável x global tem um tamanho de 400 bytes.
  6. O byte sombra exato que descreve o endereço alvo da loja tinha um valor de 0xf9.
  7. A legenda dos bytes de sombra indica que 0xf9 é uma área de preenchimento à direita de int x[100].

Observação

Quando o AddressSanitizer reporta um erro, o runtime ASan invoca o simbolizador LLVM para produzir os nomes das funções na pilha de chamadas.

Utilizar AddressSanitizer no Visual Studio

AddressSanitizer é integrado com o IDE do Visual Studio. Para ativar o AddressSanitizer para um projeto MSBuild, clique com o botão direito do mouse no projeto no Gerenciador de Soluções e escolha Propriedades. Na caixa de diálogo Property Pages, selecione Configuration Properties>C/C++>Generale, em seguida, modifique a propriedade Enable AddressSanitizer. Escolha OK para salvar as alterações.

Captura de tela da caixa de diálogo Páginas de propriedades mostrando a propriedade Enable AddressSanitizer.

Para criar a partir do IDE, desative todas as opções incompatíveis. Para um projeto existente compilado usando /Od (ou modo Debug), pode ser necessário desligar estas opções:

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

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

Use AddressSanitizer do Visual Studio: CMake

Para habilitar o AddressSanitizer para um projeto CMake criado para o Windowsde destino, siga estas etapas:

  1. Abra o menu suspenso Configurações na barra de ferramentas no topo do IDE e selecione Gerir Configurações.

    Captura de ecrã que mostra o menu suspenso de configuração do CMake que mostra opções como x64 Debug, x64 Release e, no final da lista, Gerir Configurações... está destacado.

    Essa ação abre o editor de Definições do Projeto do CMake, que reflete os conteúdos do ficheiro CMakeSettings.json do seu projeto.

  2. Escolha o link Editar JSON. Esta seleção muda a exibição para JSON bruto.

  3. Para ativar o AddressSanitizer, adicione o seguinte trecho à 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 funciona caso "edit-and-continue" seja especificado (/ZI), o qual é ativado por omissão para novos projetos CMake. Em CMakeLists.txt, comente (prefixo com #) a linha que começa com set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT". Essa frase é mais ou menos assim:

    # 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 guardar este ficheiro JSON.

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

  7. Substitua o conteúdo do ficheiro fonte, por exemplo, CMakeProject1.cpp, pelo 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 ambiente de depuração.

    Esta captura de tela captura o erro da compilação CMake.

    Captura de ecrã que mostra uma exceção com a mensagem: Erro do AddressSanitizer: transbordo global do buffer.

AddressSanitizer relatórios de falhas

O AddressSanitizer inclui funcionalidades para utilização com fluxos de trabalho na cloud e distribuídos. Essa funcionalidade permite a visualização offline de um erro AddressSanitizer no IDE. O erro é sobreposto sobre sua fonte, assim como você experimentaria em uma sessão de depuração ao vivo.

Estes ficheiros de despejo podem levar a eficiências quando se analisa um bug. Não precisas de reexecutar, encontrar dados remotos ou procurar uma máquina que tenha ficado offline.

Para produzir um ficheiro dump que possas visualizar no Visual Studio noutra máquina numa data posterior:

set ASAN_SAVE_DUMPS=MyFileName.dmp

A partir do Visual Studio 16.9, pode mostrar um erro precisamente diagnosticado, armazenado no seu ficheiro *.dmp, por cima do seu código-fonte.

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

Exemplos de erros

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

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

Diferenças com Clang 12.0

MSVC atualmente difere do Clang 12.0 em duas áreas funcionais:

  • Stack-use-after-scope: Esta definição está ativada por defeito e não pode ser desligada.
  • stack-use-after-return: esta funcionalidade requer uma opção extra do compilador, e não está disponível apenas ao definir ASAN_OPTIONS.

Essas decisões foram tomadas para reduzir a matriz de teste necessária para entregar esta 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 testes eficazes necessária para assegurar a interoperabilidade com décadas de código existente. Mais capacidades poderão ser consideradas em versões futuras:

Para obter mais informações, consulte Building for AddressSanitizer with MSVC.

Documentação da indústria

Existe uma documentação extensa para estas implementações dependentes da linguagem e da plataforma da tecnologia AddressSanitizer.

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

Ver também