เครื่องมือเพิ่มประสิทธิภาพที่อยู่

AddressSanitizer (ASan) เป็นเครื่องมือที่ทำงานได้อย่างรวดเร็วโดยใช้คอมไพเลอร์ ข้อบกพร่องหน่วยความจําในโค้ดแบบเนทีฟ

ASan ตรวจพบสิ่งต่อไปนี้

  • สแต็กและฮีปบัฟเฟอร์ล้น/ล้นเกิน
  • การใช้ฮีปหลังจากฟรี
  • การใช้สแต็กนอกขอบเขต
  • Double Free/Wild Free

ASan ทำงานได้ทั้งบน ARM แบบ 32 บิตและ 64 บิต รวมถึง x86 และ x86-64 โอเวอร์เฮด CPU ของ ASan ประมาณ 2 เท่า โอเวอร์เฮดของขนาดโค้ดอยู่ระหว่าง 50% ถึง 2 เท่า และโอเวอร์เฮดหน่วยความจำขนาดใหญ่ (ขึ้นอยู่กับรูปแบบการจัดสรรของคุณ แต่เรียงลำดับ 2x)

Android 10 และ AOSP สาขาหลักบน AArch64 สนับสนุน AddressSanitizer ที่ใช้ฮาร์ดแวร์ (HWASan) เครื่องมือที่คล้ายกันที่มีโอเวอร์เฮดของ RAM ต่ำลงและ ในช่วงข้อบกพร่องที่ตรวจพบได้ HWASan ตรวจพบการใช้สแต็กหลังจากการส่งคืน นอกเหนือจากข้อบกพร่อง ตรวจพบโดย ASan

HWASan มีค่าใช้จ่ายโอเวอร์เฮดของขนาด CPU และโค้ดที่คล้ายกัน แต่มีโอเวอร์เฮดของ RAM น้อยกว่ามาก (15%) HWASan เป็นแบบไม่กำหนดทิศทาง มีค่าแท็กที่เป็นไปได้เพียง 256 ค่า จึงมีค่าคงที่ 0.4% ก็อาจจะเกิดข้อผิดพลาด HWASan ไม่มีเขตสีแดงจำกัดของ ASan สำหรับ การตรวจหารายการส่วนเกินและเขตกักเก็บที่จำกัดสำหรับการตรวจหาการใช้งานหลังการใช้งานฟรี ดังนั้นจึงไม่สำคัญกับ HWASan ว่าข้อมูลที่เกินมาจะมีขนาดเท่าใด หรือใช้งานหน่วยความจำได้นานแค่ไหนแล้ว มีการจัดการดีล ซึ่งทำให้ HWASan ดีกว่า ASan คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ ดีไซน์ HWASan หรือเกี่ยวกับการใช้ HWASan ใน Android

ASan ตรวจพบสแต็ก/โอเวอร์โฟลว์ทั่วโลก นอกเหนือจากฮีปล้น และทำงานได้รวดเร็วโดยมีค่าใช้จ่ายในหน่วยความจำน้อยที่สุด

เอกสารนี้จะอธิบายวิธีสร้างและเรียกใช้ส่วนต่างๆ/อุปกรณ์ Android ทั้งหมดด้วย ASan หากคุณกำลังสร้างแอป SDK/NDK ด้วย ASan โปรดดู ตัวล้างที่อยู่ แทน

ทำความสะอาดไฟล์ปฏิบัติการแต่ละรายการด้วย ASan

เพิ่ม LOCAL_SANITIZE:=address หรือ sanitize: { address: true } ลงใน กฎการสร้างสำหรับไฟล์ปฏิบัติการ คุณสามารถค้นหาโค้ดสำหรับตัวอย่างที่มีอยู่หรือค้นหา เจลล้างพิษอื่นๆ ที่มีให้บริการ

เมื่อตรวจพบข้อบกพร่อง ASan จะพิมพ์รายงานแบบละเอียดทั้งตามมาตรฐาน เอาต์พุตไปยัง logcat แล้วทำให้กระบวนการขัดข้อง

ทำความสะอาดคลังภาพที่แชร์ด้วย ASan

วิธีการทำงานของ ASan นั้น ห้องสมุดที่สร้างด้วย ASan นั้นใช้ได้เฉพาะ ไฟล์ปฏิบัติการที่สร้างขึ้นด้วย ASan

