ทำความเข้าใจรายงาน HWASan

เมื่อเครื่องมือ HWASan ตรวจพบข้อบกพร่องด้านหน่วยความจำ ระบบจะสิ้นสุดกระบวนการด้วย abort() และพิมพ์รายงานไปยัง stderr และ logcat ข้อผิดพลาด HWASan จะอยู่ใน/data/tombstones เช่นเดียวกับข้อผิดพลาดข้อขัดข้องทั้งหมดในเนทีฟบน Android

รายงานตัวอย่าง

เมื่อเทียบกับข้อขัดข้องทั่วไปของระบบ HWASan จะมีข้อมูลเพิ่มเติมในช่อง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 ข้อบกพร่องของ HWASan เกือบทั้งหมดนั้นแตกต่างจากข้อบกพร่องข้างต้นตรงที่เป็นข้อผิดพลาดการจับคู่แท็กไม่ตรงกัน กล่าวคือ การเข้าถึงหน่วยความจำที่แท็กพอยน์เตอร์ไม่ตรงกับแท็กหน่วยความจำที่เกี่ยวข้อง ซึ่งอาจเป็นรายการใดก็ได้ต่อไปนี้

  • การเข้าถึงที่อยู่นอกขอบเขตบนกองหรือกองซ้อน
  • ข้อผิดพลาดการใช้หลังจากการปลดปล่อยในฮีป
  • ข้อผิดพลาดการใช้หลังจากการคืนค่าในสแต็ก

ส่วน

ต่อไปนี้คือคำอธิบายของแต่ละส่วนในรายงาน HWASan

ข้อผิดพลาดในการเข้าถึง

มีข้อมูลเกี่ยวกับการเข้าถึงหน่วยความจำที่ไม่ถูกต้อง ซึ่งรวมถึงข้อมูลต่อไปนี้

  • ประเภทการเข้าถึง (READ เทียบกับ WRITE)
  • ขนาดการเข้าถึง (จำนวนไบต์ที่พยายามเข้าถึง)
  • หมายเลขชุดข้อความของการเข้าถึง
  • แท็กพอยน์เตอร์และหน่วยความจํา (สําหรับการแก้ไขข้อบกพร่องขั้นสูง)

เข้าถึงสแต็กเทรซ

สแต็กเทรซของการเข้าถึงหน่วยความจำที่ไม่ถูกต้อง ดูสัญลักษณ์เพื่อแสดงสัญลักษณ์

สาเหตุ

สาเหตุที่อาจทำให้การเข้าถึงไม่ถูกต้อง หากมีคำที่ตรงกันหลายรายการ ระบบจะแสดงคำเหล่านั้นตามลำดับความน่าจะเป็นจากมากไปน้อย อยู่ก่อนข้อมูลโดยละเอียดเกี่ยวกับสาเหตุที่เป็นไปได้ HWASan สามารถวิเคราะห์สาเหตุต่อไปนี้

  • การใช้งานหลังจากช่วงทดลองใช้ฟรี
  • แท็กกองซ้อนไม่ตรงกัน ซึ่งอาจเป็นการใช้กองซ้อนหลังการคืนค่า การใช้กองซ้อนหลังขอบเขต หรืออยู่นอกขอบเขต
  • บัฟเฟอร์ฮีปล้น
  • รายการที่เกินขีดจำกัด

ข้อมูลหน่วยความจำ

อธิบายสิ่งที่ HWASan ทราบเกี่ยวกับหน่วยความจำที่เข้าถึง และอาจแตกต่างกันไปตามประเภทข้อบกพร่อง

