HWASan 보고서 이해하기

HWASan 도구가 메모리 버그를 감지하면 프로세스가 abort()에 의해 종료되고 보고서가 stderr 및 Logcat에 출력됩니다. Android의 모든 네이티브 충돌과 마찬가지로 HWASan 오류는 /data/tombstones에서 찾을 수 있습니다.

일반적인 네이티브 충돌과 달리 HWASan은 Tombstone 상단 근처의 'Abort message' 필드에 추가 정보를 전달합니다. 아래에서 힙 기반 비정상 종료 샘플을 확인하세요(스택 버그의 경우, 아래에서 스택 관련 섹션 참고).

예시 보고서

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
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 …]

이 보고서는 AddressSanitizer 보고서와 매우 유사합니다. AddressSanitizer 보고서와 다른 것은 거의 모든 HWASan 버그가 'tag-mismatch'라는 점입니다. 즉, 포인터 태그가 상응하는 메모리 태그와 일치하지 않는 메모리 액세스입니다. 원인은 다음 중 하나일 수 있습니다.

  • 스택 또는 힙에서 범위를 벗어난 액세스
  • 힙에서 해제 후 사용
  • 스택에서 반환 후 사용

섹션

다음은 HWASan 보고서의 각 섹션에 관한 설명입니다.

액세스 오류

잘못된 메모리 액세스와 관련하여 다음과 같은 정보가 포함됩니다.

  • 액세스 유형("READ" 또는 "WRITE")
  • 액세스 크기(액세스하려고 시도한 바이트 수)
  • 액세스의 스레드 번호
  • 포인터 및 메모리 태그(고급 디버깅의 경우)

액세스 스택 트레이스

잘못된 메모리 액세스의 스택 트레이스입니다. 기호화하려면 기호화 섹션을 참고하세요.

원인

잘못된 액세스의 잠재적 원인입니다. 후보가 여러 개라면 가능성이 높은 항목에서 낮은 항목 순으로 정렬됩니다. 이다음에 잠재적 원인에 대한 세부정보가 표시됩니다. HWASan은 다음과 같은 원인을 진단할 수 있습니다.

  • use-after-free
  • stack tag-mismatch: stack use-after-return/use after-scope 또는 범위를 벗어난 액세스일 수 있습니다.
  • heap-buffer-overflow
  • global-overflow

메모리 정보

액세스 중인 메모리에 관해 HWASan이 알고 있는 정보를 설명하며, 정보는 버그 유형에 따라 다를 수 있습니다.

버그 유형 원인 보고서 형식
tag-mismatch use-after-free

<address> is located N bytes inside of M-byte region [<start>, <end>)
  freed by thread T0 here:
heap-buffer-overflow 이는 언더플로일 수도 있습니다.

<address> is located N bytes to the right of M-byte region [<start>, <end>)
  allocated here:
stack tag-mismatch 스택 보고서는 오버플로/언더플로와 use-after-return 버그를 구분하지 않습니다. 또한 오류의 원인인 스택 할당을 찾으려면 오프라인 기호화 단계가 필요합니다. 아래의 스택 보고서 이해하기 섹션을 참고하세요.
invalid-free use-after-free 이중 해제 버그입니다.

<address> is located N bytes inside of M-byte region [<start>, <end>)
  freed by thread T0 here:
cannot describe address 와일드 해제 버그(이전에 할당된 적 없는 메모리 해제) 또는 할당된 메모리가 HWASan의 사용 가능한 버퍼에서 제거된 후의 이중 해제 버그입니다.
0x… is HWAsan shadow memory. 애플리케이션이 HWASan 내부에 있는 메모리를 해제하려고 했기 때문에 당연히 와일드 해제 버그입니다.

할당 해제 스택 트레이스

메모리가 할당 해제된 경우의 스택 트레이스입니다. use-after-free 또는 invalid-free 버그인 경우에만 표시됩니다. 기호화하려면 기호화 섹션을 참고하세요.

할당 스택 트레이스

메모리가 할당된 경우의 스택 트레이스입니다. 기호화하려면 기호화 섹션을 참고하세요.

고급 디버깅 정보

HWASan 보고서에는 다음과 같은 고급 디버깅 정보도 일부 포함되어 있습니다(순서대로).

  1. 프로세스의 스레드 목록
  2. 프로세스의 스레드 목록
  3. 오작동하는 메모리 근처의 메모리 태그 값
  4. 메모리 액세스 시점의 레지스터 덤프

