HWASan रिपोर्ट को समझना

जब HWASan टूल को मेमोरी से जुड़ी गड़बड़ी का पता चलता है, तो प्रोसेस को abort() के साथ बंद कर दिया जाता है. साथ ही, stderr और logcat में एक रिपोर्ट प्रिंट की जाती है. Android पर होने वाली सभी नेटिव क्रैश की तरह, HWASan की गड़बड़ियां भी /data/tombstones में दिखती हैं.

उदाहरण के तौर पर दी गई रिपोर्ट

नेटिव क्रैश की तुलना में, HWASan, टॉम्बस्टोन के सबसे ऊपर मौजूद Abort message फ़ील्ड में ज़्यादा जानकारी देता है. यहां हीप पर आधारित क्रैश का एक सैंपल दिया गया है. स्टैक बग के लिए, स्टैक से जुड़े सेक्शन के लिए नोट देखें.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/flame_hwasan/flame:Tiramisu/MASTER/7956676:userdebug/dev-keys'
Revision: 'DVT1.0'
ABI: 'arm64'
Timestamp: 2019-04-24 01:13:22+0000
pid: 11154, tid: 11154, name: sensors@1.0-ser  >>> /vendor/bin/hw/android.hardware.sensors@1.0-service <<<
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: '

[...]

