हां, आईएसओ सी ++ इस विकल्प को बनाने के लिए कार्यान्वयन की अनुमति देता है (लेकिन इसकी आवश्यकता नहीं है)।
लेकिन यह भी ध्यान दें कि आईएसओ सी ++ एक संकलक को कोड से बाहर निकलने की अनुमति देता है जो उद्देश्य पर क्रैश करता है (जैसे कि एक अवैध निर्देश के साथ) यदि प्रोग्राम यूबी का सामना करता है, उदाहरण के लिए त्रुटियों को खोजने में मदद करने के लिए। (या क्योंकि यह डेथक्राफ्ट 9000 है। कड़ाई से अनुरूप होना किसी भी वास्तविक उद्देश्य के लिए उपयोगी होने के लिए C ++ कार्यान्वयन के लिए पर्याप्त नहीं है)। इसलिए आईएसओ सी ++ एक संकलक को असम्बद्ध बनाने की अनुमति देगा जो एक समान कोड पर भी दुर्घटनाग्रस्त (पूरी तरह से अलग कारणों से) हो uint32_t
। भले ही यह कोई ट्रैप अभ्यावेदन के साथ एक निश्चित लेआउट प्रकार होना आवश्यक है।
यह एक दिलचस्प सवाल है कि वास्तविक कार्यान्वयन कैसे काम करते हैं, लेकिन याद रखें कि भले ही जवाब अलग था, फिर भी आपका कोड असुरक्षित होगा क्योंकि आधुनिक C ++ असेंबली भाषा का एक पोर्टेबल संस्करण नहीं है।
आप x86-64 सिस्टम V ABI के लिए संकलन कर रहे हैं , जो निर्दिष्ट करता है कि bool
एक रजिस्टर में एक फ़ंक्शन arg बिट-पैटर्न false=0
औरtrue=1
रजिस्टर 1 के निम्न 8 बिट्स द्वारा दर्शाया गया है । स्मृति में, bool
एक 1-बाइट प्रकार है जो फिर से 0 या 1 का पूर्णांक मान होना चाहिए।
(एक एबीआई कार्यान्वयन विकल्पों का एक सेट है जो एक ही मंच के लिए संकलक सहमत होते हैं ताकि वे कोड बना सकें जो एक दूसरे के कार्यों को कॉल करते हैं, जिसमें प्रकार आकार, संरचना लेआउट नियम और कॉलिंग कन्वेंशन शामिल हैं।)
ISO C ++ इसे निर्दिष्ट नहीं करता है, लेकिन यह ABI निर्णय व्यापक है क्योंकि यह bool-> int रूपांतरण सस्ते (सिर्फ शून्य-विस्तार) बनाता है । मैं किसी भी ABI के बारे में नहीं जानता जो bool
किसी आर्किटेक्चर के लिए 0 या 1 के लिए कंपाइलर को मानने नहीं देती (न कि सिर्फ x86)। यह कम बिट को फ्लिप करने के !mybool
साथ अनुकूलन की अनुमति देता है xor eax,1
: कोई भी संभावित कोड जो सिंगल सीपीयू इंस्ट्रक्शन में 0 और 1 के बीच बिट / पूर्णांक / बूल को फ्लिप कर सकता है । या a&&b
एक बिट वाइज और bool
प्रकारों के लिए संकलन । कुछ कंपाइलर असल में बुलियन मान का फायदा उठाते हैं क्योंकि कंपाइलर में 8 बिट होते हैं। क्या उन पर परिचालन अक्षम है? ।
सामान्य तौर पर, जैसा कि नियम के अनुसार संकलक उन चीजों का लाभ उठाने की अनुमति देता है जो लक्ष्य प्लेटफ़ॉर्म पर सत्य हैं, जिनके लिए संकलित किया जा रहा है , क्योंकि अंतिम परिणाम निष्पादन योग्य कोड होगा जो C ++ स्रोत के समान बाह्य-दृश्य व्यवहार को लागू करता है। (उन सभी प्रतिबंधों के साथ जो अपरिभाषित व्यवहार वास्तव में "बाहरी रूप से दिखाई देते हैं": एक डिबगर के साथ नहीं, बल्कि एक अन्य सूत्र से एक सुव्यवस्थित / कानूनी C ++ प्रोग्राम में।
संकलक निश्चित रूप से अपने कोड पीढ़ी में एक ABI गारंटी का पूरा लाभ लेने, और जैसे आप पाया जो अनुकूलन कर कोड बनाने के लिए अनुमति दी है strlen(whichString)
करने के लिए
5U - boolValue
। (बीटीडब्लू, यह अनुकूलन एक तरह का चतुर है, लेकिन शायद शॉर्टसाइट बनाम ब्रांचिंग और memcpy
तत्काल डेटा 2 के स्टोर के रूप में इनलाइनिंग ।)
या संकलक बिंदुओं की एक तालिका बना सकता है और इसे पूर्णांक मान के साथ अनुक्रमित कर सकता है bool
, फिर से यह मानकर कि यह 0 या 1. है ( यह संभावना है कि @ Barmar का सुझाव दिया गया है ।)
__attribute((noinline))
ऑप्टिमाइज़ेशन के साथ आपके कंस्ट्रक्टर ने स्टैक से सिर्फ एक बाइट को लोड करने के लिए क्लैंग के रूप में इस्तेमाल किया uninitializedBool
। यह ऑब्जेक्ट के लिए अंतरिक्ष बनाया main
के साथ push rax
(जो छोटे और विभिन्न कारण के लिए है के रूप में कुशल के रूप में के बारे में sub rsp, 8
), इसलिए जो कुछ भी कचरा प्रवेश पर अल में था करने के लिए main
मूल्य इसके लिए प्रयोग किया जाता है uninitializedBool
। यही कारण है कि आपको वास्तव में ऐसे मूल्य मिले हैं जो अभी नहीं थे 0
।
5U - random garbage
आसानी से एक बड़े अहस्ताक्षरित मूल्य में लिपटे जा सकते हैं, बिना किसी स्मृति के जाने के लिए यादगार। गंतव्य स्टैटिक स्टोरेज में है, स्टैक नहीं, इसलिए आप रिटर्न एड्रेस या कुछ और नहीं लिख रहे हैं।
अन्य कार्यान्वयन विभिन्न विकल्प, जैसे false=0
और कर सकते हैं true=any non-zero value
। फिर क्लेंग शायद यूबी के इस विशिष्ट उदाहरण के लिए कोड को क्रैश नहीं करेगा । (लेकिन अगर यह चाहते थे, तब भी इसे अनुमति दी जाएगी।) मुझे किसी भी कार्यान्वयन के बारे में नहीं पता है जो x86-64 के लिए कुछ भी चुनता है bool
, लेकिन सी ++ मानक कई चीजों की अनुमति देता है जो कोई भी करता है या करना भी नहीं चाहेगा। हार्डवेयर जो वर्तमान सीपीयू की तरह है।
आईएसओ C ++ इसे अनिर्दिष्ट छोड़ देता है कि जब आप किसी वस्तु के वस्तु निरूपण की जांच करेंगे या संशोधित करेंगे तो आप क्या पाएंगेbool
। (उदाहरण के द्वारा memcpy
ing bool
में unsigned char
है, जो आप क्योंकि ऐसा करने की अनुमति कर रहे हैं char*
कर सकते हैं उर्फ कुछ भी। और unsigned char
कोई पैडिंग बिट्स के लिए गारंटी है, तो सी ++ मानक औपचारिक रूप से आप किसी भी यूबी के बिना वस्तु अभ्यावेदन hexdump जाने है। वस्तु कॉपी करने के लिए सूचक कास्टिंग प्रतिनिधित्व char foo = my_bool
, निश्चित रूप से असाइन करने से अलग है , इसलिए 0 या 1 के लिए बूलियनकरण नहीं होगा और आपको कच्ची वस्तु प्रतिनिधित्व मिलेगा।)
आप संकलक से इस निष्पादन पथ पर UB को आंशिक रूप से "छिपा" रहे हैंnoinline
। यहां तक कि अगर यह इनलाइन नहीं करता है, हालांकि, इंटरप्रोडेक्टोरल ऑप्टिमाइज़ेशन अभी भी फ़ंक्शन का एक संस्करण बना सकता है जो किसी अन्य फ़ंक्शन की परिभाषा पर निर्भर करता है। (सबसे पहले, क्लैंग एक निष्पादन योग्य बना रहा है, न कि एक यूनिक्स साझा पुस्तकालय जहां प्रतीक-अंतर्संबंध हो सकता है। दूसरा, परिभाषा के अंदर की class{}
परिभाषा इसलिए सभी अनुवाद इकाइयों में एक ही परिभाषा होनी चाहिए। जैसे inline
कीवर्ड के साथ ।)
इसलिए एक संकलक परिभाषा के रूप में सिर्फ ( ret
या ud2
अवैध निर्देश) का उत्सर्जन कर सकता है main
, क्योंकि main
अपरिहार्य रूप से शीर्ष पर शुरू होने वाले निष्पादन का मार्ग अपरिभाषित व्यवहार का सामना करता है। (जो संकलक संकलन समय पर देख सकता है यदि उसने गैर-इनलाइन निर्माता के माध्यम से पथ का पालन करने का निर्णय लिया है।)
यूबी का सामना करने वाला कोई भी कार्यक्रम अपने पूरे अस्तित्व के लिए पूरी तरह से अपरिभाषित है। लेकिन एक फ़ंक्शन या if()
शाखा के अंदर यूबी जो वास्तव में कभी नहीं चलता है, बाकी कार्यक्रम को भ्रष्ट नहीं करता है। व्यवहार में इसका मतलब है कि संकलक एक अवैध निर्देश का उत्सर्जन करने का निर्णय ले सकते हैं, या किसी ret
भी चीज़ का उत्सर्जन नहीं कर सकते हैं और अगले ब्लॉक / फ़ंक्शन में गिर सकते हैं, पूरे मूल ब्लॉक के लिए जो यूबी को शामिल या लीड करने के लिए संकलन समय पर साबित हो सकता है।
जीसीसी और व्यवहार में बजना है वास्तव में कभी कभी फेंकना ud2
बजाय भी निष्पादन के पथ है कि कोई मतलब के लिए कोड उत्पन्न करने की कोशिश कर के, यूबी पर। या गैर- void
समारोह के अंत में गिरने जैसे मामलों के लिए , जीसीसी कभी-कभी एक ret
निर्देश छोड़ देगा । यदि आप सोच रहे थे कि "मेरा कार्य RAX में जो भी कचरा है, उसके साथ वापस आ जाएगा", तो आप गलती से गलत हैं। आधुनिक C ++ कंपाइलर भाषा का व्यवहार किसी पोर्टेबल असेंबली भाषा की तरह नहीं करते हैं। आपके प्रोग्राम को वास्तव में मान्य होना चाहिए C ++, इस बारे में धारणा बनाए बिना कि आपके फ़ंक्शन का स्टैंड-अलोन नॉन इनलाइन संस्करण कैसा हो सकता है।
एक और मज़ेदार उदाहरण यह है कि एमएमए 64 पर एमएमएफ़ मेमोरी को कभी-कभी सीगफॉल्ट तक पहुंच क्यों नहीं दिया जाता है ? । x86 अनइंस्टॉल किए गए पूर्णांकों पर गलती नहीं करता है, है ना? तो एक मिथ्या uint16_t*
समस्या क्यों होगी ? क्योंकि alignof(uint16_t) == 2
, उस धारणा का उल्लंघन करने पर SSE2 के साथ ऑटो-वेक्टरिंग होने पर सेगफॉल्ट हुआ।
यह भी देखें कि हर सी प्रोग्रामर को अपरिहार्य व्यवहार # 1/3 के बारे में जानना चाहिए , एक क्लैंग डेवलपर द्वारा एक लेख।
मुख्य बिंदु: यदि संकलक ने संकलित समय पर UB को देखा, तो यह आपके कोड के माध्यम से पथ को "तोड़" सकता है (आश्चर्य से बाहर निकल सकता है) जो ABB को लक्षित करने पर भी UB का कारण बनता है, जहां किसी भी बिट-पैटर्न के लिए एक वैध वस्तु प्रतिनिधित्व है bool
।
प्रोग्रामर द्वारा कई गलतियों के प्रति कुल शत्रुता की अपेक्षा करें, विशेष रूप से आधुनिक संकलक के बारे में बातें। यही कारण है कि आपको -Wall
चेतावनी का उपयोग और ठीक करना चाहिए । C ++ एक उपयोगकर्ता के अनुकूल भाषा नहीं है, और C ++ में कुछ भी असुरक्षित हो सकता है, भले ही वह उस लक्ष्य पर सुरक्षित हो जो आप के लिए संकलन कर रहे हैं। (उदाहरण के लिए हस्ताक्षरित अतिप्रवाह U ++ C ++ में है और संकलक मानेंगे कि ऐसा तब नहीं होता है, जब तक कि आप 2 पूरक x86 के लिए संकलन नहीं करते हैं, जब तक आप उपयोग नहीं करते हैं clang/gcc -fwrapv
।)
कंपाइल-टाइम-दृश्यमान यूबी हमेशा खतरनाक होता है, और यह सुनिश्चित करना बहुत कठिन है (लिंक-टाइम ऑप्टिमाइज़ेशन के साथ) जो आपने यूबी को वास्तव में कंपाइलर से छिपाया है और इस तरह से यह उत्पन्न कर सकता है कि किस तरह का एएसएम है।
अति-नाटकीय होने के लिए नहीं; अक्सर कंपाइलर आपको कुछ चीज़ों से दूर कर देते हैं और कोड को छोड़ देते हैं जैसे कि आप उम्मीद कर रहे हैं कि कुछ यूबी है। लेकिन शायद यह भविष्य में एक समस्या होगी यदि कंपाइलर देव कुछ अनुकूलन को लागू करते हैं जो मूल्य-सीमाओं के बारे में अधिक जानकारी प्राप्त करते हैं (जैसे कि एक चर गैर-नकारात्मक है, शायद यह x86- पर मुक्त शून्य-विस्तार के लिए साइन-एक्सटेंशन का अनुकूलन करने की अनुमति देता है- 64)। उदाहरण के लिए, वर्तमान gcc और clang में, करना हमेशा-झूठ के रूप में tmp = a+INT_MIN
अनुकूलन नहीं करता है a<0
, केवल वह tmp
हमेशा नकारात्मक होता है। (क्योंकि INT_MIN
+ a=INT_MAX
यह 2 के पूरक लक्ष्य पर नकारात्मक है, और a
है कि तुलना में किसी भी अधिक नहीं हो सकता है।)
इसलिए gcc / clang वर्तमान में गणना के इनपुट के लिए श्रेणी जानकारी प्राप्त करने के लिए पीछे नहीं हटते हैं , केवल बिना हस्ताक्षर किए अतिप्रवाह की धारणा के आधार पर परिणामों पर: गॉडबोल्ट पर उदाहरण । मुझे नहीं पता कि यह अनुकूलन उपयोगकर्ता-मित्रता या क्या के नाम पर जानबूझकर "चूक" गया है।
यह भी ध्यान दें कि कार्यान्वयन (उर्फ कंपाइलर) को आईएसओ सी ++ के अपरिभाषित होने वाले व्यवहार को परिभाषित करने की अनुमति है । उदाहरण के लिए, इंटेल के आंतरिक (जैसे _mm_add_ps(__m128, __m128)
मैनुअल SIMD वेक्टराइजेशन के लिए) का समर्थन करने वाले सभी कंपाइलर्स को गलत-संरेखित बिंदु बनाने की अनुमति देनी चाहिए, जो कि C ++ में UB है, भले ही आप उन्हें डीरेंस न करें। एक या नहीं, __m128i _mm_loadu_si128(const __m128i *)
एक गलत तरीके से __m128i*
आर्ग ले कर भारित नहीं करता है । हार्डवेयर वेक्टर पॉइंटर और संबंधित अपरिभाषित व्यवहार के बीच `reinterpret_cast`ing है?void*
char*
GNU C / C ++ -fwrapv
सामान्य हस्ताक्षरित-अतिप्रवाह UB नियमों से अलग एक नकारात्मक हस्ताक्षरित संख्या (यहां तक कि बिना ) के बाएं-शिफ्टिंग के व्यवहार को भी परिभाषित करता है। ( यह आईएसओ सी ++ में यूबी है , जबकि हस्ताक्षरित संख्याओं की सही शिफ्ट कार्यान्वयन-परिभाषित (तार्किक बनाम अंकगणित) हैं; अच्छी गुणवत्ता कार्यान्वयन एचडब्ल्यू पर अंकगणित का चयन करता है जिसमें अंकगणितीय दाएं बदलाव होते हैं, लेकिन आईएसओ सी ++ निर्दिष्ट नहीं करता है)। यह जीसीसी मैनुअल के इंटेगर खंड में प्रलेखित है , कार्यान्वयन-परिभाषित व्यवहार को परिभाषित करने के साथ कि सी मानकों को एक या दूसरे तरीके से परिभाषित करने के लिए कार्यान्वयन की आवश्यकता होती है।
गुणवत्ता के कार्यान्वयन के मुद्दे निश्चित रूप से हैं जो कंपाइलर डेवलपर्स की देखभाल करते हैं; वे आम तौर पर ऐसे संकलक बनाने की कोशिश नहीं कर रहे हैं जो जानबूझकर शत्रुतापूर्ण हैं, लेकिन सी ++ में सभी यूबी गड्ढों का लाभ उठाते हैं (सिवाय उनके जिन्हें वे परिभाषित करने के लिए चुनते हैं) कई बार बेहतर करने के लिए लगभग अप्रभेद्य हो सकते हैं।
फुटनोट 1 : ऊपरी 56 बिट्स कचरा हो सकता है जिसे कैलली को अनदेखा करना चाहिए, जैसे कि एक रजिस्टर की तुलना में संकीर्ण प्रकार के लिए।
( अन्य कपड़े कर यहां विभिन्न विकल्प बनाने । कुछ संकीर्ण पूर्णांक प्रकार की आवश्यकता होती है शून्य या साइन-बढ़ा एक रजिस्टर को भरने के लिए होने के लिए जब करने के लिए पारित कर दिया या काम करता है, MIPS64 और PowerPC64 तरह से लौट आए। के अंतिम अनुभाग देखें इस x86-64 जवाब जो पहले आईएसएएस बनाम उन लोगों की तुलना करता है ।)
उदाहरण के लिए, एक कॉलर a & 0x01010101
ने RDI में गणना की होगी और कॉल करने से पहले इसका इस्तेमाल किसी और चीज़ के लिए किया होगा bool_func(a&1)
। कॉलर दूर का अनुकूलन कर सकता है &1
क्योंकि यह पहले से ही कम बाइट के हिस्से के रूप में किया था and edi, 0x01010101
, और यह जानता है कि कैली को उच्च बाइट्स को अनदेखा करना आवश्यक है।
या अगर एक बूल को तीसरे आर्ग के रूप में पारित किया जाता है, तो शायद कोड-आकार के लिए अनुकूलन करने वाला एक कॉलर mov dl, [mem]
इसके बजाय इसे लोड करता है movzx edx, [mem]
, जो आरडीएक्स के पुराने मूल्य (या अन्य आंशिक-रजिस्टर प्रभाव) के आधार पर एक झूठी निर्भरता की कीमत पर 1 बाइट की बचत करता है। सीपीयू मॉडल पर)। या mov dil, byte [r10]
इसके बजाय पहले arg के लिए movzx edi, byte [r10]
, क्योंकि दोनों को वैसे भी REX उपसर्ग की आवश्यकता होती है।
यही कारण है कि बजना का उत्सर्जन करता है movzx eax, dil
में Serialize
, के बजाय sub eax, edi
। (पूर्णांक आर्गन्स के लिए, क्लैग इस ABI नियम का उल्लंघन करता है, इसके बजाय gcc के अनिर्दिष्ट व्यवहार पर निर्भर करता है और शून्य-बिट्स को 32 बिट्स तक सीमित करता है या साइन-एक्सटेंड करता है। किसी सूचक के लिए 32 बिट ऑफसेट को जोड़ने पर साइन या शून्य एक्सटेंशन की आवश्यकता होती है। x86-64 ABI;
इसलिए मुझे यह देखने में दिलचस्पी थी कि यह उसी काम को नहीं करता है bool
।)
फुटनोट 2: शाखाओं में mov
बँटने के बाद, आपके पास बस एक 4-बाइट , या 4-बाइट + 1-बाइट स्टोर होगा। लंबाई दुकान की चौड़ाई + ऑफसेट में निहित है।
OTOH, ग्लिबेक मेम्स्की दो 4-बाइट लोड / स्टोर करेगा जो एक ओवरलैप के साथ होता है जो लंबाई पर निर्भर करता है, इसलिए यह वास्तव में बूलियन पर पूरी तरह से सशर्त शाखाओं से मुक्त बनाने का काम करता है। देखें L(between_4_7):
ब्लॉक glibc के memcpy / memmove में। या कम से कम, चंकी आकार का चयन करने के लिए मेमकी की शाखाओं में बूलियन के लिए उसी तरह से जाएं।
यदि mov
inlining , आप 2x -immediate + cmov
और एक सशर्त ऑफसेट का उपयोग कर सकते हैं , या आप स्ट्रिंग डेटा को स्मृति में छोड़ सकते हैं।
या अगर इंटेल आइस लेक के लिए ट्यूनिंग ( फास्ट शॉर्ट आरईपी एमओवी सुविधा के साथ ), एक वास्तविक rep movsb
इष्टतम हो सकता है। glibc उस सुविधा के साथ CPU पर छोटे आकारों के लिए memcpy
उपयोग करना शुरू कर सकता है rep movsb
, जिससे बहुत सी शाखाएँ बच जाती हैं।
यूबी का पता लगाने के लिए उपकरण और असमान मूल्यों का उपयोग
Gcc और clang में, आप -fsanitize=undefined
रन-टाइम इंस्ट्रूमेंटेशन को जोड़ने के लिए संकलित कर सकते हैं जो रन-टाइम पर होने वाले UB पर चेतावनी या त्रुटि देगा। हालांकि, यह इकाईगत चर नहीं पकड़ेगा। (क्योंकि यह एक "असमान" बिट के लिए जगह बनाने के लिए प्रकार के आकार में वृद्धि नहीं करता है)।
Https://developers.redhat.com/blog/2014/10/16/gcc-undefined-behavior-sanitizer-ubsan/ देखें
एकतरफा डेटा का उपयोग खोजने के लिए, क्लैंग / एलएलवीएम में एड्रेस सेनिटाइज़र और मेमोरी सैनिटाइज़र है। https://github.com/google/sanitizers/wiki/MemorySanitizerclang -fsanitize=memory -fPIE -pie
अनइंस्टॉल किए गए वास्तविक छड़ों का पता लगाने के उदाहरण दिखाता है। यदि आप अनुकूलन के बिना संकलित करते हैं तो यह सबसे अच्छा काम कर सकता है , इसलिए चर के सभी पाठ वास्तव में asm में मेमोरी से लोड हो रहे हैं। वे दिखाते हैं कि इसका उपयोग -O2
ऐसे मामले में किया जा रहा है जहां लोड दूर नहीं होगा। मैंने खुद इसकी कोशिश नहीं की है। (कुछ मामलों में, उदाहरण के लिए, किसी सरणी को समेटने से पहले किसी संचायक को आरंभीकृत नहीं करना, clang -O3 कोड का उत्सर्जन करेगा, जो एक सदिश रजिस्टर में होता है, जो कभी भी आरंभिक नहीं होता है। इसलिए अनुकूलन के साथ, आपके पास एक ऐसा मामला हो सकता है, जिसमें UB से जुड़ी कोई मेमोरी रीड नहीं है। । परंतु-fsanitize=memory
उत्पन्न asm को बदलता है, और इसके लिए जाँच हो सकती है।]
यह असंबद्ध स्मृति की नकल को सहन करेगा, और इसके साथ सरल तर्क और अंकगणितीय संचालन भी करेगा। सामान्य तौर पर, MemorySanitizer चुपचाप एकतरफा मूल्य के आधार पर कोड ब्रांच (या नहीं लिया जाता) लेने पर मेमोरी में एकरहित डेटा के प्रसार को ट्रैक करता है, और एक चेतावनी की रिपोर्ट करता है।
MemorySanitizer, Valgrind (Memcheck टूल) में पाई गई कार्यक्षमता का सबसेट लागू करता है।
क्योंकि कॉल glibc को इस मामले के लिए काम करना चाहिए memcpy
के साथ एक length
गणना की अप्रारंभीकृत स्मृति से के आधार पर (पुस्तकालय के अंदर) एक शाखा में परिणाम होगा length
। यदि यह एक पूरी तरह से शाखाहीन संस्करण को इनलाइन करता था जो सिर्फ इस्तेमाल cmov
, इंडेक्सिंग और दो स्टोर करता था, तो यह काम नहीं कर सकता था।
memcheck
इस तरह की समस्या के लिए वाल्ग्रिंड की इच्छा भी होगी, फिर से शिकायत न करें कि क्या कार्यक्रम केवल अनधिकृत डेटा के आसपास कॉपी करता है। लेकिन यह कहता है कि यह पता चलेगा कि "कंडेनशनल जंप या मूव किसी भी बाहरी रूप से दिखने वाले व्यवहार को पकड़ने की कोशिश करता है, जो एकतरफा डेटा पर निर्भर करता है।"
शायद सिर्फ एक लोडिंग को फ्लैग न करने के पीछे का विचार यह है कि स्ट्रक्चर्स में पैडिंग हो सकती है, और वाइड वेक्टर लोड / स्टोर के साथ पूरे स्ट्रक्चर (पैडिंग सहित) को कॉपी करना एक त्रुटि नहीं है, भले ही व्यक्तिगत सदस्यों को केवल एक बार लिखा गया हो। एएसएम स्तर पर, क्या पैडिंग और क्या वास्तव में मूल्य का हिस्सा है के बारे में जानकारी खो गई है।