ऐड्रेस सैनिटाइज़र का इस्तेमाल करके, मेमोरी के गड़बड़ी को डीबग करना

इस दस्तावेज़ में, एजीडीई का इस्तेमाल करते समय, डीबग करने के खास टूल चालू करने का तरीका बताया गया है. इन टूल की मदद से, मेमोरी में हुए नुकसान का पता लगाने और डेटा को ओवरराइट करने से जुड़ी गड़बड़ियों को ठीक करने में मदद मिल सकती है.

HWAddress Sanitizer और Address Sanitizer

HWAddress Sanitizer (HWASan) और Address Sanitizer (ASan), मेमोरी में गड़बड़ी की समस्या को डीबग करने वाले टूल हैं. इनकी मदद से, मेमोरी में गड़बड़ी की समस्या को डीबग करने के साथ-साथ, ओवरराइट करने से जुड़ी गड़बड़ियों को भी डीबग किया जा सकता है. जैसे:

  • स्टैक बफ़र ओवरफ़्लो और अंडरफ़्लो
  • हेप बफ़र ओवरफ़्लो और अंडरफ़्लो
  • स्टैक का इस्तेमाल उसके दायरे से बाहर करना
  • डबल फ़्री और वाइल्ड फ़्री से जुड़ी गड़बड़ियां
  • स्टैक का इस्तेमाल, रिटर्न के बाद (सिर्फ़ HWASan के लिए)

हमारा सुझाव है कि HWASan या ASan को सिर्फ़ तब चालू करें, जब किसी समस्या को डीबग किया जा रहा हो या ऑटोमेटेड टेस्टिंग के हिस्से के तौर पर. ये टूल बेहतर परफ़ॉर्म करते हैं. हालांकि, इनका इस्तेमाल करने पर आपको जुर्माना देना पड़ता है.

रनटाइम का व्यवहार

चालू होने पर, HWASan और ASan, दोनों आपके ऐप्लिकेशन में मेमोरी के खराब होने की जांच अपने-आप करते हैं.

अगर मेमोरी से जुड़ी कोई गड़बड़ी का पता चलता है, तो ऐप्लिकेशन SIGBART (सिग्नल बंद करें) वाली गड़बड़ी के साथ क्रैश हो जाता है और logcat में ज़्यादा जानकारी वाला मैसेज प्रिंट करता है. मैसेज की एक कॉपी, /data/tombstones में मौजूद फ़ाइल में भी लिखी जाती है.

गड़बड़ी का मैसेज कुछ ऐसा दिखता है:

ERROR: HWAddressSanitizer: tag-mismatch on address 0x0042a0826510 at pc 0x007b24d90a0c
WRITE of size 1 at 0x0042a0826510 tags: 32/3d (ptr/mem) in thread T0
    #0 0x7b24d90a08  (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x2a08)
    #1 0x7b8f1e4ccc  (/apex/com.android.art/lib64/libart.so+0x198ccc)
    #2 0x7b8f1db364  (/apex/com.android.art/lib64/libart.so+0x18f364)
    #3 0x7b8f2ad8d4  (/apex/com.android.art/lib64/libart.so+0x2618d4)

0x0042a0826510 is located 0 bytes to the right of 16-byte region [0x0042a0826500,0x0042a0826510)
allocated here:
    #0 0x7b92a322bc  (/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so+0x212bc)
    #1 0x7b24d909e0  (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x29e0)
    #2 0x7b8f1e4ccc  (/apex/com.android.art/lib64/libart.so+0x198ccc)

ज़रूरी शर्तें

HWASan से जुड़ी ज़रूरी शर्तें

HWASan का इस्तेमाल करने के लिए:

  • आपके पास AGDE 24.1.99 या इसके बाद का वर्शन होना चाहिए.
  • ऐप्लिकेशन को NDK 26 या उसके बाद के वर्शन का इस्तेमाल करके बनाया जाना चाहिए.
  • ऐप्लिकेशन को टारगेट SDK टूल के 34 या उसके बाद के वर्शन के साथ बनाया जाना चाहिए.
  • टारगेट, Android 14 (एपीआई लेवल 34) या उसके बाद के वर्शन पर चलने वाला arm64-v8a डिवाइस होना चाहिए.

