Runtime do AddressSanitizer:
A biblioteca de runtime do AddressSanitizer intercepta funções e operações comuns de alocação de memória para habilitar a inspeção de acessos de memória. Há várias bibliotecas de runtime diferentes que dão suporte aos vários tipos de executáveis que o compilador pode gerar. O compilador e o vinculador associam automaticamente as bibliotecas de runtime apropriadas, desde que você passe a opção /fsanitize=address
no tempo de compilação. Você pode substituir o comportamento padrão usando a opção no momento da /NODEFAULTLIB
vinculação. Para obter mais informações, consulte a seção sobre vinculação na referência sobre linguagem, compilação e depuração do AddressSanitizer.
Ao compilar com cl /fsanitize=address
o , o compilador gera instruções para gerenciar e verificar bytes de sombra. Seu programa usa essa instrumentação para verificar os acessos de memória na pilha, no heap ou no escopo global. O compilador também produz metadados que descrevem variáveis globais e de pilha. Esses metadados permitem que o runtime gere um diagnóstico de erro preciso: nomes de função, linhas e colunas no código-fonte. Combinadas, as verificações do compilador e as bibliotecas de runtime podem diagnosticar precisamente muitos tipos de bugs de segurança de memória se forem encontrados em tempo de execução.
A lista de bibliotecas de runtime para vincular ao runtime AddressSanitizer, a partir do Visual Studio 17.7 Preview 3, a seguir. Para obter mais informações sobre as /MT
opções (vincular estaticamente o tempo de execução) e /MD
(vincular dinamicamente o redist em tempo de execução), consulte /MD, /MT, /LD (Usar biblioteca de tempo de execução).
Observação
Na tabela a seguir, {arch}
é ou i386
x86_64
.
Essas bibliotecas usam convenções Clang para nomes de arquitetura. As convenções MSVC são normalmente x86
e x64
em vez de i386
e x86_64
, mas se referem às mesmas arquiteturas.
Opção CRT | Biblioteca de tempo de execução AddressSanitizer (.lib) | Binário de tempo de execução de endereço (.dll) |
---|---|---|
/MT ou /MTd |
clang_rt.asan_dynamic-{arch} , clang_rt.asan_static_runtime_thunk-{arch} |
clang_rt.asan_dynamic-{arch} |
/MD ou /MDd |
clang_rt.asan_dynamic-{arch} , clang_rt.asan_dynamic_runtime_thunk-{arch} |
clang_rt.asan_dynamic-{arch} |
O diagrama a seguir mostra como as bibliotecas de tempo de execução de linguagem são vinculadas para as /MT
opções , /MTd
, /MD
, e /MDd
do compilador:
A imagem mostra três cenários para vincular a biblioteca de tempo de execução. O primeiro é /MT ou /MTd. My_exe.exe e my_dll.dll são mostrados com suas próprias cópias dos tempos de execução VCRuntime, Universal CRT e C++ vinculados estaticamente. Os cenários mostram /MD em que my_exe.exe e my_dll.dll compartilham vcruntime140.dll, ucrtbase.dll e msvcp140.dll. O último cenário mostra /MDd no qual my_exe.exe e my_dll.dll compartilham as versões de depuração dos runtimes: vcruntime140d.dll, ucrtbased.dll e msvcp140d.dll
O diagrama a seguir mostra como a biblioteca ASan está vinculada a várias opções do compilador:
A imagem mostra quatro cenários para vincular a biblioteca de tempo de execução do ASan. Os cenários são para /MT (vincular estaticamente o runtime), /MTd (vincular estaticamente o runtime de depuração), /MD (vincular dinamicamente o redist em runtime), /MDd (vincular dinamicamente o redist de depuração em runtime). Em todos os casos, my_exe.exe links e seus associados my_dll.dll vincular a uma única instância de clang-rt.asan-dynamix-x86_64.dll.
Mesmo ao vincular estaticamente, a DLL de runtime do ASan deve estar presente no runtime, ao contrário de outros componentes do C Runtime.
Versões anteriores
Antes do Visual Studio 17.7 Versão Prévia 3, os builds vinculados estaticamente (/MT
ou /MTd
) não usavam uma dependência de DLL. Em vez disso, o tempo de execução do AddressSanitizer foi vinculado estaticamente ao EXE do usuário. Os projetos DLL carregariam as exportações do EXE do usuário para acessar a funcionalidade ASan.
Projetos vinculados dinamicamente (/MD
ou /MDd
) usavam bibliotecas e DLLs diferentes, dependendo se o projeto estava configurado para depuração ou versão. Para obter mais informações sobre essas alterações e suas motivações, consulte MSVC Address Sanitizer – Uma DLL para todas as configurações de runtime.
A tabela a seguir descreve o comportamento anterior da vinculação da biblioteca de runtime AddressSanitizer, antes do Visual Studio 17.7 Preview 3:
Opção CRT | DLL ou EXE | DEBUG? | Uma biblioteca (.lib ) |
Binário de tempo de execução do ASan (.dll ) |
---|---|---|---|---|
/MT |
EXE | Não | clang_rt.asan-{arch} , clang_rt.asan_cxx-{arch} |
Nenhum |
/MT |
DLL | Não | clang_rt.asan_dll_thunk-{arch} |
Nenhum |
/MD |
Ou | Não | clang_rt.asan_dynamic-{arch} , clang_rt.asan_dynamic_runtime_thunk-{arch} |
clang_rt.asan_dynamic-{arch} |
/MT |
EXE | Sim | clang_rt.asan_dbg-{arch} , clang_rt.asan_dbg_cxx-{arch} |
Nenhum |
/MT |
DLL | Sim | clang_rt.asan_dbg_dll_thunk-{arch} |
Nenhum |
/MD |
Você pode usar o | Sim | clang_rt.asan_dbg_dynamic-{arch} , clang_rt.asan_dbg_dynamic_runtime_thunk-{arch} |
clang_rt.asan_dbg_dynamic-{arch} |
O diagrama a seguir mostra como a biblioteca ASan foi vinculada para várias opções do compilador antes do Visual Studio 2022 17.7 Versão Prévia 3:
A imagem mostra quatro cenários para vincular a biblioteca de tempo de execução do ASan. Os cenários são para /MT (vincular estaticamente o runtime), /MTd (vincular estaticamente o runtime de depuração), /MD (vincular dinamicamente o redist em runtime), /MDd (vincular dinamicamente o redist de depuração em runtime). Para /MT, my_exe.exe tem uma cópia vinculada estaticamente do tempo de execução do ASan. my_dll.dll links para o tempo de execução do ASan no my_exe.exe. Para /MTd, o diagrama é o mesmo, exceto que ele usa o runtime de depuração vinculado estaticamente do ASan. Para /MD, my_exe.exe e my_dll.dll vinculam ao runtime do ASan vinculado dinamicamente chamado clang_rt.asan_dynamic-x86_64.dll. Para /MDd, o diagrama é o mesmo, exceto my_exe.exe e my_dll.dll link para o runtime de depuração do ASan chamado clang_rt.asan_dbg_dynamic-x86_64.dll.
Interceptação de função
O AddressSanitizer obtém interceptação de função por meio de muitas técnicas de hotpatching. Essas técnicas são mais bem-documentadas dentro do próprio código-fonte.
As bibliotecas de runtime interceptam muitas funções comuns de gerenciamento de memória e manipulação de memória. Para obter uma lista, consulte a lista AddressSanitizer de funções interceptadas. Os interceptadores de alocação gerenciam metadados e bytes de sombra relacionados a cada chamada de alocação. Sempre que uma função CRT, como malloc
ou delete
é chamada, os interceptadores definem valores específicos na região de memória sombra do AddressSanitizer para indicar se esses locais de heap estão acessíveis no momento e quais são os limites da alocação. Esses bytes de sombra permitem que as verificações geradas pelo compilador dos bytes de sombra determinem se uma carga ou repositório é válida.
A interceptação não tem garantia de sucesso. Se um prólogo de função for muito curto para um jmp
ser gravado, a interceptação poderá falhar. Se ocorrer uma falha de interceptação, o programa lançará um debugbreak
e interromperá. Se você anexar um depurador, isso torna clara a causa do problema de interceptação. Se você tiver esse problema, relate um bug.
Observação
Opcionalmente, os usuários podem tentar continuar após uma interceptação com falha definindo a variável de ambiente ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE
como qualquer valor. Continuar após uma falha de interceptação pode resultar em relatórios de bugs perdidos para essa função.
Alocadores personalizados e o runtime addressSanitizer
O runtime do AddressSanitizer fornece interceptadores para interfaces comuns do alocador, malloc
/free
, new
/delete
, HeapAlloc
/HeapFree
(via RtlAllocateHeap
/RtlFreeHeap
). Muitos programas usam alocadores personalizados por um motivo ou outro, um exemplo seria qualquer programa usando dlmalloc
ou uma solução usando a interface std::allocator
e VirtualAlloc()
. O compilador não pode adicionar automaticamente chamadas de gerenciamento de memória de sombra a um alocador personalizado. É responsabilidade do usuário usar a interface de envenenamento manual fornecida. Essa API permite que esses alocadores funcionem corretamente com o runtime do AddressSanitizer existente e as convenções de bytes de sombra .
Interface de envenenamento do AddressSanitizer manual
A interface de esclarecimento é simples, mas impõe restrições de alinhamento ao usuário. Os usuários podem importar esses protótipos importando sanitizer/asan_interface.h
. Aqui estão os protótipos da função de interface:
void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
Para conveniência, o arquivo de cabeçalho da interface AddressSanitizer fornece macros de encapsulamento. Essas macros verificam se a funcionalidade AddressSanitizer está habilitada durante a compilação. Eles permitem que o código-fonte omita as chamadas de função de envenenamento quando não são necessárias. Essas macros devem ser preferenciais ao chamar diretamente as funções acima:
#define ASAN_POISON_MEMORY_REGION(addr, size)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)
Requisitos de alinhamento para envenenamento por AddressSanitizer
Qualquer envenenamento manual de bytes de sombra deve considerar os requisitos de alinhamento. O usuário deve adicionar preenchimento, se necessário, para que os bytes de sombra terminem em um limite de bytes na memória de sombra. Cada bit na memória de sombra addressSanitizer codifica o estado de um único byte na memória do aplicativo. Essa codificação significa que o tamanho total de cada alocação, incluindo qualquer preenchimento, deve se alinhar a um limite de 8 bytes. Se o requisito de alinhamento não for atendido, ele poderá levar a relatórios de bug incorretos. O relatório incorreto pode se manifestar como relatórios ausentes (falsos negativos) ou relatórios sobre não erros (falsos positivos).
Para obter uma ilustração do requisito de alinhamento e possíveis problemas, consulte os exemplos de alinhamento ASan fornecidos. Um deles é um pequeno programa para mostrar o que pode dar errado com envenenamento manual de memória de sombra. A segunda é uma implementação de exemplo de envenenamento manual usando a interface std::allocator
.
Opções de tempo
O Microsoft C/C++ (MSVC) usa um runtime baseado no runtime do Clang AddressSanitizer do repositório llvm-project. Por isso, a maioria das opções de runtime é compartilhada entre as duas versões. Uma lista completa das opções de runtime do Clang público está disponível aqui. Documentamos algumas diferenças nas seções a seguir. Se você descobrir opções que não funcionam conforme o esperado, relate um bug.
Opções do AddressSanitizer sem suporte
- detect_container_overflow
- unmap_shadow_on_exit
Observação
A opção halt_on_error
de runtime addressSanitizer não funciona conforme esperado. Nas bibliotecas de runtime do Clang e do MSVC, muitos tipos de erro são considerados incompletos, incluindo a maioria dos erros de corrupção de memória.
Para obter mais informações, consulte a seção Diferenças com Clang 12.0.
Opções de runtime do AddressSanitizer específicas do MSVC
windows_hook_legacy_allocators
Booleano, definido comofalse
para desabilitar a interceptação deGlobalAlloc
eLocalAlloc
alocadores.Observação
A opção
windows_hook_legacy_allocators
não estava disponível no runtime público do projeto llvm quando este artigo foi redigido. A opção pode eventualmente ser contribuída de volta para o projeto público; no entanto, depende da revisão de código e da aceitação da comunidade.A opção
windows_hook_rtl_allocators
, anteriormente um recurso de aceitação enquanto AddressSanitizer era experimental, agora está habilitada por padrão. Em versões anteriores ao Visual Studio 2022 versão 17.4.6, o valor da opção padrão éfalse
. No Visual Studio 2022 versão 17.4.6 e versões posteriores, o padrão da opçãowindows_hook_rtl_allocators
étrue
.iat_overwrite
String, definida como"error"
por padrão. Outros valores possíveis são"protect"
e"ignore"
. Alguns módulos podem substituir oimport address table
de outros módulos para personalizar implementações de determinadas funções. Por exemplo, os drivers geralmente fornecem implementações personalizadas para hardware específico. Aiat_overwrite
opção gerencia a proteção do runtime do AddressSanitizer contra substituições para funções específicasmemoryapi.h
. Atualmente, o runtime rastreia asVirtualAlloc
funções ,VirtualProtect
, eVirtualQuery
para proteção. Essa opção está disponível no Visual Studio 2022 versão 17.5 Versão Prévia 1 e versões posteriores. Os valores a seguiriat_overwrite
controlam como o runtime reage quando as funções protegidas são substituídas:- Se definido como
"error"
(o padrão), o runtime relata um erro sempre que uma substituição é detectada. - Se definido como
"protect"
, o runtime tentará evitar o uso da definição substituída e continuará. Efetivamente, a definição originalmemoryapi
da função é usada de dentro do runtime para evitar recursão infinita. Outros módulos no processo ainda usam a definição substituída. - Se definido como
"ignore"
, o runtime não tentará corrigir nenhuma função substituída e continuará com a execução.
- Se definido como
windows_fast_fail_on_error
Booleano (falso por padrão), definido comotrue
para permitir que o processo seja encerrado com um __fastfail(71) após a impressão do relatório de erros.
Observação
Quando abort_on_error valor é definido como true, no Windows o programa termina com um exit(3). Para não alterar o comportamento atual, decidimos introduzir essa nova opção. Se abort_on_error e windows_fast_fail_on_error forem verdadeiros, o programa será encerrado com o __fastfail.
Lista do AddressSanitizer de funções interceptadas (Windows)
O tempo de execução do AddressSanitizer corrige muitas funções para habilitar verificações de segurança de memória no tempo de execução. Aqui está uma lista, que não é definitiva, das funções que o runtime do AddressSanitizer monitora.
Interceptadores padrão
__C_specific_handler
(somente x64)_aligned_free
_aligned_malloc
_aligned_msize
_aligned_realloc
_calloc_base
_calloc_crt
_calloc_dbg
(somente runtime de depuração)_except_handler3
(somente x86)_except_handler4
(somente x86) (não documentado)_expand
_expand_base
(não documentado)_expand_dbg
(somente runtime de depuração)_free_base
(não documentado)_free_dbg
(somente runtime de depuração)_malloc_base
(não documentado)_malloc_crt
(não documentado)_malloc_dbg
(somente runtime de depuração)_msize
_msize_base
(não documentado)_msize_dbg
(somente runtime de depuração)_realloc_base
(não documentado)_realloc_crt
(não documentado)_realloc_dbg
(somente runtime de depuração)_recalloc
_recalloc_base
(não documentado)_recalloc_crt
(não documentado)_recalloc_dbg
(somente runtime de depuração)_strdup
atoi
atol
calloc
CreateThread
free
frexp
longjmp
malloc
memchr
memcmp
memcpy
memmove
memset
RaiseException
realloc
RtlAllocateHeap
RtlCreateHeap
RtlDestroyHeap
RtlFreeHeap
RtlRaiseException
RtlReAllocateHeap
(não documentado)RtlSizeHeap
(não documentado)SetUnhandledExceptionFilter
strcat
strchr
strcmp
strcpy
strcspn
strdup
strlen
strncat
strncmp
strncpy
strnlen
strpbrk
strspn
strstr
strtok
strtol
wcslen
wcsnlen
Interceptadores opcionais
Os interceptadores listados aqui só são instalados quando uma opção de runtime do AddressSanitizer está habilitada. Defina windows_hook_legacy_allocators
como false
para desabilitar a interceptação do alocador herdado.
set ASAN_OPTIONS=windows_hook_legacy_allocators=false
GlobalAlloc
GlobalFree
GlobalHandle
GlobalLock
GlobalReAlloc
GlobalSize
GlobalUnlock
LocalAlloc
LocalFree
LocalHandle
LocalLock
LocalReAlloc
LocalSize
LocalUnlock
Confira também
Visão geral do AddressSanitizer
Problemas conhecidos do AddressSanitizer
Referência de linguagem e build 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