[0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5








[ … regular crash dump follows …]

यह AddressSanitizer रिपोर्ट की तरह होती है. इनके उलट, HWASan की मदद से रिपोर्ट की गई गड़बड़ियों में से ज़्यादातर, टैग के न मिलने की वजह से होती हैं. इसका मतलब है कि मेमोरी को ऐक्सेस करने के दौरान, पॉइंटर टैग, मेमोरी टैग से मेल नहीं खाता. यह इनमें से कोई भी हो सकता है:

  • स्टैक या हीप पर सीमा से बाहर का ऐक्सेस
  • हीप पर, फ़्री किए गए मेमोरी ब्लॉक का इस्तेमाल करने से जुड़ी गड़बड़ी
  • स्टैक पर, फ़ंक्शन के रिटर्न होने के बाद इस्तेमाल करने से जुड़ी गड़बड़ी

सेक्शन

यहां HWASan रिपोर्ट के हर सेक्शन के बारे में बताया गया है.

ऐक्सेस से जुड़ी गड़बड़ी

इसमें मेमोरी को गलत तरीके से ऐक्सेस करने के बारे में जानकारी होती है. जैसे:

  • ऐक्सेस टाइप (READ बनाम WRITE)
  • ऐक्सेस का साइज़ (कितने बाइट का डेटा ऐक्सेस करने की कोशिश की गई)
  • ऐक्सेस का थ्रेड नंबर
  • पॉइंटर और मेमोरी टैग (ऐडवांस डीबगिंग के लिए)

स्टैक ट्रेस ऐक्सेस करना

मेमोरी को गलत तरीके से ऐक्सेस करने का स्टैक ट्रेस. सिंबल बनाने के लिए, सिंबल बनाना लेख पढ़ें.

वजह

ऐक्सेस न मिलने की संभावित वजह. अगर एक से ज़्यादा उम्मीदवार हैं, तो उन्हें मिलने की संभावना के हिसाब से घटते क्रम में दिखाया जाता है. इसमें संभावित वजह के बारे में ज़्यादा जानकारी से पहले, समस्या के बारे में बताया जाता है. HWASan इन वजहों का पता लगा सकता है:

  • बिना शुल्क के इस्तेमाल करने के बाद
  • स्टैक टैग में अंतर. यह अंतर, स्टैक का इस्तेमाल रिटर्न के बाद, स्कोप के बाद, या सीमा से बाहर होने की वजह से हो सकता है
  • हीप बफ़र ओवरफ़्लो
  • ग्लोबल ओवरफ़्लो

मेमोरी की जानकारी

इससे पता चलता है कि HWASan को ऐक्सेस की जा रही मेमोरी के बारे में क्या पता है. यह गड़बड़ी के टाइप के हिसाब से अलग-अलग हो सकता है:

गड़बड़ी का टाइप वजह रिपोर्ट फ़ॉर्मेट
टैग मेल नहीं खाता बिना शुल्क के इस्तेमाल करने के बाद इस रिपोर्ट फ़ॉर्मैट का इस्तेमाल करें:
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
हीप बफ़र ओवरफ़्लो ध्यान दें कि यह अंडरफ़्लो भी हो सकता है.
<address> is located N bytes to the right of M-byte region [<start>, <end>)
allocated here:
स्टैक टैग मेल नहीं खा रहा है स्टैक रिपोर्ट, ओवरफ़्लो या अंडरफ़्लो और यूज़-आफ़्टर-रिटर्न बग के बीच अंतर नहीं करती हैं. इसके अलावा, गड़बड़ी की वजह से स्टैक के लिए मेमोरी का कितना हिस्सा इस्तेमाल किया गया है, यह पता लगाने के लिए, ऑफ़लाइन सिंबोलाइज़ेशन करना ज़रूरी है. स्टैक रिपोर्ट के बारे में जानकारी देखें.
बिना शुल्क के उपलब्ध होने की स्थिति अमान्य है बिना शुल्क के इस्तेमाल करने के बाद डबल फ़्री बग. अगर प्रोसेस बंद होने पर ऐसा होता है, तो यह ओडीआर के उल्लंघन का संकेत दे सकता है.
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
पते के बारे में जानकारी नहीं दी जा सकती यह एक वाइल्ड फ़्री (ऐसी मेमोरी जिसे पहले असाइन नहीं किया गया था) या असाइन की गई मेमोरी को HWASan के फ़्री बफ़र से हटाने के बाद डबल फ़्री है.
0x... HWAsan की शैडो मेमोरी है यह एक गंभीर गड़बड़ी है, क्योंकि ऐप्लिकेशन HWASan की इंटरनल मेमोरी को खाली करने की कोशिश कर रहा था.

Deallocation stack trace

मेमोरी को कहां से हटाया गया, इसकी स्टैक ट्रेस. इस फ़ील्ड का इस्तेमाल सिर्फ़ उन बग के लिए करें जिनमें बिना शुल्क के इस्तेमाल करने की सुविधा उपलब्ध है या जो बिना शुल्क के इस्तेमाल करने की सुविधा के लिए मान्य नहीं हैं. सिंबल बनाने के लिए, सिंबल बनाना लेख पढ़ें.

ऐलोकेशन स्टैक ट्रेस

मेमोरी कहां इस्तेमाल की गई, इसकी स्टैक ट्रेस. सिंबल बनाने के लिए, सिंबल बनाना लेख पढ़ें.

डीबग करने के बारे में ऐडवांस जानकारी

HWASan रिपोर्ट में, डीबग करने से जुड़ी कुछ बेहतर जानकारी भी शामिल होती है. इसमें यह जानकारी इस क्रम में दी जाती है:

  1. प्रोसेस में मौजूद थ्रेड की सूची
  2. प्रोसेस में मौजूद थ्रेड की सूची
  3. गड़बड़ी वाली मेमोरी के आस-पास मौजूद मेमोरी टैग की वैल्यू
  4. मेमोरी ऐक्सेस के समय रजिस्टर का डंप

मेमोरी टैग डंप

टैग मेमोरी डंप का इस्तेमाल करके, पॉइंटर टैग के आस-पास मेमोरी के उन हिस्सों को खोजा जा सकता है जिनमें एक ही टैग का इस्तेमाल किया गया है. ये टैग, सीमा से बाहर के ऐसे ऐक्सेस की ओर इशारा कर सकते हैं जिसमें बड़ा ऑफ़सेट होता है. एक टैग, 16 बाइट की मेमोरी के बराबर होता है. पॉइंटर टैग, पते के टॉप 8 बिट होते हैं. टैग मेमोरी डंप से कुछ संकेत मिल सकते हैं. उदाहरण के लिए, यहां दाईं ओर बफ़र ओवरफ़्लो दिखाया गया है:

tags: ad/5c (ptr/mem)
[...]
Memory tags around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: 0e  0e  0e  57  20  20  20  20  20  2e  5e  5e  5e  5e  5e  b5
=>0x006f33ae2000: f6  f6  f6  f6  f6  4c  ad  ad  ad  ad  ad  ad [5c] 5c  5c  5c
  0x006f33ae2010: 5c  04  2e  2e  2e  2e  2e  2f  66  66  66  66  66  80  6a  6a
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: ab  52  eb  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
=>0x006f33ae2000: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. [..] ..  ..  ..
  0x006f33ae2010: ..  5c  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..

बाईं ओर मौजूद ad टैग के 96 बाइट के रन पर ध्यान दें. यह रन, पॉइंटर टैग से मेल खाता है.

अगर किसी मेमोरी ब्लॉक का साइज़ 16 का गुणज नहीं है, तो साइज़ का बचा हुआ हिस्सा मेमोरी टैग के तौर पर सेव किया जाता है. साथ ही, टैग को शॉर्ट ग्रैन्यूल टैग के तौर पर सेव किया जाता है. पिछले उदाहरण में, बोल्ड किए गए टैग ad के ठीक बाद, हमारे पास टैग 5c का 5 × 16 + 4 = 84 बाइट का असाइनमेंट है.

शून्य मेमोरी टैग (उदाहरण के लिए, tags: ad/00 (ptr/mem)) से पता चलता है कि स्टैक-यूज़-आफ़्टर-रिटर्न बग है.

डंप रजिस्टर करें

HWASan रिपोर्ट में रजिस्टर डंप, उस निर्देश से मेल खाता है जिसने मेमोरी को गलत तरीके से ऐक्सेस किया है. इस डंप के बाद, Android के सामान्य सिग्नल हैंडलर से एक और रजिस्टर डंप किया जाता है. दूसरे डंप को अनदेखा करें, क्योंकि इसे तब लिया गया था, जब HWASan ने abort() को कॉल किया था. यह डंप, बग से जुड़ा नहीं है.

सिंबॉलिकेशन

स्टैक ट्रेस में फ़ंक्शन के नाम और लाइन नंबर पाने के लिए, ऑफ़लाइन सिंबोलाइज़ेशन ज़रूरी है. साथ ही, स्कोप से बाहर के वैरिएबल इस्तेमाल करने से जुड़ी गड़बड़ियों के लिए वैरिएबल के नाम पाने के लिए भी यह ज़रूरी है.

पहली बार सेटअप करना: llvm-symbolizer इंस्टॉल करें

सिंबल बनाने के लिए, आपके सिस्टम में llvm-symbolizer इंस्टॉल होना चाहिए. साथ ही, इसे $PATH से ऐक्सेस किया जा सकता हो. Debian पर, इसे sudo apt install llvm का इस्तेमाल करके इंस्टॉल किया जा सकता है.

सिंबल फ़ाइलें पाना

सिंबोलाइज़ेशन के लिए, हमें ऐसे बाइनरी की ज़रूरत होती है जिनमें सिंबल मौजूद हों. उनकी जगह, बिल्ड के टाइप पर निर्भर करती है:

  • लोकल बिल्ड के लिए, सिंबल फ़ाइलें out/target/product/<product>/symbols/ में होती हैं.
  • AOSP बिल्ड के लिए (उदाहरण के लिए, Android Flash Tool से फ़्लैश किए गए बिल्ड), बिल्ड Android CI पर होते हैं. बिल्ड के लिए आर्टफ़ैक्ट में, ${PRODUCT}-symbols-${BUILDID}.zip फ़ाइल मौजूद है.
  • अपने संगठन की इंटरनल बिल्ड के लिए, सिंबल फ़ाइलें पाने में मदद पाने के लिए, अपने संगठन के दस्तावेज़ देखें.

प्रतीकात्मक रूप से दिखाना

hwasan_symbolize --symbols <DECOMPRESSED_DIR>/out/target/product/*/symbols < crash

स्टैक रिपोर्ट के बारे में जानकारी

स्टैक वैरिएबल से जुड़ी गड़बड़ियों के लिए, HWASan रिपोर्ट में इस तरह की जानकारी होती है:

Cause: stack tag-mismatch
Address 0x007d4d251e80 is located in stack of thread T64
Thread: T64 0x0074000b2000 stack: [0x007d4d14c000,0x007d4d255cb0) sz: 1088688 tls: [0x007d4d255fc0,0x007d4d259000)
Previously allocated frames:
  record_addr:0x7df7300c98 record:0x51ef007df3f70fb0  (/apex/com.android.art/lib64/libart.so+0x570fb0)
  record_addr:0x7df7300c90 record:0x5200007df3cdab74  (/apex/com.android.art/lib64/libart.so+0x2dab74)
  [...]

स्टैक बग को समझने में आपकी मदद करने के लिए, HWASan पिछले स्टैक फ़्रेम को ट्रैक करता है. HWASan, गड़बड़ी की रिपोर्ट में इन्हें ऐसे कॉन्टेंट में नहीं बदलता जिसे आसानी से समझा जा सके. इसके लिए, सिंबोलाइज़ेशन का एक और चरण ज़रूरी होता है.

ओडीआर के उल्लंघन

HWASan की ओर से रिपोर्ट किए गए, इस्तेमाल के बाद मेमोरी खाली करने से जुड़ी कुछ गड़बड़ियों से, एक ही परिभाषा के नियम (ओडीआर) के उल्लंघन का पता चल सकता है. ओडीआर का उल्लंघन तब होता है, जब एक ही प्रोग्राम में एक ही वैरिएबल को कई बार तय किया जाता है. इसका यह भी मतलब है कि वैरिएबल को कई बार डिस्ट्रक्ट किया जाता है. इससे, यूज़-आफ़्टर-फ़्री गड़बड़ी हो सकती है.

सिंबोलाइज़ेशन के बाद, ओडीआर के उल्लंघन से जुड़ी गड़बड़ियों में, __cxa_finalize के साथ यूज़-आफ़्टर-फ़्री गड़बड़ी दिखती है. यह गड़बड़ी, अमान्य ऐक्सेस स्टैक और यहां फ़्री किया गया स्टैक, दोनों पर दिखती है. यहां पहले से असाइन किए गए स्टैक में __dl__ZN6soinfo17call_constructorsEv शामिल है. साथ ही, इसे आपके प्रोग्राम में उस जगह पर पॉइंट करना चाहिए जहां स्टैक में वैरिएबल को ज़्यादा पर सेट किया गया है.

स्टैटिक लाइब्रेरी का इस्तेमाल करने पर, ओडीआर का उल्लंघन हो सकता है. अगर C++ ग्लोबल को तय करने वाली किसी स्टैटिक लाइब्रेरी को कई शेयर की गई लाइब्रेरी या एक्ज़ीक्यूटेबल में लिंक किया जाता है, तो एक ही पते की जगह में एक ही सिंबल की कई परिभाषाएं मौजूद हो सकती हैं. इससे ODR से जुड़ी गड़बड़ी होती है.

समस्या का हल

इस सेक्शन में, कुछ गड़बड़ियों और उन्हें ठीक करने के तरीके के बारे में बताया गया है.

HWAddressSanitizer, पते के बारे में ज़्यादा जानकारी नहीं दे सकता

कभी-कभी ऐसा हो सकता है कि HWASan के पास, मेमोरी के पिछले असाइनमेंट की जानकारी सेव करने के लिए जगह न बची हो. ऐसे में, रिपोर्ट में मेमोरी को तुरंत ऐक्सेस करने के लिए सिर्फ़ एक स्टैक ट्रेस होता है. इसके बाद, यह नोट होता है:

HWAddressSanitizer can not describe address in more detail.

कुछ मामलों में, इस समस्या को कई बार टेस्ट करके हल किया जा सकता है. एक और विकल्प है कि HWASan के इतिहास का साइज़ बढ़ाया जाए. इसे ग्लोबल लेवल पर build/soong/cc/sanitize.go में जाकर किया जा सकता है. इसके लिए, hwasanGlobalOptions देखें. इसके अलावा, इसे प्रोसेस एनवायरमेंट में भी किया जा सकता है. मौजूदा सेटिंग देखने के लिए, adb shell echo $HWASAN_OPTIONS आज़माएं.

यह गड़बड़ी तब भी हो सकती है, जब ऐक्सेस की गई मेमोरी को मैप न किया गया हो या उसे HWASan के बारे में जानकारी रखने वाले ऐलोकेटर के ज़रिए असाइन न किया गया हो. इस मामले में, क्रैश हेडर में दिया गया mem टैग आम तौर पर 00 होता है. अगर आपके पास पूरे टॉम्बस्टोन का ऐक्सेस है, तो मेमोरी मैप के डंप से यह पता लगाया जा सकता है कि पता किस मैपिंग से जुड़ा है.

एक ही थ्रेड में नेस्ट की गई गड़बड़ी

इसका मतलब है कि HWASan क्रैश रिपोर्ट जनरेट करते समय कोई गड़बड़ी हुई. आम तौर पर, ऐसा HWASan रनटाइम में मौजूद किसी बग की वजह से होता है. बग की शिकायत करें. अगर हो सके, तो समस्या को दोहराने के तरीके के बारे में निर्देश दें.