ประเภทข้อบกพร่อง สาเหตุ รูปแบบรายงาน
แท็กไม่ตรงกัน การใช้งานหลังจากช่วงทดลองใช้ฟรี ใช้รูปแบบรายงานนี้
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
บัฟเฟอร์ฮีปล้น โปรดทราบว่าการดำเนินการนี้อาจเป็นค่าที่ต่ำกว่าขอบเขตล่างด้วย
<address> is located N bytes to the right of M-byte region [<start>, <end>)
allocated here:
แท็กกองไม่ตรงกัน รายงานกองจะไม่แยกความแตกต่างระหว่างข้อบกพร่องที่เกิดจากการรับค่าเกินหรือรับค่าไม่เพียงพอกับข้อบกพร่องที่เกิดจากการใช้หลังจากการคืนค่า นอกจากนี้ หากต้องการค้นหาการจัดสรรสแต็กที่เป็นสาเหตุของข้อผิดพลาด คุณจะต้องทําขั้นตอนการสร้างสัญลักษณ์แบบออฟไลน์ โปรดดูทําความเข้าใจรายงานสแต็ก
ฟรีไม่ถูกต้อง การใช้งานหลังจากช่วงทดลองใช้ฟรี ข้อบกพร่องการเรียกใช้หน่วยความจำซ้ำ หากเกิดกรณีนี้เมื่อกระบวนการปิดลง อาจบ่งบอกถึงการละเมิด ODR
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
อธิบายที่อยู่ไม่ได้ อาจเป็น Free ที่ไม่ถูกต้อง (หน่วยความจำที่ไม่มีการจัดสรรมาก่อน) หรือ Free ซ้ำหลังจากที่หน่วยความจำที่จัดสรรถูกนำออกจากบัฟเฟอร์ว่างของ HWASan
0x... คือหน่วยความจำเงาของ HWAsan หน่วยความจําที่ปล่อยออกมาอย่างอิสระ เนื่องจากแอปพยายามที่จะเพิ่มพื้นที่ว่างในหน่วยความจําภายใน HWASan

สแต็กเทรซการยกเลิกการจัดสรร

สแต็กเทรซของตำแหน่งที่มีการยกเลิกการจัดสรรหน่วยความจำ แสดงเฉพาะสำหรับข้อบกพร่องการใช้หลังจากยกเลิกการจองหรือข้อบกพร่องที่ไม่เป็นโมฆะ ดูการกำหนดสัญลักษณ์เพื่อกำหนดสัญลักษณ์

สแต็กเทรซการจัดสรร

สแต็กเทรซของตำแหน่งที่มีการจัดสรรหน่วยความจำ ดูการกำหนดสัญลักษณ์เพื่อกำหนดสัญลักษณ์

ข้อมูลการแก้ไขข้อบกพร่องขั้นสูง

รายงาน 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 ระบบจะจัดเก็บส่วนที่เหลือของขนาดเป็นแท็กหน่วยความจํา และจัดเก็บแท็กเป็นแท็ก Granule แบบสั้น ในตัวอย่างก่อนหน้านี้ ถัดจากการกําหนดค่าแบบตัวหนาที่ติดแท็ก ad เรามีการจัดสรรแท็ก 5c เป็น 5 × 16 + 4 = 84 ไบต์

แท็กหน่วยความจำเป็น 0 (เช่น tags: ad/00 (ptr/mem)) บ่งบอกถึงข้อบกพร่องการใช้สแต็กหลังจากการคืนค่า

ดัมพ์รีจิสทรี

การดัมพ์รีจิสเตอร์ในรายงาน HWASan สอดคล้องกับคำสั่งที่ดำเนินการเข้าถึงหน่วยความจำที่ไม่ถูกต้อง การดัมพ์นี้ตามด้วยการดัมพ์รีจิสเตอร์อีกรายการจากตัวแฮนเดิลสัญญาณ Android ปกติ ละเว้นการดัมพ์ที่ 2 เนื่องจากเป็นการดัมพ์เมื่อ HWASan เรียกใช้ abort() และไม่เกี่ยวข้องกับข้อบกพร่อง

การใช้สัญลักษณ์

หากต้องการดูชื่อฟังก์ชันและหมายเลขบรรทัดในสแต็กเทรซ (และดูชื่อตัวแปรสำหรับข้อบกพร่องการใช้หลังจากขอบเขต) คุณต้องทำตามขั้นตอนการแปลงสัญลักษณ์แบบออฟไลน์

การตั้งค่าครั้งแรก: ติดตั้ง llvm-symbolizer

ตัวอย่างเช่น ระบบของคุณต้องติดตั้ง llvm-symbolizer และเข้าถึงได้จาก $PATH ใน Debian คุณจะติดตั้งได้โดยใช้ sudo apt install llvm

รับไฟล์สัญลักษณ์

สำหรับการระบุสัญลักษณ์ เราต้องใช้ไบนารีที่ไม่มีการถอดสัญลักษณ์ออก ตำแหน่งของไฟล์จะขึ้นอยู่กับประเภทของบิลด์ ดังนี้

  • สำหรับบิลด์ในเครื่อง ไฟล์สัญลักษณ์จะอยู่ใน out/target/product/<product>/symbols/
  • สำหรับบิลด์ AOSP (เช่น แฟลชจาก Android Flash Tool) บิลด์จะอยู่ใน 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 จะไม่เปลี่ยนรูปแบบข้อมูลเหล่านี้ให้เป็นเนื้อหาที่มนุษย์เข้าใจได้ในรายงานข้อบกพร่อง และต้องใช้ขั้นตอนการเปลี่ยนรูปแบบเพิ่มเติม

