O Google está comprometido em promover a equidade racial para as comunidades negras. Veja como.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

AddressSanitizer

AddressSanitizer (ASan) é uma ferramenta rápida baseada em compilador para detectar erros de memória no código nativo.

O ASan detecta:

  • Estouro / estouro de buffer de pilha e heap
  • Uso de pilha depois de grátis
  • Uso da pilha fora do escopo
  • Duplo grátis / grátis

O ASan é executado no ARM de 32 e 64 bits, além de x86 e x86-64. A sobrecarga de CPU da ASan é aproximadamente 2x, a sobrecarga de tamanho de código está entre 50% e 2x e uma grande sobrecarga de memória (dependente dos padrões de alocação, mas da ordem de 2x).

O Android 10 e a ramificação principal do AOSP no AArch64 suportam o ASan acelerado por hardware (HWASan) , uma ferramenta semelhante com menor sobrecarga de RAM e uma maior variedade de erros detectados. O HWASan detecta o uso da pilha após o retorno, além dos erros detectados pelo ASan.

O HWASan possui sobrecarga de CPU e tamanho de código semelhante, mas uma sobrecarga de RAM muito menor (15%). HWASan é não determinístico. Existem apenas 256 valores de tags possíveis, portanto, há uma probabilidade plana de 0,4% de perder qualquer bug. O HWASan não possui as zonas vermelhas de tamanho limitado do ASan para detectar estouros e quarentena de capacidade limitada para detectar o uso após livre, portanto, não importa para o HWASan qual o tamanho do estouro ou há quanto tempo a memória foi desalocada. Isso torna o HWASan melhor que o ASan. Você pode ler mais sobre o design do HWASan ou sobre o uso do HWASan no Android .

O ASan detecta estouros de pilha / globais, além de estouros de pilha, e é rápido com sobrecarga mínima de memória.

Este documento descreve como criar e executar partes / todo o Android com ASan. Se você estiver criando um aplicativo SDK / NDK com ASan, consulte Desinfetante de endereços .

Limpando executáveis ​​individuais com o ASan

Adicione LOCAL_SANITIZE:=address ou LOCAL_SANITIZE:=address sanitize: { address: true } à regra de construção do executável. Você pode procurar no código exemplos existentes ou encontrar outros desinfetantes disponíveis.

Quando um bug é detectado, o ASan imprime um relatório detalhado para a saída padrão e para o logcat e, em seguida, interrompe o processo.

Limpando bibliotecas compartilhadas com o ASan

Devido à maneira como o ASan funciona, uma biblioteca criada com o ASan só pode ser usada por um executável criado com o ASan.

Para limpar uma biblioteca compartilhada usada em vários executáveis, nem todos criados com o ASan, você precisa de duas cópias da biblioteca. A maneira recomendada de fazer isso é adicionar o seguinte ao Android.mk para o módulo em questão:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

Isso coloca a biblioteca em /system/lib/asan vez de /system/lib . Em seguida, execute seu executável com:

LD_LIBRARY_PATH=/system/lib/asan

Para daemons do sistema, adicione o seguinte à seção apropriada de /init.rc ou /init.$device$.rc .

setenv LD_LIBRARY_PATH /system/lib/asan

Verifique se o processo está usando bibliotecas de /system/lib/asan quando presente, lendo /proc/$PID/maps . Caso contrário, pode ser necessário desativar o SELinux:

adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID
# if it is a system service, or may be adb shell stop; adb shell start.

Melhores rastreamentos de pilha

O ASan usa um desenrolador rápido baseado em ponteiro de quadro para registrar um rastreamento de pilha para cada evento de alocação e desalocação de memória no programa. A maior parte do Android é construída sem ponteiros de quadro. Como resultado, você geralmente obtém apenas um ou dois quadros significativos. Para corrigir isso, recrie a biblioteca com ASan (recomendado!) Ou com:

LOCAL_CFLAGS:=-fno-omit-frame-pointer
LOCAL_ARM_MODE:=arm

Ou defina ASAN_OPTIONS=fast_unwind_on_malloc=0 no ambiente do processo. O último pode consumir muito a CPU, dependendo da carga.

Simbolização

