AddressSanitizer (ASan) नेटिव कोड में मेमोरी बग्स का पता लगाने के लिए एक तेज़ कंपाइलर-आधारित टूल है।
आसन का पता लगाता है:
- ढेर और ढेर बफर अतिप्रवाह/अंडरफ्लो
- मुफ्त के बाद ढेर का उपयोग
- दायरे के बाहर ढेर का उपयोग
- डबल फ्री/वाइल्ड फ्री
आसन 32-बिट और 64-बिट एआरएम, प्लस x86 और x86-64 दोनों पर चलता है। ASan का CPU ओवरहेड लगभग 2x है, कोड आकार ओवरहेड 50% और 2x के बीच है, और एक बड़ा मेमोरी ओवरहेड (आपके आवंटन पैटर्न पर निर्भर है, लेकिन 2x के क्रम पर)।
Android 10 और AArch64 पर AOSP मास्टर शाखा हार्डवेयर-त्वरित ASan (HWASan) का समर्थन करती है, जो कम रैम ओवरहेड के साथ एक समान उपकरण और पता लगाए गए बग की एक बड़ी रेंज है। HWASan, ASan द्वारा खोजे गए बग के अलावा, वापसी के बाद स्टैक के उपयोग का पता लगाता है।
HWASan में समान CPU और कोड आकार का ओवरहेड होता है, लेकिन बहुत छोटा RAM ओवरहेड (15%)। HWASan nondeterministic है। केवल 256 संभावित टैग मान हैं, इसलिए किसी भी बग के गायब होने की 0.4% संभावना है। HWASan के पास अतिप्रवाह का पता लगाने के लिए ASan के सीमित आकार के लाल क्षेत्र नहीं हैं और उपयोग-बाद-मुक्त का पता लगाने के लिए सीमित क्षमता वाले संगरोध हैं, इसलिए HWASan के लिए यह कोई मायने नहीं रखता कि अतिप्रवाह कितना बड़ा है या कितनी देर पहले स्मृति को हटा दिया गया था। यह HWASan को आसन से बेहतर बनाता है। आप HWASan के डिज़ाइन या Android पर HWASan के उपयोग के बारे में अधिक पढ़ सकते हैं।
ASan हीप ओवरफ्लो के अलावा स्टैक/ग्लोबल ओवरफ्लो का पता लगाता है, और न्यूनतम मेमोरी ओवरहेड के साथ तेज़ है।
यह दस्तावेज़ वर्णन करता है कि ASan के साथ Android के पुर्ज़े/सभी को कैसे बनाया और चलाया जाए। अगर आप आसन के साथ एसडीके/एनडीके ऐप बना रहे हैं, तो इसके बजाय एड्रेस सैनिटाइज़र देखें।
आसन के साथ अलग-अलग एक्जीक्यूटेबल्स को सेनिटाइज करना
निष्पादन योग्य के लिए निर्माण नियम में LOCAL_SANITIZE:=address
या sanitize: { address: true }
जोड़ें। आप मौजूदा उदाहरणों के लिए कोड खोज सकते हैं या अन्य उपलब्ध सैनिटाइज़र ढूंढ सकते हैं।
जब एक बग का पता चलता है, तो ASan एक वर्बोज़ रिपोर्ट को मानक आउटपुट और logcat
दोनों पर प्रिंट करता है और फिर प्रक्रिया को क्रैश कर देता है।
आसन के साथ साझा पुस्तकालयों को साफ करना
आसन के काम करने के तरीके के कारण, आसन के साथ निर्मित पुस्तकालय का उपयोग केवल एक निष्पादन योग्य द्वारा किया जा सकता है जो कि आसन के साथ बनाया गया है।
एक साझा पुस्तकालय को साफ करने के लिए जो कई निष्पादन योग्य में उपयोग किया जाता है, जिनमें से सभी आसन के साथ नहीं बनाए जाते हैं, आपको पुस्तकालय की दो प्रतियों की आवश्यकता होती है। ऐसा करने का अनुशंसित तरीका निम्नलिखित को Android.mk
में विचाराधीन मॉड्यूल के लिए जोड़ना है:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
यह पुस्तकालय को /system/lib/asan
के बजाय /system/lib
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 प्रोग्राम में प्रत्येक मेमोरी आवंटन और डीलोकेशन इवेंट के लिए स्टैक ट्रेस रिकॉर्ड करने के लिए एक तेज़, फ्रेम-पॉइंटर-आधारित अनविंडर का उपयोग करता है। अधिकांश एंड्रॉइड फ्रेम पॉइंटर्स के बिना बनाया गया है। परिणामस्वरूप, आपको अक्सर केवल एक या दो अर्थपूर्ण फ़्रेम मिलते हैं। इसे ठीक करने के लिए, या तो पुस्तकालय को आसन (अनुशंसित!), या इसके साथ पुनर्निर्माण करें:
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
स्थान) प्रदान कर सकता है।
ऐप्स में आसन
आसन जावा कोड में नहीं देख सकता है, लेकिन यह जेएनआई पुस्तकालयों में बग का पता लगा सकता है। उसके लिए, आपको आसन के साथ निष्पादन योग्य बनाने की आवश्यकता है, जो इस मामले में /system/bin/app_process( 32|64 )
है। यह एक ही समय में डिवाइस पर सभी ऐप्स में आसन को सक्षम बनाता है, जो एक भारी भार है, लेकिन 2 जीबी रैम वाला डिवाइस इसे संभालने में सक्षम होना चाहिए।
LOCAL_SANITIZE:=address
को app_process
बिल्ड रूल में frameworks/base/cmds/app_process
में जोड़ें। अभी के लिए उसी फ़ाइल में app_process__asan
लक्ष्य पर ध्यान न दें (यदि आप इसे पढ़ते समय अभी भी मौजूद हैं)।
उपयुक्त system/core/rootdir/init.zygote( 32|64 ).rc
फ़ाइल के service zygote
ज़ीगोट सेक्शन को संपादित करें ताकि class main
वाली इंडेंटेड लाइन्स के ब्लॉक में निम्नलिखित लाइन्स को जोड़ा जा सके, उसी राशि से इंडेंट भी:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
बिल्ड, एडीबी सिंक, फास्टबूट फ्लैश बूट, और रीबूट करें।
रैप संपत्ति का उपयोग करना
पिछले खंड में दृष्टिकोण ASan को सिस्टम के प्रत्येक ऐप में डालता है (वास्तव में, Zygote प्रक्रिया के प्रत्येक वंशज में)। आसन के साथ केवल एक (या कई) ऐप चलाना संभव है, धीमे ऐप स्टार्टअप के लिए कुछ मेमोरी ओवरहेड का व्यापार करना।
यह आपके ऐप को wrap.
संपत्ति। निम्नलिखित उदाहरण आसन के तहत जीमेल ऐप चलाता है:
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
app_process पर फिर से लिखता है, जो कि ASan के साथ बनाया गया है। यह गतिशील पुस्तकालय खोज पथ की शुरुआत में /system/lib/asan
भी जोड़ता है। इस प्रकार /system/lib/asan
से आसन-वाद्य पुस्तकालयों को /system /system/lib
lib में सामान्य पुस्तकालयों के लिए पसंद किया जाता है जब asanwrapper
के साथ चलते हैं।
यदि कोई बग पाया जाता है, तो ऐप क्रैश हो जाता है, और रिपोर्ट लॉग पर प्रिंट हो जाती है।
SANITIZE_TARGET
Android 7.0 और उच्चतर में एक ही बार में ASan के साथ संपूर्ण Android प्लेटफ़ॉर्म बनाने के लिए समर्थन शामिल है। (यदि आप Android 9 से उच्चतर रिलीज़ बना रहे हैं, तो HWASan एक बेहतर विकल्प है।)
एक ही बिल्ड ट्री में निम्न कमांड चलाएँ।
make -j42
SANITIZE_TARGET=address make -j42
इस मोड में, userdata.img
में अतिरिक्त पुस्तकालय होते हैं और उन्हें डिवाइस पर भी फ्लैश किया जाना चाहिए। निम्न कमांड लाइन का प्रयोग करें:
fastboot flash userdata && fastboot flashall
यह साझा पुस्तकालयों के दो सेट बनाता है: सामान्य /system/lib
(पहला मेक इनवोकेशन), और आसन-इंस्ट्रूमेंटेड इन /data/asan/lib
(दूसरा मेक इनवोकेशन)। दूसरे निर्माण से निष्पादन योग्य पहले निर्माण से अधिलेखित कर देते हैं। ASan-वाद्य यंत्रों को एक अलग पुस्तकालय खोज पथ मिलता है जिसमें PT_INTERP में /system/bin/linker_asan
PT_INTERP
उपयोग के माध्यम से /system/lib
से पहले /data/asan/lib
शामिल है।
जब $SANITIZE_TARGET
मान बदल गया है, तो बिल्ड सिस्टम इंटरमीडिएट ऑब्जेक्ट निर्देशिकाओं को बंद कर देता है। यह /system/lib
के तहत स्थापित बायनेरिज़ को संरक्षित करते हुए सभी लक्ष्यों के पुनर्निर्माण के लिए बाध्य करता है।
आसन के साथ कुछ लक्ष्य नहीं बनाए जा सकते:
- स्थिर रूप से जुड़े निष्पादन योग्य
-
LOCAL_CLANG:=false
लक्ष्य -
LOCAL_SANITIZE:=false
SANITIZE_TARGET=address
के लिए गलत नहीं हैं
इस तरह के निष्पादन योग्य SANITIZE_TARGET
बिल्ड में छोड़ दिए जाते हैं, और पहले मेक इनवोकेशन का संस्करण /system/bin
में छोड़ दिया जाता है।
इस तरह के पुस्तकालय बिना आसन के बने हैं। वे स्थिर पुस्तकालयों से कुछ आसन कोड शामिल कर सकते हैं जिन पर वे निर्भर हैं।