AddressSanitizer
Visão geral
As linguagens C & C++ são poderosas, mas podem sofrer de uma classe de bugs que afetam a correção e a segurança do programa. A partir do Visual Studio 2019 versão 16.9, o MSVC (compilador C/C++) e o IDE da Microsoft dão suporte ao desinfetante AddressSanitizer . AddressSanitizer (ASan) é um compilador e uma tecnologia de runtime que expõe muitos bugs difíceis de localizar com falsos positivos zero:
- Incompatibilidades alloc/dealloc e incompatibilidades de tipo
new
/delete
- Alocações muito grandes para o heap
calloc
estouro ealloca
estouro- Liberação dupla e Uso após liberação
- Estouro de variável global
- Estouro de buffer de heap
- Alinhamento inválido de valores alinhados
memcpy
estrncat
sobreposição de parâmetro- Estouro de buffer de pilha e estouro
- Uso de pilha após
return
e usar após o escopo - Uso de memória depois de envenenado
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.
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
. A nova 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, vinculação incremental e /RTC
.
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 antes de executar o programa, um arquivo de despejo ASAN_SAVE_DUMPS=MyFileName.dmp
de memória será criado com metadados extras para depuração post-mortem eficiente de bugs diagnosticados com precisão. 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 por meio de Ferramentas>Obter Ferramentas e Recursos... Escolha Modificar em sua instalação existente do Visual Studio no Instalador do Visual Studio para acessar a tela a seguir.
Observação
Se você executar o 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:
- Builds de linha de comando
- Sistema de projeto do Visual Studio
- Integração do CMake com o Visual Studio
Recompile e execute seu programa normalmente. Essa geração de código expõe muitos tipos de bugs diagnosticados com precisão. Esses erros são relatados de três maneiras: no IDE do depurador, na linha de comando ou armazenados em um novo tipo de arquivo de despejo para processamento offline preciso.
A Microsoft recomenda que você use o AddressSanitizer nestes três fluxos de trabalho padrão:
Loop interno do desenvolvedor
- Visual Studio - Linha de comando
- Visual Studio - Sistema de projeto
- Visual Studio – CMake
CI/CD – integração contínua/desenvolvimento contínuo
- Relatório de erros – Novos arquivos de despejo do AddressSanitizer
Fuzzing – compilando com o wrapper libFuzzer
- Azure OneFuzz
- Computador local
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 Windows 10 (e posterior) dependente da plataforma do AddressSanitizer. Esta documentação complementa a excelente documentação do Google, Apple e GCC já publicadas.
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 opção /fsanitize=address
é compatível com todos os níveis de otimização C++ ou C existentes (por exemplo, /Od
, /O1
, /O2
, /O2 /GL
e PGO
). 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.
As bibliotecas do AddressSanitizer (arquivos .lib) são vinculadas automaticamente. Para obter mais informações, consulte Referência de linguagem, build e depuração 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 comando do desenvolvedor para Visual Studio 2019, compile main.cpp
usando /fsanitize=address /Zi
Quando você executa o resultado main.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:
Há sete destaques vermelhos identificando as principais informações no relatório de erros. Eles são mapeados para a lista numerada que segue esta captura de tela. As caixas numeradas destacam o seguinte texto: 1) global-buffer-overflow 2) WRITE de tamanho 4 3) basic-global-overflow.cpp 7 4) à direita da variável global 'x' definida em 'basic-global-overflow.cpp:3:8' 5) de tamanho 400 6) 00 00[f9]f9 f9 7) A caixa está na área de legenda de byte de sombra e contém redzone global: f9
Destaques em vermelho, de cima para baixo
- O bug de segurança de memória é um estouro de buffer global.
- Havia 4 bytes (32 bits) armazenados fora de qualquer variável definida pelo usuário.
- O repositório ocorreu na função
main()
definida no arquivobasic-global-overflow.cpp
na linha 7. - A variável nomeada
x
é definida em basic-global-overflow.cpp na linha 3, começando na coluna 8 - Essa variável global
x
tem 400 bytes de tamanho - O byte de sombra exato que descreve o endereço direcionado pelo repositório tinha um valor de
0xf9
- A legenda do byte de sombra diz
0xf9
que é uma área de preenchimento à direita deint x[100]
Observação
Os nomes de função na pilha de chamadas são produzidos por meio do simbolizador LLVM invocado pelo runtime após o erro.
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.
Para compilar a partir do IDE, opte por todas as opções incompatíveis. Para um projeto existente compilado usando /Od
(ou modo de depuração), talvez seja necessário desativar estas opções:
- Desative editar e continuar
- Desative
/RTC1
(verificações de runtime) - Desative
/INCREMENTAL
(vinculação incremental)
Para compilar e executar o depurador, pressione F5. Uma janela Exceção Lançada aparece no Visual Studio:
Usar o AddressSanitizer do Visual Studio: CMake
Para habilitar o AddressSanitizer para um projeto do CMake criado para o Windows de destino, siga estas etapas:
Abra a lista suspensa Configurações na barra de ferramentas na parte superior do IDE e selecione selecione Gerenciar configurações.
Isso abre o editor de configurações do projeto do CMake, que reflete o conteúdo do arquivo do
CMakeSettings.json
seu projeto.Escolha o link Editar JSON no editor. Essa seleção alterna o modo de exibição para JSON bruto.
Adicione o seguinte snippet à predefinição, dentro
"configurePresets":
para ativar o"windows-base"
Address Sanitizer:"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" } },
O sanitizador de endereços não funcionará se editar e continuar for especificado (
/ZI
), que é habilitado por padrão para novos projetos do CMake. EmCMakeLists.txt
, comente (prefixo com#
) a linha que começa comset(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"
. Essa linha fica mais ou menos assim, depois:# set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
Digite Ctrl+S para salvar este arquivo JSON
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.
Substitua o conteúdo do arquivo de origem (por exemplo,
CMakeProject1.cpp
) pelo seguinte:// 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; }
Escolha F5 para recompilar e executar no depurador.
Esta captura de tela mostra o erro de build do CMake.
Despejos de falha do AddressSanitizer
Introduzimos uma nova funcionalidade no AddressSanitizer para uso com fluxos de trabalho distribuídos e na nuvem. Essa funcionalidade permite a exibição offline de um erro addressSanitizer no IDE. O erro é sobreposto sobre sua origem, assim como você experimentaria em uma sessão de depuração ao vivo.
Esses novos arquivos de despejo podem levar a eficiências ao analisar um bug. Você não precisa executar novamente, localizar dados remotos ou procurar um computador que ficou offline.
Para produzir um novo tipo de arquivo de despejo que pode ser exibido no Visual Studio em outro computador posteriormente:
set ASAN_SAVE_DUMPS=MyFileName.dmp
A partir do Visual Studio 16.9, você pode exibir um erro diagnosticado com precisão, armazenado em seu arquivo *.dmp
, além do código-fonte.
Essa nova funcionalidade de despejo de falhas 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
):
alloc-dealloc-mismatch
allocation-size-too-big
calloc-overflow
double-free
dynamic-stack-buffer-overflow
global-buffer-overflow
heap-buffer-overflow
heap-use-after-free
invalid-allocation-alignment
memcpy-param-overlap
new-delete-type-mismatch
stack-buffer-overflow
stack-buffer-underflow
stack-use-after-return
stack-use-after-scope
strncat-param-overlap
use-after-poison
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 de
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 funcionalidades podem ser consideradas em versões posteriores:
- Falha da ordem de inicialização
- Estouro dentro de objeto
- Estouro de contêiner
- Subtração/comparação de ponteiro
Para obter mais informações, consulte Criando para AddressSanitizer com MSVC.
Documentação existente do setor
Já 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
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