เพื่อทำความสะอาดไลบรารีที่ใช้ร่วมกันซึ่งใช้ในไฟล์สั่งการหลายรายการ ไม่ใช่ทั้งหมด ที่สร้างด้วย ASan คุณต้องมีสำเนา ของไลบรารี 2 ฉบับ วิธีที่แนะนำคือให้เพิ่มข้อมูลต่อไปนี้ลงใน Android.mk สำหรับโมดูลที่เป็นปัญหา

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

การดำเนินการนี้จะทำให้ไลบรารีอยู่ใน /system/lib/asan แทนที่จะเป็น /system/lib จากนั้นเรียกใช้ไฟล์ปฏิบัติการด้วยสิ่งต่อไปนี้

LD_LIBRARY_PATH=/system/lib/asan

สำหรับ Daemon ของระบบ ให้เพิ่มรายการต่อไปนี้ลงในส่วนที่เหมาะสมของ /init.rc หรือ /init.$device$.rc

setenv LD_LIBRARY_PATH /system/lib/asan

ยืนยันว่ากระบวนการใช้ไลบรารีจาก /system/lib/asan เมื่อนำเสนอโดยการอ่าน /proc/$PID/maps ไม่เช่นนั้น คุณอาจต้อง เพื่อปิดใช้งาน SELinux

adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID
# if it is a system service, or may be adb shell stop; adb shell start.

สแต็กเทรซที่ดียิ่งขึ้น

ASan ใช้เครื่องมือคลายปมที่ใช้เฟรมไวท์บอร์ดเพื่อบันทึกการเรียงซ้อน ติดตามสำหรับเหตุการณ์การจัดสรรหน่วยความจำและข้อเสนอตำแหน่งดีลทั้งหมดในโปรแกรม พบบ่อยที่สุด ของ Android สร้างขึ้นโดยไม่ใช้ตัวชี้เฟรม ด้วยเหตุนี้ คุณจึงมักจะได้รับ เพียงแค่ 1 หรือ 2 เฟรมเท่านั้น ในการแก้ไขปัญหานี้ ให้สร้างไลบรารีอีกครั้งด้วย ASan (แนะนำ!) หรือด้วย:

LOCAL_CFLAGS:=-fno-omit-frame-pointer
LOCAL_ARM_MODE:=arm

หรือกำหนดให้มี ASAN_OPTIONS=fast_unwind_on_malloc=0 ในขั้นตอนนี้ ของคุณ รายการหลังอาจใช้ CPU มาก โดยขึ้นอยู่กับ ด้วย

สัญลักษณ์

ในช่วงแรก รายงาน ASan มีการอ้างอิงถึงออฟเซ็ตในไบนารีและแชร์ ห้องสมุด การดูข้อมูลไฟล์และบรรทัดมี 2 วิธีดังนี้

  • ตรวจสอบว่าไบนารี llvm-symbolizer อยู่ใน /system/bin llvm-symbolizer สร้างขึ้นจากแหล่งที่มาใน third_party/llvm/tools/llvm-symbolizer
  • กรองรายงานผ่าน external/compiler-rt/lib/asan/scripts/symbolize.py สคริปต์

วิธีที่ 2 สามารถให้ข้อมูลเพิ่มเติม (เช่น สถานที่ตั้ง file:line แห่ง) เนื่องจาก ความพร้อมใช้งานของไลบรารีสัญลักษณ์ในโฮสต์

ASan ในแอป

ASan มองเห็นโค้ด Java ไม่ได้ แต่ตรวจพบข้อบกพร่องใน JNI ได้ ห้องสมุด คุณต้องสร้างไฟล์ปฏิบัติการด้วย ASan ซึ่ง กรณีนี้คือ /system/bin/app_process(32|64) ช่วงเวลานี้ เปิดใช้งาน ASan ในแอปทั้งหมดบนอุปกรณ์พร้อมกัน ซึ่งเป็น การใช้งานหนัก แต่อุปกรณ์ที่มี RAM 2 GB ควรรองรับได้

เพิ่ม LOCAL_SANITIZE:=address ไว้ใน กฎของบิลด์ app_process ใน frameworks/base/cmds/app_process เพิกเฉย ตอนนี้เป้าหมาย app_process__asan ในไฟล์เดียวกัน ยังคงมีอยู่ ณ เวลาที่คุณอ่านข้อความนี้)

แก้ไขส่วน service zygote ของ system/core/rootdir/init.zygote(32|64).rc ที่เหมาะสมเพื่อเพิ่ม ต่อบรรทัดไปยังบล็อกของบรรทัดที่มีการเยื้องที่มี class main และ เยื้องด้วยจํานวนเท่ากัน:

    setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib
    setenv ASAN_OPTIONS allow_user_segv_handler=true

