दिलचस्प पोस्ट
मैं वेबसाइट पर कस्टम फ़ॉन्ट का उपयोग कैसे कर सकता हूं? काफ्का का उपयोग (सीक्यूआरएस) इवेंटस्टोर अच्छा विचार? "आज", "कल", "एक सप्ताह पहले", "एक महीने पहले", "एक साल पहले" के रूप में रिश्तेदार प्रारूप में NSDate कैसे परिवर्तित करें? स्क्रीनएक्स / वाई, क्लाइंट एक्स / वाई और पेजएक्स / वाई में अंतर क्या है? Asp.net MVC पैरामीटर के रूप में नियंत्रक को देखने से JSON ऑब्जेक्ट को कैसे पास करें I ggplot2 का उपयोग कर एक कैनवास में एकाधिक ग्राफ़ जन्म तिथि और प्राप्त दर () पर आधारित आयु (साल में) की गणना कैसे करें पायथन स्ट्रेटम () और समयक्षेत्र? सख्त मानकों: केवल चर संदर्भ PHP 5.4 द्वारा असाइन किया जाना चाहिए एक दृश्य का निर्माण करने के लिए '*' का प्रयोग क्यों करना बुरा है? मैं ब्राउज़र को पेज को प्रदर्शित करने के लिए कैसे इंतजार कर सकता हूं जब तक कि यह पूरी तरह लोड नहीं हो जाता? जावा के साथ Firebase (गैर- android) जानकारी पुनर्प्राप्त करें MFMailComposeViewController का उपयोग करके ईमेल शरीर में एक छवि कैसे जोड़ें एंड्रॉइड स्पैन, स्पैनस्ट्रिंग, स्पैनेबल, स्पॅनलेबल स्ट्रिंग और चारसेंवेन्स कौन सा Iomanip manipulators 'चिपचिपा' रहे हैं?

क्या x86 और x64 पर एक बफ़र के अंत में पढ़ना सुरक्षित है?

उच्च प्रदर्शन एल्गोरिदम में कई तरीके पाए जा सकते हैं (और वे हैं) सरल अगर उन्हें इनपुट बफ़र्स के अंत से एक छोटी राशि पढ़ने की अनुमति दी गई हो। यहां, "छोटी राशि" का अर्थ आम तौर पर W - 1 बाइट के अंत तक होता है, जहां W एल्गोरिथम के बाइट्स में शब्द का आकार होता है (उदाहरण के लिए, 64-बिट खंडों में इनपुट को एल्गोरिदम प्रसंस्करण के लिए 7 बाइट्स तक)।

यह स्पष्ट है कि इनपुट बफर के अंत में लिखना कभी भी सुरक्षित नहीं होता है, सामान्य तौर पर, क्योंकि आप बफर 1 से परे डेटा को घुमा सकते हैं यह भी स्पष्ट है कि किसी बफ़र के दूसरे पृष्ठ में अंत में पढ़ना सेगमेंटेशन फॉल्ट / एक्सेस उल्लंघन हो सकता है, क्योंकि अगले पृष्ठ को पठनीय नहीं किया जा सकता है।

गठबंधन मूल्यों को पढ़ने के विशेष मामले में, हालांकि, एक पृष्ठ गलती असंभव लगता है, कम से कम x 86 पर। उस प्लेटफार्म पर, पृष्ठ (और इसलिए मेमोरी संरक्षण झंडे) में 4K ग्रैन्युलैरिटी होती है (बड़ा पृष्ठ, जैसे 2 एमबी या 1 जीबी, संभव है, लेकिन ये 4K के गुणक हैं) और इतना गठबंधन पढ़ता है कि एक ही पृष्ठ में केवल बाइट्स को मान्य होगा बफर का हिस्सा

