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 em stderr e logcat. Como todas as falhas nativas no Android, os erros do HWASan estão em /data/tombstones.

Exemplo de relatório

Em comparação com falhas nativas normais, o HWASan contém informações extras no campo Abort message perto da parte de cima do tombstone. Confira um exemplo de falha baseada em heap. Para bugs de pilha, consulte a observação das seções específicas da 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 deles, quase todos os bugs do HWASan são erros de incompatibilidade de tags, ou seja, um acesso de memória em que uma tag de ponteiro não corresponde à tag de memória correspondente. Isso pode ser qualquer um dos seguintes:

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

Seções

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

Erro de acesso

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

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

Stack trace de acesso

Stack trace do acesso de memória incorreto. Consulte Simbolização para simbolizar.

Causa

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

  • Uso após a liberação
  • Incompatibilidade de tags de pilha, que pode ser uso de pilha após o retorno, uso de pilha após o escopo ou fora dos limites
  • Estouro de buffer de heap
  • Estouro 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 Uso após a liberação 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:
Incompatibilidade de tags de pilha Os relatórios de pilha não diferenciam entre estouro 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 Entender os relatórios de pilha reports.
Liberação inválida Uso após a liberação Um bug de liberação dupla. Se isso acontecer no encerramento do processo, poderá 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 Uma liberação selvagem (liberação de memória que não havia sido alocada antes) ou uma liberação dupla após a memória alocada ser removida do buffer livre do HWASan.
0x... é a memória sombra do HWASan Uma liberação selvagem, já que o app estava tentando liberar memória interna do HWASan.

Stack trace de desalocação

Stack trace de onde a memória foi desalocada. Presente apenas para bugs de uso após a liberação ou liberação inválida. Consulte Simbolização para simbolizar.

Stack trace de alocação

Stack trace de onde a memória foi alocada. Consulte Simbolização para simbolizar.

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

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

  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 tags de memória

É possível usar o despejo de memória de tags para procurar alocações de memória próximas com a mesma tag que a tag de ponteiro. Essas tags podem apontar para um acesso fora dos limites com um grande deslocamento. Uma tag corresponde a 16 bytes de memória. A tag de ponteiro é os 8 bits mais significativos do endereço. O despejo de memória de tags pode dar dicas. Por exemplo, o seguinte é um estouro de buffer à 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 de 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 grânulo curta. No exemplo anterior, logo após a alocação em negrito marcada como 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 de pilha após o retorno.

Despejo de registro

O despejo de registro nos relatórios do HWASan corresponde à instrução que realizou o acesso de memória inválido. Esse despejo é seguido por outro despejo de registro do gerenciador de sinais normal 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 receber nomes de funções e números de linhas em stack traces (e receber nomes de variáveis para bugs de uso após o escopo), é necessária uma etapa de simbolização off-line.

Primeira configuração: instale o llvm-symbolizer

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

Receber arquivos de símbolos

Para a simbolização, exigimos binários não removidos que contenham símbolos. O local deles depende do tipo de build:

  • Para builds locais, os arquivos de símbolos 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 receber ajuda na obtenção de arquivos de símbolos.

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 este:

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 você a entender os bugs de pilha, o HWASan acompanha os frames de pilha anteriores. O HWASan não transforma esses frames em conteúdo compreensível para humanos no relatório de bugs e exige uma etapa de simbolização adicional.

Violações de ODR

Alguns bugs de uso após a liberação informados pelo HWASan podem indicar uma violação da regra de uma definição (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 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 pilha liberada aqui. A pilha alocada anteriormente aqui contém __dl__ZN6soinfo17call_constructorsEv e deve apontar para o local no programa que define a variável mais acima na pilha.

A ODR pode ser violada se bibliotecas estáticas forem usadas. Se uma biblioteca estática que define um global C++ estiver 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.

HWAddressSanitizer não pode descrever endereços 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 de memória imediato, seguido de 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. É possível fazer isso globalmente em build/soong/cc/sanitize.go (procure hwasanGlobalOptions) ou no ambiente de processo (tente adb shell echo $HWASAN_OPTIONS para conferir as configurações atuais).

Esse erro também pode acontecer se a memória acessada não estiver mapeada ou alocada por um alocador não compatível com o HWASan. Nesse caso, a tag mem listada no cabeçalho da falha geralmente é 00. Se você tiver acesso ao tombstone completo, pode ser útil consultar o despejo 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 ocorreu um bug ao gerar o relatório de falhas do HWASan. Isso geralmente ocorre devido a um bug no tempo de execução do HWASan. Registre um bug e forneça instruções sobre como reproduzir o problema, se possível.