สร้าง, ซิงค์ adb, Fastboot Flash Boot และรีบูต

ใช้คุณสมบัติการรวม

แนวทางในส่วนก่อนหน้านี้ทำให้ ASan ลงในระบบ (อันที่จริงก็คือทุกองค์ประกอบสืบทอดของ Zygote กระบวนการ) คุณจะเรียกใช้แอปเพียงแอปเดียว (หรือหลายแอป) ด้วย ASan ได้ เพิ่มโอเวอร์เฮดหน่วยความจำบางส่วนเพื่อให้การเริ่มต้นแอปที่ช้าลง

ซึ่งทำได้โดยการเริ่มต้นแอปด้วยพร็อพเพอร์ตี้ wrap. ตัวอย่างต่อไปนี้เรียกใช้แอป Gmail ภายใต้ ASan

adb root
adb shell setenforce 0  # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"

ในบริบทนี้ asanwrapper จะเขียน /system/bin/app_process ใหม่ ไปยัง /system/bin/asan/app_process ซึ่งสร้างขึ้นด้วย ASan และเพิ่ม /system/lib/asan ในตอนเริ่มต้นด้วย เส้นทางการค้นหาไลบรารีแบบไดนามิกได้ วิธีนี้ใช้โดย ASan ไลบรารีจาก /system/lib/asan ควรแปลงเป็นไลบรารีปกติ ใน /system/lib เมื่อทำงานกับ asanwrapper

หากพบข้อบกพร่อง แอปจะขัดข้อง และรายงานจะถูกพิมพ์ไปยัง บันทึก

ทำให้เป้าหมายเสร็จสมบูรณ์

Android 7.0 ขึ้นไปมีการสนับสนุนในการสร้างแพลตฟอร์ม Android ทั้งแพลตฟอร์มด้วย ASan ได้พร้อมกัน (หากคุณกำลังสร้างรุ่นที่สูงกว่า Android 9 การใช้ HWASan ถือเป็นตัวเลือกที่ดีกว่า)

เรียกใช้คำสั่งต่อไปนี้ในโครงสร้างบิลด์เดียวกัน

make -j42
SANITIZE_TARGET=address make -j42

ในโหมดนี้ userdata.img จะมีไลบรารีเพิ่มเติมและต้อง ในอุปกรณ์ด้วย ใช้บรรทัดคำสั่งต่อไปนี้

fastboot flash userdata && fastboot flashall

ระบบจะสร้างไลบรารีที่ใช้ร่วมกัน 2 ชุด ได้แก่ ชุดปกติใน /system/lib (การเรียกใช้ครั้งแรก) และใช้ ASan ใน /data/asan/lib (การเรียกใช้ครั้งที่ 2) ไฟล์ดำเนินการจาก บิลด์ที่ 2 จะเขียนทับบิลด์จากบิลด์แรก ใช้เครื่องดนตรี ASan ไฟล์ปฏิบัติการจะได้รับเส้นทางการค้นหาไลบรารีอื่นที่รวม /data/asan/lib ก่อน /system/lib ผ่านการใช้ /system/bin/linker_asan ใน PT_INTERP

ไดเรกทอรีของออบเจ็กต์ระบบบิลด์จะเข้ารหัสออบเจ็กต์ตัวกลางเมื่อ ค่า $SANITIZE_TARGET มีการเปลี่ยนแปลง บังคับให้มีการสร้างใหม่ กำหนดเป้าหมายขณะที่เก็บไบนารีที่ติดตั้งไว้ภายใต้ /system/lib

เป้าหมายบางอย่างไม่สามารถสร้างด้วย ASan ได้:

  • ไฟล์ปฏิบัติการที่ลิงก์แบบคงที่
  • เป้าหมาย LOCAL_CLANG:=false
  • LOCAL_SANITIZE:=false ไม่ใช่ ASan สำหรับ SANITIZE_TARGET=address

ระบบจะข้ามไฟล์ปฏิบัติการเช่นนี้ในบิลด์ SANITIZE_TARGET และ เวอร์ชันจากการเรียกใช้ครั้งแรกยังคงอยู่ใน /system/bin

ห้องสมุดลักษณะนี้สร้างขึ้นโดยไม่มี ASan มี ASan บางอย่าง จากไลบรารีแบบคงที่ที่ต้องใช้

เอกสารประกอบ