메모리 태그 덤프

태그 메모리 덤프를 사용하면 포인터 태그와 태그가 동일한 근처의 메모리 할당을 찾을 수 있습니다. 큰 오프셋으로 범위를 벗어난 액세스를 가리킬 수 있습니다. 태그 1개는 메모리 16바이트에 해당합니다. 포인터 태그는 주소의 상위 8비트입니다. 태그 메모리 덤프는 힌트를 제공할 수 있습니다. 예를 들어 다음은 버퍼 오버플로(오른쪽)입니다.

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  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
(포인터 태그와 일치하는 왼쪽 'ad' 태그의 6 × 16 = 96바이트 실행입니다.)

할당 크기가 16의 배수가 아닌 경우 크기의 나머지는 메모리 태그로 저장되고 태그는 짧은 그래뉼 태그로 저장됩니다. 위의 예에서는 굵게 표시되어 있으며 할당 태그가 지정된 ad 바로 뒤에 태그 5c의 5 × 16 + 4 = 84바이트 할당이 있습니다.

0 메모리 태그(예: tags: ad/00 (ptr/mem))는 일반적으로 stack-use-after-return 버그를 나타냅니다.

레지스터 덤프

HWASan 보고서의 레지스터 덤프는 잘못된 메모리 액세스를 실행한 실제 명령에 해당합니다. 일반 Android 신호 핸들러의 또 다른 레지스터 덤프 ignore the second one이 뒤에 옵니다. 이 레지스터 덤프는 HWASan이 abort()를 호출할 때 표시되며 버그와는 관련이 없습니다.

기호화

스택 트레이스에서 함수 이름과 줄 번호를 가져오고 use-after-scope 버그의 변수 이름을 가져오려면 오프라인 기호화 단계가 필요합니다.

최초 설정: llvm-symbolizer 설치

기호화하려면 시스템에 llvm-symbolizer가 설치되어 있고 $PATH에서 액세스할 수 있어야 합니다. Debian에서는 sudo apt install llvm을 사용하여 설치할 수 있습니다.

기호 파일 가져오기

기호화를 위해서는 기호가 포함된 제거되지 않은 바이너리가 필요합니다. 빌드 유형에 따라 찾을 수 있는 위치가 달라집니다.

로컬 빌드의 경우 기호 파일을 out/target/product/<product>/symbols/에서 찾을 수 있습니다.

AOSP 빌드(예: Flashstation에서 플래시됨)의 경우 빌드는 Android CI에서 찾을 수 있습니다. 빌드의 '아티팩트'에 `${PRODUCT}-symbols-${BUILDID}.zip` 파일이 있습니다.

조직의 내부 빌드는 기호 파일 가져오기와 관련된 조직 문서를 참고하세요.

기호화

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

스택 보고서 이해하기

스택 변수에서 발생하는 버그의 경우 HWASan 보고서에 다음과 같은 세부정보가 포함됩니다.

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)
  [...]
	

HWASan은 스택 버그를 파악할 수 있도록 과거에 발생한 스택 프레임을 추적합니다. 현재 HWASan은 버그 신고에서 사람이 읽을 수 있는 콘텐츠로 이를 변환하지 않기 때문에 추가 기호화 단계가 필요합니다.

문제 해결

'HWAddressSanitizer can not describe address in more detail.'

가끔 HWASan에서 이전 메모리 할당에 관한 정보를 저장할 공간이 부족할 수 있습니다. 이 경우 보고서에 즉시 메모리 액세스를 위한 스택 트레이스 하나만 포함되고 이어서 다음 메모가 표시됩니다.

  HWAddressSanitizer can not describe address in more detail.

테스트를 여러 번 실행하면 이 문제가 해결되는 경우도 있습니다. 또 다른 옵션은 HWASan 기록 크기를 늘리는 것입니다. build/soong/cc/sanitize.go(hwasanGlobalOptions 찾기) 또는 프로세스 환경(adb shell echo $HWASAN_OPTIONS를 시도하여 현재 설정 확인하기)에서 전역적으로 실행할 수 있습니다.

'nested bug in the same thread'

이는 HWASan 비정상 종료 보고서를 생성하는 동안 버그가 발생했음을 의미합니다. 일반적으로 HWASan 런타임 내 버그로 인한 문제입니다. 버그를 신고하고 가능한 경우 문제를 재현하는 방법에 관한 설명을 제공해 주세요.