AddressSanitizer (ASan) הוא כלי מבוסס מהדר (compiler) מהיר לזיהוי באגים בזיכרון בקוד נייטיב.
ASan מזהה:
- גלישת נתונים/מאגר נתונים זמני של ערימה וערימה
- שימוש בערימה אחרי בחינם
- שימוש במקבץ מחוץ להיקף
- מיטה זוגית חופשיה/חינמית
ASan פועלת גם ב-ARM 32 סיביות וגם ב-ARM 64 סיביות, וגם ב-x86 וב-x86-64. תקורה של המעבד (CPU) של ASan הוא בערך פי 2, תקורה של גודל קוד היא בין 50% לפי 2, ותקורת זיכרון גדולה (בהתאם לדפוסי ההקצאה שלכם, אך בסדר 2x).
Android 10 והסניף הראשי של AOSP ב-AArch64 תמיכה ב-Hardware-AssistSanitizer (HWASan), כלי דומה עם תקורת RAM נמוכה יותר טווח הבאגים שזוהו. שירות HWASan מזהה שימוש בסטאק אחרי החזרה, בנוסף לבאגים שזוהו על ידי ASan.
ל-HWASan יש תקורה דומה לגבי המעבד (CPU) והקוד, אבל התקורה של ה-RAM היא קטנה בהרבה (15%). HWASan אינו קבוע. קיימים רק 256 ערכי תגים אפשריים, ולכן יש ערך קבוע של 0.4% שיש סבירות גבוהה שיחמיץ באג כלשהו. ב-HWASan אין אזורים אדומים מוגבלים בגודלם זיהוי חריגות והסגר עם קיבולת מוגבלת לזיהוי מקרי שימוש לאחר השימוש (post-free), אז לא משנה ל-HWASan כמה גדול נפח הגלישה או כמה זמן עבר הזיכרון הוקצה. זה עוזר לשפר את HWASan מאשר ASan. אפשר לקרוא מידע נוסף על עיצוב של HWASan או מידע על השימוש ב-HWASan ב-Android.
ASan מזהה קריסות/חריגות גלובליות בנוסף לעומס 'ערימה', והוא מהיר עם תקורת זיכרון מינימלית.
במסמך הזה מתואר איך לפתח ולהפעיל חלקים של Android או את כל מכשירי Android עם אסן. אם אתם מפתחים אפליקציית SDK/NDK עם ASan, עיינו במאמר בנושא כלי לחיטוי כתובות במקום זאת.
חיטוי קובצי הפעלה ספציפיים באמצעות ASan
הוספת LOCAL_SANITIZE:=address
או sanitize: { address: true }
אל
כלל ה-build של קובץ ההפעלה. אפשר לחפש בקוד דוגמאות קיימות או למצוא
חומרי החיטוי האחרים שזמינים.
כשמזוהה באג, ASan מדפיסה דוח מפורט
הפלט אל logcat
ואז קורס של התהליך.
חיטוי ספריות משותפות באמצעות ASan
בשל אופן הפעולה של ASan, ספרייה שנבנתה באמצעות ASan יכולה לשמש רק שנוצר באמצעות 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 משתמשת ב-unwinder מהיר מבוסס-פריים כדי להקליט סטאק לעקוב אחרי כל אירוע של הקצאת זיכרון ומיקום עסקה בתוכנית. נפוצים של Android בנוי ללא מצביעי מסגרות. כתוצאה מכך, לעיתים קרובות תקבלו רק מסגרת אחת או שתיים עם משמעות. כדי לפתור את הבעיה, בנה מחדש את הספרייה עם ASan (מומלץ!), או עם:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
או להגדיר את ASAN_OPTIONS=fast_unwind_on_malloc=0
בתהליך
הסביבה. האפשרות השנייה עלולה להיות עמוסה מאוד במעבד, בהתאם
את העומס.
ייצוג
בהתחלה, הדוחות של 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 בנפח 2GB אמור להתמודד עם הבעיה הזו.
הוספת LOCAL_SANITIZE:=address
אל
כלל ה-build 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, אתחול מהיר של 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
, שנוצר באמצעות
אסן. היא גם מוסיפה /system/lib/asan
בתחילת
נתיב החיפוש בספרייה הדינמית. בשיטה הזו נעשה שימוש באינסטגרם
ספריות מ-/system/lib/asan
מקבלות עדיפות על ספריות רגילות
ב-/system/lib
כשמריצים אותו עם asanwrapper
.
אם יתגלה באג, האפליקציה תקרוס והדוח יודפס ב ביומן.
SANITIZE_TARGET
Android 7.0 ואילך כולל תמיכה בבניית פלטפורמת Android כולה עם ASan בבת אחת. (אם אתם מפתחים גרסה מתקדמת יותר מ-Android 9, עדיף להשתמש ב-HWASan).
מריצים את הפקודות הבאות באותו עץ build.
make -j42
SANITIZE_TARGET=address make -j42
במצב הזה, הקובץ userdata.img
מכיל ספריות נוספות וחייב להיות
הבהוב גם כן למכשיר. משתמשים בשורת הפקודה הבאה:
fastboot flash userdata && fastboot flashall
הדבר יוצר שתי קבוצות של ספריות משותפות: נורמלית ב-
/system/lib
(ההפעלה הראשונה), ו-ASan עם אינסטרומנטציה
/data/asan/lib
(השנייה מפעילה). קובצי הרצה מ-
ה-build השני יחליף את ה-build מה-build הראשון. עם אינסטלציה ASan
קובצי הפעלה מקבלים נתיב חיפוש אחר בספרייה שכולל
/data/asan/lib
לפני /system/lib
באמצעות שימוש ב-
/system/bin/linker_asan
בPT_INTERP
.
מערכת ה-build מאחזרת ספריות אובייקטים מתווכות כאשר
הערך של $SANITIZE_TARGET
השתנה. פעולה זו מחייבת בנייה מחדש של כל
יעדים תוך שמירה על הקבצים הבינאריים המותקנים במסגרת /system/lib
.
יש יעדים שלא ניתן ליצור באמצעות ASan:
- קובצי הפעלה שמקושרים באופן סטטי
LOCAL_CLANG:=false
יעדיםLOCAL_SANITIZE:=false
לא מוגדרים כ-ASand עבורSANITIZE_TARGET=address
המערכת מדלגת על הפעלות כאלה ב-build של SANITIZE_TARGET
.
הגרסה מההפעלה הראשונה של ההפעלה נשארה ב-/system/bin
.
ספריות כאלה נבנו ללא ASan. הם יכולים להכיל חלק מה-ASan. מספריות סטטיות שעליהן הן תלויות.