เอกสารนี้แสดงวิธีเปิดใช้เครื่องมือแก้ไขข้อบกพร่องพิเศษเมื่อใช้ AGDE เครื่องมือเหล่านี้ช่วยแก้ปัญหาการเสียหายของหน่วยความจำและข้อผิดพลาดในการเขียนทับที่วินิจฉัยได้ยาก
HWAddress Sanitizer และ Address Sanitizer
HWAddress Sanitizer (HWASan) และ Address Sanitizer (ASan) เป็นเครื่องมือแก้ไขข้อบกพร่องการเสียหายของหน่วยความจําที่ช่วยแก้ไขข้อบกพร่องการเสียหายของหน่วยความจําและการเขียนทับ เช่นข้อผิดพลาดต่อไปนี้
- การล้นและการลบล้างบัฟเฟอร์ของกองซ้อน
- การล้นและการไม่เพียงพอของบัฟเฟอร์กองขยะ
- การใช้สแต็กนอกขอบเขต
- ข้อผิดพลาด Double free และ Wild free
- การใช้สแต็กหลังจากการกลับมา (HWASan เท่านั้น)
เราขอแนะนำให้เปิดใช้ HWASan หรือ ASan เฉพาะในกรณีที่กำลังแก้ไขข้อบกพร่องหรือเป็นส่วนหนึ่งของการทดสอบอัตโนมัติเท่านั้น แม้ว่าเครื่องมือเหล่านี้จะมีประสิทธิภาพ แต่การใช้เครื่องมือเหล่านี้ก็อาจส่งผลให้มีการหักคะแนน
ลักษณะการทํางานของรันไทม์
เมื่อเปิดใช้ ทั้ง HWASan และ ASan จะตรวจสอบข้อบกพร่องของหน่วยความจำในแอปโดยอัตโนมัติ
หากตรวจพบข้อผิดพลาดเกี่ยวกับหน่วยความจำ แอปจะขัดข้องพร้อมข้อผิดพลาด SIGBART
(signal abort) และพิมพ์ข้อความโดยละเอียดไปยัง logcat ระบบจะเขียนสำเนาของข้อความลงในไฟล์ภายใต้ /data/tombstones
ด้วย
ข้อความแสดงข้อผิดพลาดจะมีลักษณะคล้ายกับตัวอย่างต่อไปนี้
ERROR: HWAddressSanitizer: tag-mismatch on address 0x0042a0826510 at pc 0x007b24d90a0c
WRITE of size 1 at 0x0042a0826510 tags: 32/3d (ptr/mem) in thread T0
#0 0x7b24d90a08 (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x2a08)
#1 0x7b8f1e4ccc (/apex/com.android.art/lib64/libart.so+0x198ccc)
#2 0x7b8f1db364 (/apex/com.android.art/lib64/libart.so+0x18f364)
#3 0x7b8f2ad8d4 (/apex/com.android.art/lib64/libart.so+0x2618d4)
0x0042a0826510 is located 0 bytes to the right of 16-byte region [0x0042a0826500,0x0042a0826510)
allocated here:
#0 0x7b92a322bc (/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so+0x212bc)
#1 0x7b24d909e0 (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x29e0)
#2 0x7b8f1e4ccc (/apex/com.android.art/lib64/libart.so+0x198ccc)
สิ่งที่ต้องมีก่อน
ข้อกำหนดของ HWASan
วิธีใช้ HWASan
- คุณต้องใช้ AGDE 24.1.99 ขึ้นไป
- แอปต้องสร้างโดยใช้ NDK 26 ขึ้นไป
- แอปต้องสร้างด้วย SDK เป้าหมาย 34 ขึ้นไป
- เป้าหมายต้องเป็นอุปกรณ์
arm64-v8a
ที่ใช้ Android 14 (API ระดับ 34) ขึ้นไป
ใช้ไลบรารีมาตรฐาน C++ ที่แชร์ในโปรเจ็กต์
ASan เข้ากันไม่ได้กับการจัดการข้อยกเว้น C++ เมื่อใช้ libc++_static
เนื่องจากปัญหาที่ทราบแล้ว ปัญหานี้จะไม่เกิดขึ้นเมื่อใช้ libc++_shared
HWASan มีการใช้งานโอเปอเรเตอร์ new
และ delete
ของตัวเอง ซึ่งจะใช้ไม่ได้หากมีการลิงก์ไลบรารีมาตรฐานแบบคงที่ไว้ในโปรเจ็กต์
หากต้องการเปลี่ยนการตั้งค่านี้ โปรดดูส่วนการลิงก์คลังมาตรฐาน C++ ของเอกสารนี้
เปิดใช้การสร้างเคอร์เซอร์เฟรม
HWASan และ ASan ใช้โปรแกรมยกเลิกการซ้อนที่ทำงานเร็วซึ่งอิงตามตัวชี้เฟรมเพื่อสร้างข้อมูลการติดตามสแต็กสำหรับเหตุการณ์การจัดสรรและการยกเลิกการจัดสรรหน่วยความจำ ซึ่งหมายความว่าคุณต้องเปิดใช้การสร้างเคอร์เซอร์เฟรมในการตั้งค่าคอมไพเลอร์ C++ เพื่อใช้ฟีเจอร์เหล่านี้ กล่าวคือ คุณต้องปิดใช้การเพิ่มประสิทธิภาพการละเว้นเคอร์เซอร์เฟรม
หากต้องการเปลี่ยนการตั้งค่านี้ โปรดดูส่วนการเปิดใช้การสร้างเคอร์เซอร์เฟรมของเอกสารนี้
การกำหนดค่าโปรเจ็กต์ Visual Studio ให้ใช้ HWASan หรือ ASan
การเปิดใช้ HWASan หรือ ASan
หากต้องการเปิดใช้ HWASan หรือ ASan ให้ไปที่พร็อพเพอร์ตี้การกําหนดค่า > ทั่วไปในหน้าพร็อพเพอร์ตี้ของโปรเจ็กต์
รูปที่ 1: ตัวเลือกพร็อพเพอร์ตี้ของโปรเจ็กต์ในหน้าต่าง Visual Studio Solution Explorer
รูปที่ 2: การตั้งค่า Address Sanitizer (ASan) ในพร็อพเพอร์ตี้ทั่วไปของโปรเจ็กต์
หากต้องการเปิดใช้ HWASan สําหรับโปรเจ็กต์ ให้เปลี่ยนการตั้งค่า Address Sanitizer (ASan) เป็น Hardware ASan Enabled (fsanitize=hwaddress)
หากต้องการเปิดใช้ ASan สําหรับโปรเจ็กต์ ให้เปลี่ยนการตั้งค่า Address Sanitizer (ASan) เป็น ASan Enabled (fsanitize=address)
การเปิดใช้การสร้างเคอร์เซอร์เฟรม
การสร้างตัวชี้เฟรมจะควบคุมโดยการตั้งค่าคอมไพเลอร์ C/C++ ละเว้นตัวชี้เฟรม และสามารถดูได้ในหน้าพร็อพเพอร์ตี้ของโปรเจ็กต์ในส่วนพร็อพเพอร์ตี้การกําหนดค่า > C/C++ > การเพิ่มประสิทธิภาพ
รูปที่ 3: ตําแหน่งการตั้งค่าละเว้นเคอร์เซอร์เฟรม
เมื่อใช้ HWASan หรือ ASan ให้ตั้งค่าละเว้นตัวชี้เฟรมเป็นไม่ (-fno-omit-frame-pointer)
การลิงก์คลังมาตรฐาน C++ ในโหมดไลบรารีที่ใช้ร่วมกัน
การตั้งค่าโหมด linker สําหรับคลังมาตรฐาน C++ จะอยู่ในหน้าพร็อพเพอร์ตี้ของโปรเจ็กต์ในส่วนพร็อพเพอร์ตี้การกําหนดค่า > ทั่วไป ในส่วนค่าเริ่มต้นของโปรเจ็กต์
รูปที่ 4: ตําแหน่งที่จะพบการตั้งค่าโหมด linker สําหรับคลังมาตรฐาน C++
ขณะใช้ HWASan หรือ ASan ให้ตั้งค่าการใช้ STL เป็นใช้คลังมาตรฐาน C++ (.so) ค่านี้จะลิงก์ไลบรารีมาตรฐาน C++ เข้ากับโปรเจ็กต์ของคุณเป็นไลบรารีที่แชร์ ซึ่งจำเป็นต่อการทำงานที่ถูกต้องของ HWASan และ ASan
การสร้างการกำหนดค่าการสร้างสําหรับการใช้โปรแกรมตรวจสอบที่อยู่ที่ปลอดภัย
หากต้องการใช้ HWASan หรือ ASan ชั่วคราว คุณอาจไม่ต้องการสร้างการกำหนดค่าบิลด์ใหม่เพื่อใช้กับเครื่องมือเหล่านี้เพียงอย่างเดียว กรณีนี้อาจเกิดขึ้นเมื่อโปรเจ็กต์มีขนาดเล็ก คุณกำลังสำรวจฟีเจอร์ หรือกำลังแก้ปัญหาที่คุณพบระหว่างการทดสอบ
อย่างไรก็ตาม หากพบว่ามีประโยชน์และวางแผนที่จะใช้เป็นประจำ คุณอาจพิจารณาสร้างการกำหนดค่าบิลด์ใหม่สำหรับ HWASan หรือ ASan ตามที่แสดงในตัวอย่าง Teapot คุณอาจทำเช่นนี้ในกรณีต่างๆ เช่น เรียกใช้ Address Sanitizer เป็นประจำเป็นส่วนหนึ่งของการทดสอบหน่วย หรือระหว่างการทดสอบการทำงานเบื้องต้นของเกมข้ามคืน
การสร้างการกำหนดค่าบิลด์แยกต่างหากอาจมีประโยชน์อย่างยิ่งหากคุณมีโปรเจ็กต์ขนาดใหญ่ที่ใช้ไลบรารีของบุคคลที่สามจำนวนมาก ซึ่งปกติแล้วคุณจะต้องลิงก์แบบคงที่กับไลบรารีมาตรฐาน C++ การกําหนดค่าบิลด์เฉพาะจะช่วยตรวจสอบว่าการตั้งค่าโปรเจ็กต์ถูกต้องอยู่เสมอ
หากต้องการสร้างการกำหนดค่าบิลด์ ให้คลิกปุ่มเครื่องมือจัดการการกําหนดค่า… จากหน้าพร็อพเพอร์ตี้ของโปรเจ็กต์ แล้วเปิดเมนูแบบเลื่อนลงการกําหนดค่าโซลูชันที่ใช้งานอยู่ จากนั้นเลือก
การใช้ HWASan กับเครื่องมือจัดสรรหน่วยความจำที่กำหนดเอง
HWASan จะสกัดกั้นหน่วยความจำที่จัดสรรผ่าน malloc
(หรือ new
) โดยอัตโนมัติเพื่อให้สามารถแทรกแท็กลงในพอยน์เตอร์และตรวจสอบการจับคู่แท็กที่ไม่ตรงกัน
อย่างไรก็ตาม เมื่อใช้ตัวจัดสรรหน่วยความจําที่กําหนดเอง HWASan จะไม่สามารถดักรับเมธอดการจัดสรรหน่วยความจําที่กําหนดเองโดยอัตโนมัติ ดังนั้น หากต้องการใช้ HWASan กับตัวจัดสรรหน่วยความจำที่กำหนดเอง ให้เครื่องมือตัวจัดสรรหน่วยความจำเพื่อเรียกใช้ HWASan อย่างชัดแจ้ง ซึ่งทําได้โดยใช้โค้ดเพียงไม่กี่บรรทัด
สิ่งที่ต้องมีก่อน
วิธีการ HWASan ที่คุณจำเป็นต้องเรียกมีการกำหนดไว้ในส่วนหัวนี้
#include "sanitizer/hwasan_interface.h"
เครื่องมือวัดผลวิธีการจัดสรรหน่วยความจํา
จัดสรรออบเจ็กต์ที่ความละเอียดและการจัดแนวบล็อก 16 ไบต์ เช่น หากคุณมีตัวจัดสรรพูลที่ให้บริการออบเจ็กต์ขนาดคงที่ 24 ไบต์ ให้ปัดเศษการจัดสรรขึ้นเป็น 32 ไบต์ และจัดแนวเป็น 16 ไบต์
สร้างแท็ก 8 บิต แท็กต้องไม่ใช้ค่า 0-16 เนื่องจากค่าเหล่านั้นสงวนไว้สําหรับการใช้งานภายใน
เปิดใช้ HWASan เพื่อเริ่มติดตามพื้นที่หน่วยความจำด้วยแท็กนั้น
__hwasan_tag_memory((void*) address, tag, size);
แทรกแท็กไปยัง 8 บิตบนสุดของตัวชี้
address = __hwasan_tag_pointer((void*) address, tag);
เครื่องมือวัดวิธีการเพิ่มพื้นที่หน่วยความจำ
รีเซ็ตแท็กสำหรับภูมิภาคหน่วยความจำเพื่อให้การเข้าถึงเพิ่มเติมผ่านพอยน์เตอร์ที่ติดแท็กที่มีอยู่ไม่สำเร็จ
__hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), 0, size);
การทำงานกับพูลออบเจ็กต์ที่จัดสรรไว้ล่วงหน้า
หากตัวจัดสรรหน่วยความจำจัดสรรพื้นที่หน่วยความจำล่วงหน้าสำหรับออบเจ็กต์ในพูลและส่งคืนออบเจ็กต์กลับไปยังพูลแทนที่จะยกเลิกการจัดสรรหน่วยความจำจริง วิธีการยกเลิกการจัดสรรหน่วยความจำจะเขียนทับแท็กสำหรับหน่วยความจำและพอยน์เตอร์ด้วยค่าใหม่ได้โดยตรง ดังนี้
```
__hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), tag, size);
ptr = __hwasan_tag_pointer((void*)ptr, tag);
```
หากใช้เทคนิคนี้ วิธีการจัดสรรของคุณไม่จําเป็นต้องติดแท็กพอยน์เตอร์หรือบล็อกหน่วยความจํา แต่ให้ติดแท็กพอยน์เตอร์และบล็อกหน่วยความจําเมื่อคุณจัดสรรออบเจ็กต์ล่วงหน้าในพูล ดูตัวอย่างที่ใช้สไตล์นี้ได้ที่ PoolAllocator sample