Bytes de sombra do AddressSanitizer
Resumimos brevemente o conceito de bytes de sombra e como eles podem ser usados pela implementação de runtime de /fsanitize=address
. Para obter mais detalhes, consulte a pesquisa inicial AddressSanitizer - Serebryany, et al e a documentação atual do algoritmo AddressSanitizer.
Conceito principal
Cada 8 bytes no espaço de endereço virtual do aplicativo pode ser descrito usando um byte de sombra.
Um byte de sombra descreve quantos bytes estão acessíveis no momento da seguinte maneira:
- 0 significa todos os 8 bytes
- 1-7 significa um a sete bytes
- Os números negativos codificam o contexto para o runtime a ser usado para o diagnóstico de relatório.
Legenda do byte de sombra
Considere esta legenda de bytes de sombra em que todos os números negativos são definidos:
Mapeamento: descrevendo seu espaço de endereço
Cada 8 bytes no espaço de endereço virtual do aplicativo alinhado a "0-mod-8" pode ser mapeado para o byte de sombra que descreve esse slot no espaço de endereço virtual. Esse mapeamento pode ser feito com uma ação simples de deslocar e adicionar.
Em x86:
char shadow_byte_value = *((Your_Address >> 3) + 0x30000000)
Em x64:
char shadow_byte_value = *((Your_Address >> 3) + _asan_runtime_assigned_offset)
Geração de código: testes
Considere como bytes de sombra específicos podem ser gravados, seja pelo código gerado pelo compilador, pelos dados estáticos ou pelo runtime. Este pseudocódigo mostra como é possível gerar uma verificação que precede qualquer carregamento ou armazenamento:
ShadowAddr = (Addr >> 3) + Offset;
if (*ShadowAddr != 0) {
ReportAndCrash(Addr);
}
Ao instrumentar uma referência de memória com menos de 8 bytes de largura, a instrumentação é um pouco mais complexa. Se o valor da sombra for positivo (o que significa que apenas os primeiros k bytes na palavra de 8 bytes podem ser acessados), precisamos comparar os últimos 3 bits do endereço com k.
ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k)) {
ReportAndCrash(Addr);
}
O runtime e o código gerado pelo compilador gravam bytes de sombra. Esses bytes de sombra permitem ou revogam o acesso quando os escopos terminam ou o armazenamento é liberado. As verificações acima leem bytes de sombra que descrevem "slots" de 8 bytes no espaço de endereço do aplicativo, em um determinado momento da execução do programa. Além dessas verificações geradas explicitamente, o runtime também verifica bytes de sombra depois de interceptar (ou "capturar") muitas funções no CRT.
Para mais informações, confira a lista de funções interceptadas.
Como definir bytes de sombra
O código gerado pelo compilador e o runtime do AddressSanitizer podem gravar bytes de sombra. Por exemplo, o compilador pode definir bytes de sombra para permitir o acesso de tamanho fixo a locais de pilha definidos em um escopo interno. O runtime pode colocar variáveis globais na seção de dados entre bytes de sombra.
Confira também
Visão geral do AddressSanitizer
Problemas conhecidos do AddressSanitizer
Referência de linguagem e build do AddressSanitizer
Referência de runtime do AddressSanitizer
Nuvem do AddressSanitizer ou teste distribuído
Integração do depurador do AddressSanitizer
Exemplos de erro do AddressSanitizer