अपने प्रोजेक्ट में शेयर की गई C++ स्टैंडर्ड लाइब्रेरी का इस्तेमाल करना

किसी जानी-पहचानी समस्या की वजह से, libc++_static का इस्तेमाल करते समय ASan, C++ एक्सेप्शन हैंडल करने के साथ काम नहीं करता. libc++_shared का इस्तेमाल करने पर, यह समस्या नहीं दिखती.

HWASan में ऑपरेटर new और delete को लागू करने का अपना तरीका है. अगर स्टैंडर्ड लाइब्रेरी को प्रोजेक्ट में स्टैटिक तौर पर लिंक किया गया है, तो इनका इस्तेमाल नहीं किया जा सकता.

इस सेटिंग को बदलने के लिए, इस दस्तावेज़ का C++ स्टैंडर्ड लाइब्रेरी को लिंक करना सेक्शन देखें.

फ़्रेम पॉइंटर जनरेशन की सुविधा चालू करना

HWASan और ASan, मेमोरी के ऐलोकेशन और डिऐलोकेशन इवेंट के लिए, स्टैक ट्रेस की जानकारी जनरेट करने के लिए, फ़ास्ट फ़्रेम पॉइंटर पर आधारित अनवाइंडर का इस्तेमाल करते हैं. इसका मतलब है कि इन सुविधाओं का इस्तेमाल करने के लिए, आपको C++ कंपाइलर की सेटिंग में फ़्रेम पॉइंटर जनरेशन की सुविधा चालू करनी होगी. इसका मतलब है कि आपको फ़्रेम पॉइंटर को हटाने के लिए ऑप्टिमाइज़ेशन की सुविधा बंद करनी होगी.

इस सेटिंग को बदलने के लिए, इस दस्तावेज़ का फ़्रेम पॉइंटर जनरेशन चालू करना सेक्शन देखें.

HWASan या ASan का इस्तेमाल करने के लिए, अपने Visual Studio प्रोजेक्ट को कॉन्फ़िगर करना

HWASan या ASan को चालू करना

HWASan या ASan चालू करने के लिए, अपने प्रोजेक्ट के प्रॉपर्टी पेजों में कॉन्फ़िगरेशन प्रॉपर्टी > सामान्य पर जाएं.

मौजूदा प्रोजेक्ट के लिए, Visual Studio Solution Explorer प्रॉपर्टी मेन्यू.

पहला इलस्ट्रेशन: Visual Studio Solution Explorer विंडो में, प्रोजेक्ट का प्रॉपर्टी विकल्प.

प्रोजेक्ट प्रॉपर्टी पेजों का डायलॉग, जिसमें सामान्य प्रॉपर्टी दिखाई गई हैं और पते को साफ़ करने की सुविधा की सेटिंग हाइलाइट की गई हैं.

दूसरी इमेज: प्रोजेक्ट की सामान्य प्रॉपर्टी में पते को सुरक्षित करने वाली सुविधा (ASan) की सेटिंग.

अपने प्रोजेक्ट के लिए HWASan चालू करने के लिए, पते की गड़बड़ी ठीक करने वाला टूल (ASan) की सेटिंग को हार्डवेयर ASan चालू है (fsanitize=hwaddress) पर सेट करें.

अपने प्रोजेक्ट के लिए ASan चालू करने के लिए, Address Sanitizer (ASan) सेटिंग को ASan चालू है (fsanitize=address) पर सेट करें.

फ़्रेम पॉइंटर जनरेशन की सुविधा चालू करना

