Partilhar via


Tempo de execução do AddressSanitizer

A biblioteca de tempo de execução AddressSanitizer interceta funções e operações comuns de alocação de memória para permitir a inspeção de acessos à memória. Existem várias bibliotecas de tempo de execução diferentes que suportam os vários tipos de executáveis que o compilador pode gerar. O compilador e o vinculador vinculam automaticamente as bibliotecas de tempo de execução apropriadas, desde que você passe a opção em tempo de /fsanitize=address compilação. Você pode substituir o comportamento padrão usando a opção no momento do /NODEFAULTLIB link. Para obter mais informações, consulte a seção sobre vinculação na linguagem AddressSanitizer, compilação e referência de depuração.

Ao compilar com cl /fsanitize=addresso , o compilador gera instruções para gerenciar e verificar bytes de sombra. Seu programa usa essa instrumentação para verificar os acessos à 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 tempo de execução gere diagnósticos de erros precisos: nomes de funções, linhas e colunas no código-fonte. Combinadas, as verificações do compilador e as bibliotecas de tempo de execução podem diagnosticar com precisão muitos tipos de bugs de segurança de memória se forem encontrados em tempo de execução.

A lista de bibliotecas de tempo de execução para vincular ao tempo de execução AddressSanitizer, a partir do Visual Studio 17.7 Preview 3, segue. Para obter mais informações sobre as /MT opções (vincular estaticamente o tempo de execução) e /MD (vincular dinamicamente o redist no tempo de execução), consulte /MD, /MT, /LD (Usar biblioteca Run-Time).

Note

Na tabela a seguir, {arch} é ou i386x86_64. Essas bibliotecas usam convenções Clang para nomes de arquitetura. As convenções MSVC são normalmente x86 e x64 não i386 e x86_64, mas referem-se às mesmas arquiteturas.

Opção CRT Biblioteca de tempo de execução AddressSanitizer (.lib) Endereço binário de tempo de execuçã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 estão vinculadas para as opções , /MT/MTd, /MDe /MDd compilador:

Diagrama de como as bibliotecas de tempo de execução são vinculadas para várias opções 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, CRT Universal e C++ vinculados estaticamente. Os cenários mostram /MD no qual my_exe.exe e my_dll.dll compartilham vcruntime140.dll, ucrtbase.dlle 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 tempos de execução: vcruntime140d.dll, ucrtbased.dlle msvcp140d.dll

O diagrama a seguir mostra como a biblioteca ASan está vinculada para várias opções do compilador:

Diagrama de como a dll de tempo de execução ASan está vinculada.

A imagem mostra quatro cenários para vincular a biblioteca de tempo de execução ASan. Os cenários são para /MT (vincular estaticamente o tempo de execução), /MTd (vincular estaticamente o tempo de execução da depuração), /MD (vincular dinamicamente o redist no tempo de execução), /MDd (vincular dinamicamente o redist de depuração no tempo de execução). Em todos os casos, my_exe.exe links e seus associados my_dll.dll link para uma única instância de clang_rt.asan_dynamic-x86_64.dll.

Mesmo ao vincular estaticamente, a DLL de tempo de execução ASan deve estar presente no tempo de execução - ao contrário de outros componentes do C Runtime.

Versões anteriores

Antes do Visual Studio 17.7 Preview 3, compilações vinculadas 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 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 foi configurado para depuração ou versão. Para obter mais informações sobre essas alterações e suas motivações, consulte MSVC AddressSanitizer – One DLL for all Runtime Configurations.

A tabela a seguir descreve o comportamento anterior da vinculação da biblioteca de tempo de execução AddressSanitizer, antes do Visual Studio 17.7 Preview 3:

Opção CRT DLL ou EXE DEBUG? Biblioteca ASan (.lib) ASan binário de tempo de execução (.dll)
/MT EXE No clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch} None
/MT DLL No clang_rt.asan_dll_thunk-{arch} None
/MD Either No clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MT EXE Yes clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch} None
/MT DLL Yes clang_rt.asan_dbg_dll_thunk-{arch} None
/MD Either Yes 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 Preview 3:

Diagrama de como a dll de tempo de execução ASan foi vinculada antes do Visual Studio 2022 Preview 3.

