أداة AddressSanitizer (ASan) هي أداة سريعة مستندة إلى المُجمِّع لرصد أخطاء الذاكرة في الرموز البرمجية الأصلية.
يرصد ASan ما يلي:
- فائض/نقص سعة المخزن المؤقت للذاكرة المكدس والذاكرة العشوائية
- استخدام الذاكرة لأخذ لقطات لعناصر متعددة بعد تحريرها
- استخدام الحزمة خارج النطاق
- رسوم مجانية مزدوجة/رسوم مجانية بدون قيود
يعمل ASan على كل من معالِج ARM بإصدارَي 32 و64 بت، بالإضافة إلى x86 وx86-64. تبلغ النفقات العامة لوحدة المعالجة المركزية في ASan ضعفًا تقريبًا، وتتراوح النفقات العامة لحجم الرمز البرمجي بين% 50 وضعف التكلفة، وتبلغ النفقات العامة للذاكرة قيمة كبيرة (تعتمد على أنماط التخصيص، ولكن تبلغ تقريبًا ضعف التكلفة).
يتيح كلّ من Android 10 والفرع الرئيسي من AOSP على AArch64 استخدام أداة AddressSanitizer (HWASan) المستندة إلى الأجهزة، وهي أداة مشابهة تستهلك ذاكرة وصول عشوائي أقل وترصد عددًا أكبر من الأخطاء. ترصد أداة HWASan استخدام الحزمة بعد الرجوع، بالإضافة إلى الأخطاء التي ترصدها أداة ASan.
تستهلك تقنية HWASan موارد وحدة المعالجة المركزية وحجم الرمز البرمجي بشكل مشابه، ولكنّها تستهلك موارد ذاكرة وصول عشوائي أقل بكثير (15%). HWASan غير محدّد. لا تتوفّر سوى 256 قيمة محتملة للعلامات، لذا هناك احتمال بنسبة 0.4% بأن يتم تجاهل أي خطأ. لا تتضمّن أداة HWASan المناطق الحمراء ذات الحجم المحدود في أداة ASan لرصد حالات تجاوز الذاكرة ووضع العزل ذات السعة المحدودة لرصد حالات الاستخدام بعد تحرير الذاكرة، وبالتالي لا يهمّ أداة HWASan حجم تجاوز الذاكرة أو المدة التي مضت على تحرير الذاكرة. وهذا يجعل HWASan أفضل من ASan. يمكنك الاطّلاع على مزيد من المعلومات حول تصميم HWASan أو حول استخدام HWASan على Android.
ترصد أداة ASan حالات تجاوز سعة الذاكرة في الحزمة/الذاكرة الشاملة بالإضافة إلى حالات تجاوز سعة الذاكرة في الحِزمة، وهي سريعة بأقل تكلفة ممكنة للذاكرة.
يصف هذا المستند طريقة إنشاء أجزاء من Android أو كل أجهزة Android وتشغيلها باستخدام ميزة ASan. إذا كنت بصدد إنشاء تطبيق حزمة تطوير برامج (SDK) أو حزمة تطوير تطبيقات (NDK) باستخدام أداة ASan، يمكنك الاطّلاع على أداة فحص العناوين بدلاً من ذلك.
تطهير ملفات تنفيذ فردية باستخدام ASan
أضِف LOCAL_SANITIZE:=address
أو sanitize: { address: true }
إلى
قاعدة الإنشاء للملف القابل للتنفيذ. يمكنك البحث في الرمز عن الأمثلة الحالية أو للعثور على
المعقّمات الأخرى المتاحة.
عند رصد خطأ، تطبع أداة ASan تقريرًا مفصّلاً في كلّ من المخرج
العادي وlogcat
، ثم تؤدي إلى تعطُّل العملية.
إزالة البيانات غير الصالحة من المكتبات المشتركة باستخدام ASan
بسبب طريقة عمل ASan، لا يمكن استخدام مكتبة تم إنشاؤها باستخدام ASan إلا من خلال ملف executible تم إنشاؤه باستخدام ASan.
لتطهير مكتبة مشترَكة يتم استخدامها في ملفات تنفيذية متعددة، وليس كلها
مُنشأة باستخدام ASan، تحتاج إلى نسختَين من المكتبة. إنّ الطريقة المُقترَحة لإجراء ذلك هي إضافة ما يلي إلى Android.mk
للوحدة المعنيّة:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
يؤدي ذلك إلى وضع المكتبة في /system/lib/asan
بدلاً من
/system/lib
. بعد ذلك، يمكنك تشغيل الملف القابل للتنفيذ باستخدام:
LD_LIBRARY_PATH=/system/lib/asan
بالنسبة إلى خدمات النظام، أضِف ما يلي إلى القسم المناسب منملف
/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 بدون مؤشرات الإطارات. ونتيجةً لذلك، غالبًا ما تحصل على إطار واحد أو إطارَين ذيَين معنى فقط. لحلّ هذه المشكلة، يمكنك إعادة إنشاء المكتبة باستخدام IDE IDE (يُنصح به) أو باستخدام:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
أو اضبط ASAN_OPTIONS=fast_unwind_on_malloc=0
في بيئة
العملية. يمكن أن يستهلك هذا الأخير وحدة المعالجة المركزية (CPU) بشكل كبير، وذلك استنادًا إلى
الحِمل.
الترميز
في البداية، تحتوي تقارير ASan على إشارات إلى الموضع في الملفات الثنائية والمكتبات المشترَكة. هناك طريقتان للحصول على معلومات الملف المصدر والسطر:
- تأكَّد من توفّر ملف
llvm-symbolizer
الثنائي في/system/bin
. تم إنشاءllvm-symbolizer
من مصادر فيthird_party/llvm/tools/llvm-symbolizer
. - فلتِر التقرير من خلال
external/compiler-rt/lib/asan/scripts/symbolize.py
النص البرمجي.
يمكن أن يوفّر النهج الثاني المزيد من البيانات (أي file:line
موقعًا جغرافيًا) بسبب
توفّر المكتبات الرمزية على المضيف.
ASan في التطبيقات
لا يمكن لأداة ASan الاطّلاع على رمز Java، ولكن يمكنها رصد الأخطاء في مكتبات JNI. ولإجراء ذلك، عليك إنشاء الملف القابل للتنفيذ باستخدام ASan، والذي يُمثّل في
هذه الحالة /system/bin/app_process(32|64)
. يؤدي ذلك إلى تفعيل ASan في جميع التطبيقات على الجهاز في الوقت نفسه، ما يشكّل عبئًا ثقيلاً، ولكن من المفترض أن يكون الجهاز المزوّد بذاكرة وصول عشوائي (RAM) بسعة 2 غيغابايت قادرًا على التعامل مع ذلك.
أضِف 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 وإعادة التشغيل
استخدام سمة wrap
تؤدي الطريقة الموضّحة في القسم السابق إلى تضمين 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
في بداية
مسار البحث في المكتبة الديناميكية. بهذه الطريقة، يتم تفضيل مكتبات /system/lib/asan
التي تم تجهيزها لأداة ASan مقارنةً بالمكتبات العادية في /system/lib
عند التشغيل باستخدام asanwrapper
.
في حال العثور على خطأ، يتعطّل التطبيق ويتم طباعة التقرير في السجلّ.
SANITIZE_TARGET
يشمل الإصدار 7.0 من Android والإصدارات الأحدث دعمًا لإنشاء نظام Android الأساسي بأكمله باستخدام ASan في آنٍ واحد. (إذا كنت بصدد إنشاء إصدار أحدث من Android 9، يُعدّ HWASan خيارًا أفضل.)
نفِّذ الأوامر التالية في شجرة التصميم نفسها.
make -j42
SANITIZE_TARGET=address make -j42
في هذا الوضع، يحتوي userdata.img
على مكتبات إضافية ويجب
فلاشها على الجهاز أيضًا. استخدِم سطر الأوامر التالي:
fastboot flash userdata && fastboot flashall
يؤدي ذلك إلى إنشاء مجموعتَين من المكتبات المشتركة: المكتبة العادية في
/system/lib
(أول طلب تشغيل لـ make) والمكتبة التي تم فحصها باستخدام ASan في
/data/asan/lib
(الطلب الثاني لتشغيل make). تُحلّ الملفات التنفيذية من الإصدار
الثاني محلّ الملفات التنفيذية من الإصدار الأول. تحصل ملفات exes التي تم تجهيزها لأداة 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 من المكتبات الثابتة التي تعتمد عليها.