फ़्रेम पॉइंटर जनरेशन को फ़्रेम पॉइंटर हटाएं C/C++ के लिए कॉम्पाइलर सेटिंग से कंट्रोल किया जाता है. इसे प्रोजेक्ट के प्रॉपर्टी पेजों में, कॉन्फ़िगरेशन प्रॉपर्टी > C/C++ > ऑप्टिमाइज़ेशन में देखा जा सकता है.

प्रोजेक्ट प्रॉपर्टी पेजों का डायलॉग, जिसमें C/C++ ऑप्टिमाइज़ेशन प्रॉपर्टी दिखाई गई हैं और फ़्रेम पॉइंटर को हटाने की सेटिंग हाइलाइट की गई हैं.

तीसरी इमेज: फ़्रेम पॉइंटर हटाएं सेटिंग कहां मिलेगी.

HWASan या ASan का इस्तेमाल करते समय, फ़्रेम पॉइंटर को हटाएं सेटिंग को नहीं (-fno-omit-frame-pointer) पर सेट करें.

शेयर की गई लाइब्रेरी मोड में C++ स्टैंडर्ड लाइब्रेरी को लिंक करना

C++ स्टैंडर्ड लाइब्रेरी के लिए लिंकर मोड की सेटिंग, आपके प्रोजेक्ट के प्रॉपर्टी पेजों में कॉन्फ़िगरेशन प्रॉपर्टी > सामान्य में, प्रोजेक्ट डिफ़ॉल्ट सेक्शन में देखी जा सकती है.

प्रोजेक्ट प्रॉपर्टी पेजों का डायलॉग, जिसमें सामान्य कैटगरी चुनी गई है और STL सेटिंग के इस्तेमाल को हाइलाइट किया गया है.

चौथी इमेज: C++ स्टैंडर्ड लाइब्रेरी के लिए, लिंकर मोड की सेटिंग कहां मिलेगी.

HWASan या ASan का इस्तेमाल करते समय, STL का इस्तेमाल करें को C++ स्टैंडर्ड लाइब्रेरी (.so) का इस्तेमाल करें पर सेट करें. यह वैल्यू, C++ स्टैंडर्ड लाइब्रेरी को आपके प्रोजेक्ट में शेयर की गई लाइब्रेरी के तौर पर जोड़ती है. यह वैल्यू, HWASan और ASan के सही तरीके से काम करने के लिए ज़रूरी है.

Address Sanitizer का इस्तेमाल करने के लिए, बिल्ड कॉन्फ़िगरेशन बनाना

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

हालांकि, अगर आपको यह सुविधा काम की लगती है और आपको इसका नियमित तौर पर इस्तेमाल करना है, तो Teapot सैंपल में दिखाए गए तरीके के हिसाब से, HWASan या ASan के लिए नया बिल्ड कॉन्फ़िगरेशन बनाया जा सकता है. उदाहरण के लिए, ऐसा तब किया जा सकता है, जब आप अपनी यूनिट टेस्ट के हिस्से के तौर पर, Address Sanitizer को नियमित तौर पर चलाते हों या अपने गेम के रात भर चलने वाले स्मोके टेस्ट के दौरान.

अलग से बिल्ड कॉन्फ़िगरेशन बनाना तब काफ़ी फ़ायदेमंद हो सकता है, जब आपके पास एक बड़ा प्रोजेक्ट हो और उसमें तीसरे पक्ष की कई लाइब्रेरी का इस्तेमाल किया जाता हो. आम तौर पर, इन लाइब्रेरी को C++ स्टैंडर्ड लाइब्रेरी के साथ स्टैटिक तौर पर लिंक किया जाता है. खास बिल्ड कॉन्फ़िगरेशन की मदद से, यह पक्का किया जा सकता है कि आपकी प्रोजेक्ट सेटिंग हमेशा सटीक रहें.

बिल्ड कॉन्फ़िगरेशन बनाने के लिए, अपने प्रोजेक्ट के प्रॉपर्टी पेजों पर, कॉन्फ़िगरेशन मैनेजर… बटन पर क्लिक करें. इसके बाद, सक्रिय समाधान कॉन्फ़िगरेशन ड्रॉप-डाउन खोलें. इसके बाद, को चुनें और सही नाम के साथ नया बिल्ड कॉन्फ़िगरेशन बनाएं. उदाहरण के लिए, HWASan चालू है.