A imagem mostra quatro cenários para vincular a biblioteca de tempo de execução ASan. Os cenários são para /MT (vincular estaticamente o tempo de execução), /MTd (vincular estaticamente o tempo de execução da depuração), /MD (vincular dinamicamente o redist no tempo de execução), /MDd (vincular dinamicamente o redist de depuração no tempo de execução). Para /MT, my_exe.exe tem uma cópia vinculada estaticamente do tempo de execução 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 usa o tempo de execução ASan vinculado estaticamente debug. Para /MD, my_exe.exe e my_dll.dll link para o tempo de execução ASan dinamicamente vinculado 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 tempo de execução de depuração ASan chamado clang_rt.asan_dbg_dynamic-x86_64.dll.

Função de interceção

O AddressSanitizer consegue intercetação de funções através de muitas técnicas de hotpatching. Essas técnicas são melhor documentadas dentro do próprio código-fonte.

As bibliotecas de tempo de execução intercetam muitas funções comuns de gerenciamento e manipulação de memória. Para obter uma lista, consulte AddressSanitizer lista de funções intercetadas. Os intercetores de alocação gerenciam metadados e shadow bytes relacionados a cada chamada de alocação. Sempre que uma função CRT como malloc ou delete é chamada, os intercetadores definem valores específicos na região de memória de sombra AddressSanitizer para indicar se esses locais de heap estão atualmente acessíveis 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 armazenamento é válido.

Não é garantido que a interceção tenha êxito. Se um prólogo de função for muito curto para ser jmp escrito, a intercetação pode falhar. Se ocorrer uma falha de interceção, o programa lança um debugbreak e para. Se você anexar um depurador, ele deixará clara a causa do problema de intercetação. Se você tiver esse problema, reporte um bug.

Note

Opcionalmente, os usuários podem tentar continuar após uma intercetação com falha, definindo a variável ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE de ambiente para qualquer valor. Continuar após uma falha de intercetação pode resultar em relatórios de bugs perdidos para essa função.

Alocadores personalizados e o tempo de execução do AddressSanitizer

O tempo de execução do AddressSanitizer fornece intercetores para interfaces comuns de alocadores, malloc/free, new/delete,HeapAlloc/HeapFree(via ).RtlAllocateHeap/RtlFreeHeap Muitos programas fazem uso de alocadores personalizados por uma razão ou outra, um exemplo seria qualquer programa usando dlmalloc ou uma solução usando a std::allocator interface e VirtualAlloc(). O compilador não consegue 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 as convenções existentes de tempo de execução e byte de sombra AddressSanitizer.

Endereço manualInterface de envenenamento do Sanitizer

A interface para 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);

Por conveniência, o arquivo de cabeçalho da interface AddressSanitizer fornece macros de wrapper. Essas macros verificam se a funcionalidade AddressSanitizer está habilitada durante a compilação. Eles permitem que seu código-fonte omita as chamadas de função de envenenamento quando elas não são necessárias. Essas macros devem ser preferidas em vez de chamar as funções acima diretamente:

#define ASAN_POISON_MEMORY_REGION(addr, size)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)

Note

Se você envenenar manualmente a memória, você deve desenvenená-la antes de reutilizar. Isso é especialmente importante para endereços de pilha, como para uma variável local, que são frequentemente reutilizados durante a execução do programa. Você corre o risco de introduzir use-after-poison falsos positivos em endereços de pilha envenenados manualmente se não os desenvenenar antes que a estrutura da pilha seja removida.

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 estar alinhado a um limite de 8 bytes. Se o requisito de alinhamento não for cumprido, isso pode levar a relatórios de bugs incorretos. A comunicação incorreta pode manifestar-se como notificações em falta (falsos negativos) ou notificações de 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 é um pequeno programa para mostrar o que pode dar errado com o envenenamento manual de memória de sombra. O segundo é um exemplo de implementação de envenenamento manual usando a std::allocator interface.

Opções de tempo de execução

MSVC AddressSanitizer é uma bifurcação sincronizada regularmente do tempo de execução do Clang AddressSanitizer. Como resultado, o MSVC herda implicitamente muitas das opções de tempo de execução ASan do Clang. Uma lista completa de opções que mantemos e testamos ativamente pode ser encontrada aqui. Se você descobrir opções que não funcionam como esperado, reporte um bug.

Configurar opções de tempo de execução

As opções de tempo de execução do ASan são definidas de duas maneiras:

  • A variável de ambiente ASAN_OPTIONS
  • A __asan_default_options função de utilizador

Se a variável de ambiente e a função de usuário especificarem opções conflitantes, as ASAN_OPTIONS opções na variável de ambiente terão precedência.