Inicialmente, os relatórios do ASan contêm referências a compensações em binários e bibliotecas compartilhadas. Há duas maneiras de obter informações sobre o arquivo e a linha de origem:

  • Verifique se o binário llvm-symbolizer está presente em /system/bin . llvm-symbolizer é construído a partir de fontes em third_party/llvm/tools/llvm-symbolizer .
  • Filtre o relatório pelo script external/compiler-rt/lib/asan/scripts/symbolize.py .

A segunda abordagem pode fornecer mais dados (ou seja, localizações de file:line ) devido à disponibilidade de bibliotecas simbolizadas no host.

ASan em aplicativos

O ASan não pode ver o código Java, mas pode detectar erros nas bibliotecas JNI. Para isso, você precisa construir o executável com o ASan, que neste caso é /system/bin/app_process( 32|64 ) . Isso habilita o ASan em todos os aplicativos no dispositivo ao mesmo tempo, o que é uma carga pesada, mas um dispositivo com 2 GB de RAM deve ser capaz de lidar com isso.

Inclua LOCAL_SANITIZE:=address na regra de construção app_process em frameworks/base/cmds/app_process . Ignore o destino app_process__asan no mesmo arquivo por enquanto (se ainda estiver lá no momento em que você ler isso).

Edite a seção service zygote arquivo system/core/rootdir/init.zygote( 32|64 ).rc apropriado para adicionar as seguintes linhas ao bloco de linhas recuadas que contêm a class main , também recuado na mesma quantidade:

    setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib
    setenv ASAN_OPTIONS allow_user_segv_handler=true

Construa, adb sync, inicialização rápida por flash e reinicialização.

Usando a propriedade Wrap

A abordagem na seção anterior coloca o ASan em todos os aplicativos do sistema (na verdade, em todos os descendentes do processo do Zygote). É possível executar apenas um (ou vários) aplicativos com o ASan, trocando alguma sobrecarga de memória pela inicialização mais lenta do aplicativo.

Isso pode ser feito iniciando seu aplicativo com o wrap. propriedade. O exemplo a seguir executa o aplicativo Gmail em ASan:

adb root
adb shell setenforce 0  # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"

Nesse contexto, o asanwrapper reescreve /system/bin/app_process em /system/bin/asan/app_process , construído com o ASan. Ele também adiciona /system/lib/asan no início do caminho de pesquisa da biblioteca dinâmica. Dessa forma, as bibliotecas instrumentadas pelo ASan em /system/lib/asan são preferidas às bibliotecas normais em /system/lib ao executar com o asanwrapper .

Se um erro for encontrado, o aplicativo falha e o relatório é impresso no log.

SANITIZE_TARGET

O Android 7.0 e superior incluem suporte para criar toda a plataforma Android com o ASan de uma só vez. (Se você estiver criando uma versão superior ao Android 9, o HWASan é uma escolha melhor.)

Execute os seguintes comandos na mesma árvore de construção.

make -j42
SANITIZE_TARGET=address make -j42

Nesse modo, o userdata.img contém bibliotecas extras e também deve ser atualizado para o dispositivo. Use a seguinte linha de comando:

fastboot flash userdata && fastboot flashall

Isso cria dois conjuntos de bibliotecas compartilhadas: normal em /system/lib (a primeira invocação), e ASan instrumentado em /data/asan/lib (a segunda invocação). Os executáveis ​​da segunda versão substituem os da primeira versão. Os executáveis ​​instrumentados por ASan obtêm um caminho de pesquisa de biblioteca diferente que inclui /data/asan/lib antes /system/lib através do uso de /system/bin/linker_asan em PT_INTERP .

O sistema de construção desobstrui diretórios de objetos intermediários quando o valor $SANITIZE_TARGET é alterado. Isso força a reconstrução de todos os destinos, preservando os binários instalados em /system/lib .

Alguns destinos não podem ser criados com o ASan:

  • Executáveis ​​vinculados estaticamente
  • LOCAL_CLANG:=false destinos LOCAL_CLANG:=false
  • LOCAL_SANITIZE:=false não é ASan'd para SANITIZE_TARGET=address

Executáveis ​​como esses são ignorados na construção SANITIZE_TARGET e a versão da primeira chamada de criação é deixada em /system/bin .

Bibliotecas como essa são criadas sem o ASan. Eles podem conter algum código ASan das bibliotecas estáticas das quais eles dependem.

Documentação de suporte