कस्टम मेमोरी ऐलोकेटर के साथ HWASan का इस्तेमाल करना

HWASan, malloc (या new) के ज़रिए ऐलोकेट की गई मेमोरी को अपने-आप इंटरसेप्ट करता है, ताकि वह पॉइंटर में टैग इंजेक्ट कर सके और टैग मैच न होने की जांच कर सके.

हालांकि, कस्टम मेमोरी ऐलोकेटर का इस्तेमाल करने पर, HWASan आपके कस्टम मेमोरी ऐलोकेशन के तरीकों को अपने-आप इंटरसेप्ट नहीं कर पाता. इसलिए, अगर आपको अपने कस्टम मेमोरी एलोकेटर के साथ HWASan का इस्तेमाल करना है, तो अपने मेमोरी एलोकेटर को साफ़ तौर पर HWASan को कॉल करने के लिए इंस्ट्रूमेंट करें. इसे सिर्फ़ कुछ लाइनों के कोड से किया जा सकता है.

ज़रूरी शर्तें

आपको जिन HWASan तरीकों को कॉल करना है वे इस हेडर में बताए गए हैं:

#include "sanitizer/hwasan_interface.h"

मेमोरी के बंटवारे का तरीका तय करना

  1. ऑब्जेक्ट को 16-बाइट ब्लॉक के हिसाब से बांटें और अलाइन करें. उदाहरण के लिए, अगर आपके पास पूल एलोकेटर है, जो 24-बाइट के साइज़ के फिक्स्ड-साइज़ ऑब्जेक्ट दिखाता है, तो अपने एलोकेशन को 32-बाइट तक राउंड करें और 16-बाइट के हिसाब से अलाइन करें.

  2. 8-बिट टैग जनरेट करें. आपके टैग में 0 से 16 तक की वैल्यू का इस्तेमाल नहीं किया जाना चाहिए, क्योंकि ये वैल्यू इंटरनल इस्तेमाल के लिए रिज़र्व हैं.

  3. उस टैग की मदद से मेमोरी क्षेत्र को ट्रैक करने के लिए, HWASan को चालू करें:

    __hwasan_tag_memory((void*) address, tag, size);
    
  4. अपने पॉइंटर के सबसे ऊपर मौजूद आठ बिट में टैग इंजेक्ट करें:

    address = __hwasan_tag_pointer((void*) address, tag);
    

मेमोरी को डिएलोकेट करने का तरीका तय करना

  1. मेमोरी क्षेत्र के लिए टैग को रीसेट करें, ताकि टैग किए गए मौजूदा पॉइंटर के ज़रिए, आगे के ऐक्सेस न हो पाएं:

    __hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), 0, size);
    

पहले से तय किए गए ऑब्जेक्ट पूल के साथ काम करना

अगर आपका मेमोरी ऐलोकेटर, पूल में ऑब्जेक्ट पहले से ऐलोकेट करता है और उन्हें मुक्त करने के बजाय पूल में वापस लौटाता है, तो मेमोरी और पॉइंटर के लिए, डिएलोकेशन का तरीका सीधे तौर पर नई वैल्यू के साथ टैग को ओवरराइट कर सकता है:

```
__hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), tag, size);
ptr = __hwasan_tag_pointer((void*)ptr, tag);
```

इस तकनीक का इस्तेमाल करने पर, आपके ऐलोकेशन के तरीकों को पॉइंटर या मेमोरी ब्लॉक को टैग करने की ज़रूरत नहीं होती. हालांकि, पूल में ऑब्जेक्ट को पहले से ऐलोकेट करने पर, पॉइंटर और मेमोरी ब्लॉक को टैग करें. इस स्टाइल का इस्तेमाल करने वाले उदाहरण के लिए, PoolAllocator सैंपल देखें.