Várias opções são especificadas separando-as com dois pontos (:).

O exemplo a seguir define alloc_dealloc_mismatch como um e symbolize zero:

set ASAN_OPTIONS=alloc_dealloc_mismatch=1:symbolize=0

Ou adicione a seguinte função ao seu código:

extern "C" const char* __asan_default_options()
{
  return "alloc_dealloc_mismatch=1:symbolize=0";
}

Opções de AddressSanitizer não suportadas

  • detect_container_overflow
  • unmap_shadow_on_exit

Note

A opção halt_on_error de tempo de execução AddressSanitizer não funciona da maneira que você poderia esperar. Nas bibliotecas de tempo de execução Clang e MSVC, muitos tipos de erro são considerados não continuáveis, incluindo a maioria dos erros de corrupção de memória.

Para obter mais informações, consulte a seção Diferenças com o Clang 12.0 .

Opções de tempo de execução do AddressSanitizer específicas do MSVC

  • continue_on_error Booleano, definido como false por padrão. Quando definido como true, ele permite que o programa continue a ser executado depois que uma violação de memória é relatada, permitindo que você colete vários relatórios de erros.

  • iat_overwrite String, definida como "error" por padrão. Outros valores possíveis são "protect" e "ignore". Alguns módulos podem substituir o import 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. A iat_overwrite opção gerencia a proteção do tempo de execução do AddressSanitizer contra substituições para funções específicas memoryapi.h . O tempo de execução atualmente rastreia o VirtualAlloc, VirtualProtecte VirtualQuery funções para proteção. Esta opção está disponível no Visual Studio 2022 versão 17.5 Preview 1 e versões posteriores. Os valores a seguir iat_overwrite controlam como o tempo de execução reage quando as funções protegidas são substituídas:

    • Se definido como "error" (o padrão), o tempo de execução relata um erro sempre que uma substituição é detetada.
    • Se definido como "protect", o tempo de execução tenta evitar o uso da definição substituída e prossegue. Efetivamente, a definição original memoryapi da função é usada de dentro do tempo de execução para evitar recursão infinita. Outros módulos no processo ainda usam a definição substituída.
    • Se definido como "ignore", o tempo de execução não tenta corrigir nenhuma função substituída e prossegue com a execução.
  • windows_fast_fail_on_error Booleano (false por padrão), definido para true permitir que o processo termine com um após imprimir o relatório de __fastfail(71) erros.

    Note

    Quando abort_on_error value é definido como true, no Windows o programa termina com um exit(3)arquivo . Para não mudar o comportamento atual, decidimos introduzir esta nova opção. Se ambos abort_on_error e windows_fast_fail_on_error forem true, o programa sairá com o __fastfail.

  • windows_hook_legacy_allocators Booleano, definido para false desativar a intercetação e GlobalAllocLocalAlloc alocadores.

    Note

    A opção windows_hook_legacy_allocators não estava disponível no tempo de execução público do llvm-project quando este artigo foi escrito. A opção pode, eventualmente, ser reconduzida para o projeto público; no entanto, depende da revisão do código e da aceitação da comunidade.

    A opção windows_hook_rtl_allocators, anteriormente um recurso de aceitação enquanto o AddressSanitizer era experimental, agora está habilitada por padrão. Em versões anteriores ao Visual Studio 2022 versão 17.4.6, o valor de opção padrão é false. No Visual Studio 2022 versão 17.4.6 e versões posteriores, a opção windows_hook_rtl_allocators assume como truepadrão .

AddressSanitizer lista de funções intercetadas (Windows)

O tempo de execução AddressSanitizer hotpatches muitas funções para permitir verificações de segurança de memória em tempo de execução. Aqui está uma lista não exaustiva das funções que o tempo de execução do AddressSanitizer monitora.

Intercetores padrão

Intercetores opcionais

Os intercetores listados aqui só são instalados quando uma opção de tempo de execução AddressSanitizer está ativada. Defina windows_hook_legacy_allocators como false para desativar a intercetação do alocador herdado. set ASAN_OPTIONS=windows_hook_legacy_allocators=false

Consulte também

Visão geral do AddressSanitizer
AddressSanitizer problemas conhecidos
de compilação e referência de linguagem AddressSanitizer
AddressSanitizer shadow bytes
AddressSanitizer na nuvem ou de testes distribuídos
de integração do depurador AddressSanitizer
Exemplos de erro AddressSanitizer