Entender os relatórios do HWASan

Quando a ferramenta HWASan detecta um bug de memória, o processo é encerrado com abort(), e um relatório é impresso no stderr e no Logcat. Como todos os travamentos nativos no Android, os erros do HWASan estão em /data/tombstones.

Exemplo de relatório

Em comparação com falhas nativas normais, o HWASan tem informações extras no campo Mensagem de interrupção, perto da parte de cima da lápide. Confira um exemplo de falha baseada em heap. Para bugs de pilha, consulte a nota sobre as seções específicas de pilha.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/flame_hwasan/flame:Tiramisu/MASTER/7956676:userdebug/dev-keys'
Revision: 'DVT1.0'
ABI: 'arm64'
Timestamp: 2019-04-24 01:13:22+0000
pid: 11154, tid: 11154, name: sensors@1.0-ser  >>> /vendor/bin/hw/android.hardware.sensors@1.0-service <<<
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: '

[...]

[0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5








[ … regular crash dump follows …]

Isso é semelhante a um relatório do AddressSanitizer. Ao contrário desses, quase todos os bugs do HWASan são erros de incompatibilidade de tag, ou seja, um acesso à memória em que uma tag de ponteiro não corresponde à tag de memória correspondente. Isso pode ser um dos seguintes motivos:

  • Acesso fora dos limites na pilha ou na pilha de heap
  • Erro de uso após liberação no heap
  • Erro de uso após o retorno na pilha

Seções

Confira a explicação de cada uma das seções do relatório HWASan.

Erro de acesso

Contém informações sobre o acesso incorreto à memória, incluindo:

  • Tipo de acesso (READ versus WRITE)
  • Tamanho de acesso (quantos bytes foram acessados)
  • Número da linha de execução do acesso
  • Tags de ponteiro e de memória (para depuração avançada)

Acesso ao stack trace

Stack trace do acesso de memória inválido. Consulte Simbologia para saber como simbolizar.

Causa

A possível causa do acesso indevido. Se houver vários candidatos, eles serão listados em ordem de probabilidade decrescente. Antecede as informações detalhadas sobre a possível causa. O HWASan pode diagnosticar as seguintes causas:

  • Use After Free
  • Incompatibilidade de tag de pilha, que pode ser uso de pilha após retorno, uso de pilha após escopo ou fora dos limites
  • Estouro de buffer de heap
  • Transbordamento global

Informações de memória

Descreve o que o HWASan sabe sobre a memória que está sendo acessada e pode variar de acordo com o tipo de bug:

Tipo de bug Causa Formato do relatório
Incompatibilidade de tags Use After Free Use este formato de relatório:
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
Estouro de buffer de heap Isso também pode ser um underflow.
<address> is located N bytes to the right of M-byte region [<start>, <end>)
allocated here:
Tag de pilha incompatível Os relatórios de pilha não diferenciam overflow ou underflow e bugs de uso após o retorno. Além disso, para encontrar a alocação de pilha que é a origem do erro, é necessária uma etapa de simbolização off-line. Consulte Noções básicas sobre relatórios de pilha.
Liberação inválida Use After Free Um bug de double free. Se isso acontecer no encerramento do processo, pode indicar uma violação de ODR.
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
Não é possível descrever o endereço Ou um free selvagem (livre de memória que não foi alocada antes) ou um double free depois que a memória alocada foi removida do buffer livre do HWASan.
0x... é a memória sombra do HWAsan Um wild free, porque o app estava tentando liberar memória interna do HWASan.

Stack trace de desalocação

Stack trace de onde a memória foi desalocada. Apresentado apenas para bugs de uso após a liberação ou bugs de invalid-free. Consulte Simbologia para saber mais.

Stack trace de alocação

Stack trace de onde a memória foi alocada. Consulte Simbologia para saber mais.

Informações avançadas de depuração

O relatório do HWASan também apresenta algumas informações avançadas de depuração, incluindo:

  1. A lista de linhas de execução no processo
  2. A lista de linhas de execução no processo
  3. O valor das tags de memória perto da memória com falha
  4. O despejo dos registros no ponto de acesso à memória

Despejo de tag de memória

É possível usar o despejo de memória de tag para procurar alocações de memória próximas com a mesma tag que a tag do ponteiro. Essas tags podem apontar para um acesso fora dos limites com um deslocamento grande. Uma tag corresponde a 16 bytes de memória. A tag do ponteiro é os 8 bits principais do endereço. O dump de memória de tags pode dar dicas. Por exemplo, o seguinte é um buffer overflow à direita:

tags: ad/5c (ptr/mem)
[...]
Memory tags around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: 0e  0e  0e  57  20  20  20  20  20  2e  5e  5e  5e  5e  5e  b5
=>0x006f33ae2000: f6  f6  f6  f6  f6  4c  ad  ad  ad  ad  ad  ad [5c] 5c  5c  5c
  0x006f33ae2010: 5c  04  2e  2e  2e  2e  2e  2f  66  66  66  66  66  80  6a  6a
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: ab  52  eb  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
=>0x006f33ae2000: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. [..] ..  ..  ..
  0x006f33ae2010: ..  5c  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..

Observe a execução de 6 × 16 = 96 bytes de tags ad à esquerda que correspondem à tag do ponteiro.

Se o tamanho de uma alocação não for um múltiplo de 16, o restante do tamanho será armazenado como a tag de memória e a tag será armazenada como uma tag de granulo curto. No exemplo anterior, logo após a alocação em negrito marcada ad, temos uma alocação de 5 × 16 + 4 = 84 bytes da tag 5c.

Uma tag de memória zero (por exemplo, tags: ad/00 (ptr/mem)) indica um bug de uso da pilha após o retorno.

Registro de despejo

O despejo de registro nos relatórios do HWASan corresponde à instrução que executou o acesso à memória inválido. Esse dump é seguido por outro dump de registro do gerenciador de sinais regular do Android. Ignore o segundo despejo, porque ele foi feito quando o HWASan chamou abort() e não é relevante para o bug.

Simbolização

Para conferir os nomes de função e os números de linha em stack traces e conferir os nomes de variáveis para bugs de uso após o escopo, é necessária uma etapa de simbolização off-line.

Configuração inicial: instale o llvm-symbolizer

Para simbolizar, seu sistema precisa ter o llvm-symbolizer instalado e acessível em $PATH. No Debian, é possível instalar usando sudo apt install llvm.

Conseguir arquivos de símbolo

Para a simbolização, são necessários binários não simplificados que contenham símbolos. A localização depende do tipo de build:

  • Para builds locais, os arquivos de símbolo estão em out/target/product/<product>/symbols/.
  • Para builds do AOSP (por exemplo, atualizados pela Android Flash Tool), os builds estão no Android CI. Nos Artefatos do build, há um arquivo ${PRODUCT}-symbols-${BUILDID}.zip.
  • Para builds internos da sua organização, consulte a documentação da organização para saber como acessar os arquivos de símbolo.

Simbolizar

hwasan_symbolize --symbols <DECOMPRESSED_DIR>/out/target/product/*/symbols < crash

Entender os relatórios de pilha

Para bugs que ocorrem com variáveis de pilha, o relatório do HWASan contém detalhes como estes:

Cause: stack tag-mismatch
Address 0x007d4d251e80 is located in stack of thread T64
Thread: T64 0x0074000b2000 stack: [0x007d4d14c000,0x007d4d255cb0) sz: 1088688 tls: [0x007d4d255fc0,0x007d4d259000)
Previously allocated frames:
  record_addr:0x7df7300c98 record:0x51ef007df3f70fb0  (/apex/com.android.art/lib64/libart.so+0x570fb0)
  record_addr:0x7df7300c90 record:0x5200007df3cdab74  (/apex/com.android.art/lib64/libart.so+0x2dab74)
  [...]

Para ajudar a entender os bugs de pilha, o HWASan rastreia os frames de pilha anteriores. O HWASan não transforma esses dados em conteúdo compreensível para humanos no relatório de bug e requer uma etapa de simbolização extra.

Violações de ODR

Alguns bugs de uso após a liberação relatados pelo HWASan podem indicar uma violação da regra de definição única (ODR, na sigla em inglês). Uma violação de ODR acontece quando a mesma variável é definida várias vezes no mesmo programa. Isso também significa que a variável é destruída várias vezes, o que pode levar ao uso de um erro de uso após a liberação.

Após a simbolização, as violações de ODR mostram um erro de uso após a liberação com __cxa_finalize, tanto na pilha de acesso inválido quanto na freed here. A pilha alocada anteriormente aqui contém __dl__ZN6soinfo17call_constructorsEv e deve apontar para o local no programa que define a variável mais alta na pilha.

O ODR pode ser violado se bibliotecas estáticas forem usadas. Se uma biblioteca estática que define um global C++ for vinculada a várias bibliotecas compartilhadas ou executáveis, várias definições do mesmo símbolo poderão existir no mesmo espaço de endereço, o que causa um erro de ODR.

Solução de problemas

Esta seção descreve alguns erros e como resolvê-los.

O HWAddressSanitizer não pode descrever o endereço com mais detalhes

Às vezes, o HWASan pode ficar sem espaço para informações sobre alocações de memória anteriores. Nesse caso, o relatório contém apenas um stack trace para o acesso imediato à memória, seguido por uma observação:

HWAddressSanitizer can not describe address in more detail.

Em alguns casos, é possível resolver esse problema executando o teste várias vezes. Outra opção é aumentar o tamanho do histórico do HWASan. Isso pode ser feito globalmente em build/soong/cc/sanitize.go (procure por hwasanGlobalOptions) ou no ambiente de processo (tente adb shell echo $HWASAN_OPTIONS para ver as configurações atuais).

Esse erro também pode acontecer se a memória acessada não for mapeada ou alocada por um alocador compatível com o HWASan. Nesse caso, a tag mem listada no cabeçalho do crash geralmente é 00. Se você tiver acesso ao tombstone completo, consulte o dump de mapas de memória para descobrir a qual mapeamento (se houver) o endereço pertence.

Bug aninhado na mesma linha de execução

Isso significa que houve um bug ao gerar o relatório de falha do HWASan. Isso geralmente ocorre devido a um bug no ambiente de execução do HWASan. Registre um bug e forneça instruções sobre como reproduzir o problema, se possível.