यहां कुछ लूप का एक प्रामाणिक उदाहरण है जो इसके इनपुट को संरेखित करता है और बफर के अंत में 7 बाइट्स तक पढ़ता है:

 int processBytes(uint8_t *input, size_t size) { uint64_t *input64 = (uint64_t *)input, end64 = (uint64_t *)(input + size); int res; if (size < 8) { // special case for short inputs that we aren't concerned with here return shortMethod(); } // check the first 8 bytes if ((res = match(*input)) >= 0) { return input + res; } // align pointer to the next 8-byte boundary input64 = (ptrdiff_t)(input64 + 1) & ~0x7; for (; input64 < end64; input64++) { if ((res = match(*input64)) > 0) { return input + res < input + size ? input + res : -1; } } return -1; } 

आंतरिक फ़ंक्शन int match(uint64_t bytes) नहीं दिखाया गया है, लेकिन ऐसा कुछ है जो एक विशिष्ट पैटर्न के साथ एक बाइट मिलान करता है, और पाया जाता है कि निम्नतम स्थिति (0-7) अगर 1-अन्यथा मिले

सबसे पहले, एक्सपोज़र की सादगी के लिए आकार <8 वाले मामलों को दूसरे फ़ंक्शन पर बंद कर दिया जाता है फिर पहले 8 (अनलग बाइट्स) के लिए एक एकल जांच की जाती है। फिर शेष floor((size - 7) / 8) लिए एक लूप किया जाता है floor((size - 7) / 8) 8 बाइट्स 2 का हिस्सा यह लूप बफर के अंत में 7 बाइट्स तक पढ़ सकता है (7 बाइट केस तब होता है जब input & 0xF == 1 )। हालांकि, वापसी कॉल में एक चेक होता है जिसमें कोई नकली मिलान नहीं होता है जो बफर के अंत से परे होता है।

व्यावहारिक रूप से बोलना, क्या इस तरह के एक समारोह x86 और x86-64 पर सुरक्षित है?

इन प्रकार के ओरेरेड्स उच्च प्रदर्शन कोड में सामान्य हैं। ऐसे ओवरराइड से बचने के लिए विशेष पूंछ कोड भी आम है कभी-कभी आप वाल्ग्रिंड जैसे चुप्पी उपकरणों के लिए पूर्व की जगह को बदलते हैं। कभी-कभी आप ऐसे प्रतिस्थापन के प्रस्ताव को देखते हैं, जो मैदान पर खारिज कर दिया जाता है मुहावरे सुरक्षित है और उपकरण त्रुटि (या बस बहुत रूढ़िवादी) है

भाषा वकीलों के लिए एक नोट:

पॉइंट को अपने आवंटित आकार से परे पढ़ना निश्चित रूप से मानक में नहीं है। मैं भाषा के वकील जवाबों की सराहना करता हूं, और यहां तक ​​कि कभी-कभी उन्हें स्वयं लिखता हूं, और जब भी कोई एक अध्याय और कविता खोदता है, जो उपरोक्त कोड को दिखाता है, तब तक मैं खुश रहूंगा और इसलिए मैं इसे सही तरीके से सुरक्षित नहीं करता (और मैं प्रतिलिपि दूंगा विवरण यहाँ)। अंततः हालांकि, यह नहीं है कि मैं इसके बाद क्या हूं। एक व्यावहारिक मामला के रूप में, कई सामान्य मुहावरे जिनमें पॉइंटर कनवर्ज़न, संरचना का उपयोग शामिल है, हालांकि इस तरह के संकेत और तांत्रिक तौर पर अपरिभाषित हैं, लेकिन उच्च गुणवत्ता और उच्च प्रदर्शन कोड में व्यापक हैं। अक्सर कोई विकल्प नहीं होता है, या वैकल्पिक आधा गति या उससे कम पर चलता है

यदि आप चाहें, तो इस प्रश्न का एक संशोधित संस्करण देखें, जो है:

उपरोक्त कोड x86 / x86-64 विधानसभा में संकलित किया गया है, और उपयोगकर्ता ने यह सत्यापित किया है कि यह अपेक्षित तरीके से संकलित है (यानी, संकलक ने वास्तव में कुछ करने के लिए आंशिक रूप से आउट-ऑफ-बाउंड एक्सेस का उपयोग नहीं किया है चालाक , संकलित प्रोग्राम को सुरक्षित कर रहा है?

उस संबंध में, यह प्रश्न सी प्रश्न और एक x86 विधानसभा सवाल दोनों है। इस युगल का उपयोग करते हुए अधिकांश कोड सी में लिखे गए हैं, और सी अभी भी उच्च प्रदर्शन पुस्तकालयों के लिए प्रमुख भाषा है, आसानी से एएमएम जैसे कम स्तर की सामग्री को ग्रहण कर रही है, और उच्चतर चीजें जैसे <सब कुछ » कट्टर संख्यात्मक आला के बाहर कम से कम जहां फोरट्रान अभी भी गेंद बजाता है। इसलिए मुझे सी-कंपाइलर और नीचे दिए गए प्रश्न के बारे में दिलचस्पी है, इसलिए मैंने इसे शुद्ध x86 विधानसभा प्रश्न के रूप में तैयार नहीं किया है।

जो सभी ने कहा, जबकि मैं केवल मानक दिखने वाले मानक के लिंक में दिलचस्पी है, यह यूडी है, मुझे वास्तविक क्रियान्वयन के किसी भी विवरण में बहुत दिलचस्पी है जो इस विशिष्ट यूडी को अप्रत्याशित कोड बनाने के लिए उपयोग कर सकते हैं। अब मुझे नहीं लगता है कि यह कुछ गहरे सुंदर गहरे पार-प्रक्रिया विश्लेषण के बिना हो सकता है, लेकिन जीसीसी अतिप्रवाह सामान ने बहुत सारे लोगों को आश्चर्यचकित किया …


1 जाहिरा तौर पर हानिरहित मामलों में, उदाहरण के लिए, जहां एक ही मान वापस लिखा जाता है, यह समवर्ती कोड को तोड़ सकता है।

2 इस ओवरलैपिंग काम के लिए ध्यान देने की आवश्यकता है कि यह फ़ंक्शन और match() फ़ंक्शन किसी विशेष idempotent तरीके से व्यवहार करता है – विशेष रूप से कि वापसी मूल्य ओवरलैपिंग चेक का समर्थन करता है इसलिए "पहले बाइट मिलान वाला पैटर्न ढूंढें" क्योंकि सभी match() कॉल अभी भी क्रम में हैं। एक "गिनती बाइट्स मिलान पैटर्न" विधि काम नहीं करती, हालांकि, क्योंकि कुछ बाइट्स को दोबारा गिना जा सकता है। एक तरफ के रूप में: "न्यूनतम बाइट लौटें" कॉल जैसे कुछ फ़ंक्शन इन-ऑर्डर प्रतिबंध के बिना भी काम करेंगे, लेकिन सभी बाइट्स की जांच करनी होगी।

3 यह ध्यान देने योग्य है कि --partial-loads-ok लिए एक ध्वज है , – --partial-loads-ok जो इस बात को नियंत्रित करता है कि क्या इस तरह की --partial-loads-ok वास्तव में एक त्रुटि के रूप में की गई है। डिफ़ॉल्ट हां है , इसका मतलब है कि सामान्य तौर पर ऐसे भार को तत्काल त्रुटियों के रूप में नहीं माना जाता है, लेकिन यह लोड बाइट्स के बाद के उपयोग को ट्रैक करने के लिए एक प्रयास किया गया है, जिनमें से कुछ मान्य हैं और जिनमें से कुछ नहीं हैं, त्रुटि के साथ फ़्लैग किए गए अगर आउट-ऑफ-रेंज बाइट्स का उपयोग किया जाता है उपरोक्त उदाहरण के मामले में, जिसमें पूरे शब्द को match() में पहुंचाया जाता है, ऐसे विश्लेषण से निष्कर्ष निकाला जाएगा कि बाइट्स का उपयोग किया जाता है, भले ही परिणामों को अंततः छोड़ा गया हो। वालग्रिंड सामान्य तौर पर यह निर्धारित नहीं कर सकता कि आंशिक भार से अमान्य बाइट वास्तव में उपयोग किए जाते हैं (और सामान्य रूप में पता लगाना शायद बहुत कठिन है)

Solutions Collecting From Web of "क्या x86 और x64 पर एक बफ़र के अंत में पढ़ना सुरक्षित है?"

हां, यह x86 asm में सुरक्षित है, और मौजूदा libc strlen(3) कार्यान्वयन इस का लाभ उठाते हैं।

यह सी में भी सुरक्षित है, x86 के लिए संकलित है, जहां तक ​​मुझे पता है। किसी ऑब्जेक्ट के बाहर पढ़ना कोर्स में है, सी में अपरिभाषित व्यवहार, लेकिन सी-लक्ष्यीकरण-x 86 के लिए यह अच्छी तरह से परिभाषित है। मुझे लगता है कि यह यूबी की तरह नहीं है कि आक्रामक कंपलर अनुकूलन करते समय ऐसा नहीं हो पाएंगे, लेकिन इस बिंदु पर एक संकलक-लेखक की पुष्टि अच्छी होगी, विशेषकर उन मामलों के लिए जहां यह संकलन-समय पर सहज रूप से संभव है, जो एक पहुंच से बाहर हो जाता है एक वस्तु के अंत में पिछले (@RossRidge के साथ टिप्पणियों में चर्चा देखें: इस उत्तर के पिछले संस्करण ने यह स्पष्ट किया कि यह बिल्कुल सुरक्षित था, लेकिन एलएलवीएम ब्लॉग पोस्ट वास्तव में उस तरीके से नहीं पढ़ता है)।

आपके द्वारा प्राप्त डेटा अप्रत्याशित कूड़ा है, लेकिन कोई अन्य संभावित दुष्प्रभाव नहीं होगा। जब तक आपका प्रोग्राम कचरा बाइट्स से प्रभावित नहीं होता है, तब तक यह ठीक है। (जैसे कि यूआईटी 64_ टी के बाइट्स में से शून्य शून्य है , तो पहले शून्य बाइट को खोजने के लिए एक बाइट लूप का उपयोग करें, भले ही कचरे से बाहर क्या है।


इसी प्रकार, एक कलाकार के साथ अनियंत्रित पॉइंटर्स बनाना सी मानक में यूबी है (भले ही आप उन्हें डिफरेंश नहीं करते हैं)। यह x86 को लक्षित करते समय सभी ज्ञात सी कंपाइलर्स में अच्छी तरह से परिभाषित है इंटेल के एसएसई इन्टरिनिक्स भी इसकी आवश्यकता होती है; जैसे __m128i _mm_loadu_si128 (__m128i const* mem_addr) एक __m128i 16-बाइट __m128i लिए एक संकेतक लेता है।

(AVX512 के लिए, उन्होंने अंत में बदल दिया है कि असुविधाजनक डिज़ाइन पसंद को void* __m512i _mm512_loadu_si512 (void const* mem_addr) जैसे नए __m512i _mm512_loadu_si512 (void const* mem_addr) लिए void* कर दिया गया है।

यहां तक ​​कि एक unaligned uint64_t* या int* को uint64_t* करना सुरक्षित है (और अच्छी तरह से परिभाषित व्यवहार है) x86 के लिए संकलित सी में। हालांकि, एक __m128i* सीधे (लोड / स्टोर movdqa का उपयोग करने के बजाय) का उपयोग करना movdqa का उपयोग movdqa , जो movdqa पॉइंटर्स पर दोष है।


आम तौर पर इस तरह की छोरियां किसी भी अतिरिक्त कैश लाइनों को छूने से बचती हैं, जिनके कारण प्रदर्शन के कारणों के लिए उन्हें न सिर्फ पृष्ठों को स्पर्श करना पड़ता है।

यह बहुत कम संभावना नहीं है कि मेमोरी-मैप किए गए I / O रजिस्टरों को एक ही पृष्ठ में बफर के रूप में होना चाहिए जो आपको विस्तृत भार, या विशेष रूप से एक ही 64B कैश-लाइन के साथ लूप करना चाहता था, भले ही आप इस तरह से फ़ंक्शन बुला रहे हों डिवाइस ड्रायवर (या एक्स-सर्वर जैसे उपयोगकर्ता-स्पेस प्रोग्राम जो कुछ एमएमआईओ स्पेस मैप किया हुआ है)।

यदि आप 60-बाइट बफर को प्रोसेस कर रहे हैं और 4-बाइट एमआईएमओ रजिस्टर से पढ़ने से बचने की आवश्यकता है, तो आप इसके बारे में पता करेंगे इस तरह की स्थिति सामान्य कोड के लिए नहीं होती है


strlen एक लूप का strlen उदाहरण है जो एक अंतर्निहित-लंबाई बफर को क्रियान्वित करता है और इस प्रकार बफर के अंत के पूर्व के बिना पढ़ा बिना वेक्टर की जा सकती है। अगर आपको टर्मिनल 0 बाइट के पिछले पढ़ने से बचने की आवश्यकता है, तो आप केवल एक समय में एक बाइट पढ़ सकते हैं।

उदाहरण के लिए, glibc के कार्यान्वयन से पहले 64B संरेखण सीमा तक डेटा को संभालने के लिए प्रस्तावना का उपयोग किया जाता है। फिर मुख्य पाश (asm स्रोत के लिए gitweb लिंक) में , यह चार SSE2 गठबंधन भार का उपयोग कर एक पूरे 64B कैश लाइन लोड करता है। यह उन्हें नीचे एक सदिश में pminub (अहस्ताक्षरित बाइट्स का न्यूनतम) में विलीन कर लेता है, इसलिए अंतिम वेक्टर के पास शून्य तत्व होगा, यदि चार वैक्टरों में से कोई भी शून्य हो। यह पता लगाने के बाद कि स्ट्रिंग का अंत उस कैश लाइन में कहीं था, यह चार वैक्टरों में से प्रत्येक को अलग से जांचता है जहां यह देखने के लिए कि (सदिश के भीतर स्थित स्थिति को खोजने के लिए pmovmskb -शून्य के एक सदिश के खिलाफ ठेठ pcmpeqb और pmovmskb / bsf का प्रयोग करना।) pmovmskb को चुनने के लिए कुछ अलग स्ट्रेलन रणनीतियां थीं , लेकिन मौजूदा एक सभी x86-64 सीपीयू।


एक बार में 64B को लोड करना निश्चित रूप से एक 64B- गठबंधन सूचक से सुरक्षित होता है, क्योंकि स्वाभाविक रूप से गठबंधन पहुंच कैश-लाइन या पेज-लाइन सीमाओं को पार नहीं कर सकती है ।


अगर आप समय से पहले बफर की लंबाई का पता लगाते हैं, तो बफर के आखिरी बाइट पर समाप्त होने वाले अनारक्षित लोड का उपयोग करके अंतिम संरेखित वेक्टर से परे बाइट्स को संभालने से पहले आप बाइट्स को पढ़ने से बच सकते हैं। (फिर से, यह केवल idempotent एल्गोरिदम के साथ काम करता है, जैसे मेम्सी, जो कि परवाह नहीं करते हैं कि वे गंतव्य में स्टोर्स को ओवरलैप करते हैं। संशोधित-इन-प्लेस एल्गोरिदम अक्सर ऐसा नहीं कर सकते हैं, सिवाय कोई स्ट्रिंग को ऊपरी- एसएसई 2 के साथ मामला है , जहां पहले से ही ऊपर उठाए गए डेटा को दोबारा शुरू करना ठीक है। स्टोर-अग्रेषण स्टाल के अलावा यदि आप अपने अन्तर्निहित लोड करते हैं जो आपके अंतिम संरेखित स्टोर से ओवरलैप करता है।)

यदि आप गैर-सीपीयू उपकरणों के विचार की अनुमति देते हैं, तो संभावित असुरक्षित संचालन का एक उदाहरण पीसीआई-मैप किए गए मेमोरी पेजों के आउट-ऑफ-बाउंड क्षेत्र तक पहुंच रहा है। इसमें कोई गारंटी नहीं है कि लक्ष्य डिवाइस एक ही पृष्ठ आकार या संरेखण का प्रयोग मुख्य स्मृति सबसिस्टम के रूप में कर रहा है। उदाहरण के लिए, एक्सेस करने का प्रयास [cpu page base]+0x800 उपकरण पृष्ठ की गलती को चालू कर सकता है अगर डिवाइस 2KiB पृष्ठ मोड में है यह आम तौर पर सिस्टम बगचेक का कारण होगा