การละเมิด ODR

ข้อบกพร่องบางรายการที่เกิดจากการใช้หลังจากการปลดปล่อยหน่วยความจำซึ่ง HWASan รายงานอาจบ่งบอกถึงการละเมิดกฎคําจํากัดความเดียว (ODR) การละเมิด ODR เกิดขึ้นเมื่อมีการกําหนดตัวแปรเดียวกันหลายครั้งในโปรแกรมเดียวกัน ซึ่งหมายความว่าระบบจะทำลายตัวแปรหลายครั้ง ซึ่งอาจทําให้เกิดข้อผิดพลาด "ใช้หลังจากยกเลิกการจัดสรรแล้ว"

หลังจากการทำสัญลักษณ์ การละเมิด ODR จะแสดงข้อผิดพลาดการใช้หลังจากการปลดปล่อยด้วย __cxa_finalize ทั้งในสแต็กการเข้าถึงที่ไม่ถูกต้องและสแต็กปลดปล่อยที่นี่ กอง previously allocated here มี __dl__ZN6soinfo17call_constructorsEv และควรชี้ไปที่ตําแหน่งในโปรแกรมที่กําหนดตัวแปรที่สูงขึ้นในกอง

การใช้ไลบรารีแบบคงที่อาจละเมิด ODR หากมีการลิงก์ไลบรารีแบบคงที่ซึ่งกำหนดตัวแปรส่วนกลาง C++ เข้ากับไลบรารีที่ใช้ร่วมกันหรือไฟล์ปฏิบัติการหลายรายการ อาจมีการกำหนดสัญลักษณ์เดียวกันหลายรายการในพื้นที่ที่อยู่เดียวกัน ซึ่งทำให้เกิดข้อผิดพลาด ODR

การแก้ปัญหา

ส่วนนี้จะอธิบายข้อผิดพลาดบางประการและวิธีแก้ไข

HWAddressSanitizer อธิบายที่อยู่อย่างละเอียดไม่ได้

บางครั้ง HWASan อาจมีพื้นที่ไม่เพียงพอสำหรับข้อมูลเกี่ยวกับการจองหน่วยความจำที่ผ่านมา ในกรณีนี้ รายงานจะมีสแต็กเทรซเพียงรายการเดียวสําหรับการเข้าถึงหน่วยความจําโดยตรง ตามด้วยหมายเหตุต่อไปนี้

HWAddressSanitizer can not describe address in more detail.

ในบางกรณี คุณสามารถแก้ปัญหานี้ได้โดยทำการทดสอบหลายครั้ง อีกตัวเลือกหนึ่งคือการทำให้ขนาดประวัติ HWASan เพิ่มขึ้น คุณทําแบบรวมได้ใน build/soong/cc/sanitize.go (มองหา hwasanGlobalOptions) หรือในสภาพแวดล้อมกระบวนการ (ลองใช้ adb shell echo $HWASAN_OPTIONSเพื่อดูการตั้งค่าปัจจุบัน)

ข้อผิดพลาดนี้ยังอาจเกิดขึ้นได้หากหน่วยความจำที่เข้าถึงไม่ได้แมปหรือจัดสรรโดยตัวจัดสรรที่ไม่ทราบว่ามี HWASan ในกรณีนี้ แท็ก mem ที่แสดงในส่วนหัวของข้อขัดข้องมักจะเป็น 00 หากคุณมีสิทธิ์เข้าถึงรายการที่ลบไปแล้วแบบเต็ม คุณอาจต้องดูข้อมูลการแมปหน่วยความจำเพื่อดูว่าที่อยู่นั้นอยู่ในการแมปใด (หากมี)

ข้อบกพร่องที่ซ้อนกันในชุดข้อความเดียวกัน

ซึ่งหมายความว่ามีข้อบกพร่องขณะสร้างรายงานข้อขัดข้องของ HWASan ซึ่งโดยปกติแล้ว ปัญหานี้เกิดจากข้อบกพร่องในรันไทม์ HWASan รายงานข้อบกพร่องและระบุวิธีการทําให้ปัญหาเกิดซ้ำ (หากเป็นไปได้)