वैधता के लिए परीक्षण बिंदु (C / C ++)


91

क्या निर्धारित करने का कोई तरीका है (प्रोग्रामिक रूप से, निश्चित रूप से) यदि कोई दिया गया सूचक "वैध" है? NULL के लिए चेक करना आसान है, लेकिन 0x00001234 जैसी चीजों के बारे में क्या? जब इस तरह के पॉइंटर को रोकने की कोशिश की जाती है तो एक अपवाद / दुर्घटना होती है।

एक क्रॉस-प्लेटफ़ॉर्म विधि पसंद की जाती है, लेकिन प्लेटफ़ॉर्म-विशिष्ट (विंडोज और लिनक्स के लिए) भी ठीक है।

स्पष्टीकरण के लिए अद्यतन: समस्या बासी / मुक्त / असिंचित बिंदुओं के साथ नहीं है; इसके बजाय, मैं एक एपीआई लागू कर रहा हूं जो कॉलर से पॉइंटर्स लेता है (जैसे एक स्ट्रिंग के लिए पॉइंटर, एक फ़ाइल हैंडल, आदि)। कॉलर पॉइंटर के रूप में एक अमान्य मान (उद्देश्य या गलती से) भेज सकता है। मैं एक दुर्घटना को कैसे रोकूँ?



मुझे लगता है कि लिनक्स के लिए सबसे अच्छा सकारात्मक जवाब जॉर्ज कैरेट ने दिया है। यदि वह पर्याप्त नहीं है, तो लाइब्रेरी में फ़ंक्शन प्रतीक तालिका या अपने स्वयं के फ़ंक्शन तालिकाओं के साथ उपलब्ध पुस्तकालयों की तालिका का एक और स्तर बनाने पर विचार करें। फिर उन सटीक तालिकाओं के खिलाफ जांच करें। बेशक, वे नकारात्मक उत्तर भी सही हैं: आप वास्तव में 100% सुनिश्चित नहीं हो सकते हैं कि क्या कोई फ़ंक्शन पॉइंटर मान्य है या नहीं जब तक कि आप उपयोगकर्ता एप्लिकेशन पर कई अतिरिक्त प्रतिबंध नहीं लगाते हैं।
मिंगहुआ

क्या एपीआई विनिर्देश वास्तव में कार्यान्वयन द्वारा पूरा करने के लिए इस तरह के दायित्व को निर्दिष्ट करता है? वैसे, मुझे लगता है कि आप डेवलपर और डिज़ाइनर दोनों हैं, ऐसा नहीं माना जाता है। मेरा कहना है कि, मुझे नहीं लगता कि कोई एपीआई कुछ इस तरह निर्दिष्ट करेगा "एक अवैध सूचक के तर्क के रूप में पारित होने के कारण, फ़ंक्शन को समस्या को संभालना चाहिए और NULL लौटना चाहिए।" एक एपीआई एक उचित उपयोग की शर्तों के तहत एक सेवा प्रदान करने का दायित्व उठाता है, न कि हैक्स द्वारा। फिर भी, यह थोड़ा बेवकूफ होने का कोई नुकसान नहीं है। एक संदर्भ का उपयोग करने से ऐसे मामले कम फैलते हैं। :)
पोनारोस

जवाबों:


75

स्पष्टीकरण के लिए अद्यतन: समस्या बासी, मुक्त या गैर-व्यवस्थित पॉइंटर्स के साथ नहीं है; इसके बजाय, मैं एक एपीआई लागू कर रहा हूं जो कॉलर से पॉइंटर्स लेता है (जैसे एक स्ट्रिंग के लिए पॉइंटर, एक फ़ाइल हैंडल, आदि)। कॉलर पॉइंटर के रूप में एक अमान्य मान (उद्देश्य या गलती से) भेज सकता है। मैं एक दुर्घटना को कैसे रोकूँ?

आप वह जाँच नहीं कर सकते। कोई तरीका नहीं है कि आप जांच सकें कि कोई पॉइंटर "वैध" है या नहीं। आपको यह विश्वास करना होगा कि जब लोग एक फ़ंक्शन का उपयोग करते हैं जो एक पॉइंटर लेता है, तो उन लोगों को पता होता है कि वे क्या कर रहे हैं। यदि वे आपको 0x4211 एक सूचक मान के रूप में पास करते हैं, तो आपको 0x4211 पते के बिंदुओं पर भरोसा करना होगा। और अगर वे "गलती से" एक वस्तु को मारते हैं, तो भले ही आप कुछ डरावने ऑपरेशन सिस्टम फ़ंक्शन (IsValidPtr या जो भी) का उपयोग करेंगे, आप अभी भी एक बग में फिसल जाएंगे और तेजी से विफल नहीं होंगे।

इस तरह के संकेत देने के लिए अशक्त बिंदुओं का उपयोग करना शुरू करें और अपने पुस्तकालय के उपयोगकर्ता को बताएं कि यदि वे गलती से अमान्य बिंदुओं को गंभीरता से पारित कर देते हैं, तो उन्हें संकेत का उपयोग नहीं करना चाहिए :)


यह शायद सही उत्तर है, लेकिन मुझे लगता है कि एक साधारण फ़ंक्शन जो सामान्य हेक्सस्पीक मेमोरी स्थानों की जांच करता है, सामान्य डीबगिंग के लिए उपयोगी होगा ... अभी मुझे एक पॉइंटर मिला है जो कभी-कभी 0xfeeefeee को इंगित करता है और अगर मेरे पास एक सरल फ़ंक्शन है जो मैं कर सकता था काली मिर्च का उपयोग करते हुए चारों ओर मुखर यह अपराधी को खोजने के लिए बहुत आसान बना देगा ... संपादित करें: हालांकि यह मुश्किल नहीं होगा कि मैं खुद को एक अनुमान
लगाऊं

@ मुद्दा यह है कि कुछ C और C ++ कोड बिना किसी अवैध पते पर सूचक अंकगणित कर सकते हैं (कचरा-इन, कचरा-आउट सिद्धांत के आधार पर) और इस तरह से "अंकगणितीय रूप से संशोधित" सूचक में से गुजरेंगे। -अज्ञात अवैध पते सामान्य मामलों में अमान्य वस्तु पते या किसी गलत प्रकार के आधार पर गैर-मौजूद व्यवहार्यता से एक विधि की तलाश की जा रही है, या केवल एक पॉइंटर से एक संरचना तक फ़ील्ड को पढ़ना जो किसी को इंगित नहीं करता है।
२१

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

34

यहां लिनक्स के तहत सी प्रोग्राम के लिए तीन आसान तरीके हैं जो उस मेमोरी की स्थिति के बारे में आत्मनिरीक्षण कर सकते हैं जिसमें वह चल रहा है, और क्यों प्रश्न का संदर्भ कुछ संदर्भों में उपयुक्त परिष्कृत है।

  1. Getpagesize () को कॉल करने और पॉइंटर को एक पेज की सीमा पर राउंड करने के बाद, आप यह पता लगाने के लिए कि क्या कोई पेज वैध है और क्या यह काम करने वाले सेट के भाग का हिस्सा होता है, के लिए mincore () कॉल कर सकता है। ध्यान दें कि इसके लिए कुछ कर्नेल संसाधनों की आवश्यकता होती है, इसलिए आपको इसे बेंचमार्क करना चाहिए और यह निर्धारित करना चाहिए कि क्या यह फ़ंक्शन आपके एपी में वास्तव में उपयुक्त है। यदि आपकी एपीआई इंटरप्ट को संभालने जा रही है, या सीरियल पोर्ट से मेमोरी में पढ़ रही है, तो अप्रत्याशित व्यवहार से बचने के लिए इसे कॉल करना उचित है।
  2. स्टेट / कॉल करने के बाद यह निर्धारित करने के लिए कि क्या कोई / प्रोक / सेल्फ डायरेक्टरी उपलब्ध है, आप उस क्षेत्र के बारे में जानकारी प्राप्त करने के लिए / प्रॉप / सेल्फ / मैप्स के माध्यम से उसे खोल और पढ़ सकते हैं जिसमें एक पॉइंटर रहता है। खरीद के लिए मैन पेज का अध्ययन करें, प्रक्रिया की जानकारी छद्म फाइल सिस्टम। स्पष्ट रूप से यह अपेक्षाकृत महंगा है, लेकिन आप पार्स के परिणाम को एक सरणी में कैशिंग के साथ दूर करने में सक्षम हो सकते हैं जिसे आप बाइनरी खोज का उपयोग करके कुशलता से देख सकते हैं। / Proc / self / smaps पर भी विचार करें। यदि आपकी एपीआई उच्च-प्रदर्शन कंप्यूटिंग के लिए है, तो प्रोग्राम / proc / self / numa के बारे में जानना चाहेगा, जो गैर-समान मेमोरी आर्किटेक्चर के लिए मैन पेज के अंतर्गत प्रलेखित है।
  3. Get_mempolicy (MPOL_F_ADDR) कॉल उच्च प्रदर्शन कंप्यूटिंग एपी कार्य के लिए उपयुक्त है, जहां निष्पादन के कई सूत्र हैं और आप गैर-समान मेमोरी के लिए आत्मीयता के लिए अपने काम का प्रबंधन कर रहे हैं क्योंकि यह सीपीयू कोर और सॉकेट संसाधनों से संबंधित है। इस तरह की एपि निश्चित रूप से आपको यह भी बताएगी कि क्या कोई सूचक वैध है।

Microsoft Windows के अंतर्गत फ़ंक्शन QueryWorkingSetEx है जो प्रक्रिया स्थिति API (NUMP API में भी) के तहत प्रलेखित है। परिष्कृत NUMA API प्रोग्रामिंग के लिए एक कोरोलरी के रूप में यह फ़ंक्शन आपको वैधता (C / C ++) कार्य के लिए सरल "परीक्षण बिंदुओं" को करने देगा, क्योंकि यह कम से कम 15 वर्षों के लिए पदावनत होने की संभावना नहीं है।


13
पहला उत्तर जो स्वयं प्रश्न के बारे में नैतिक होने का प्रयास नहीं करता है और वास्तव में इसका पूरी तरह से उत्तर देता है। लोगों को कभी-कभी यह एहसास नहीं होता है कि किसी व्यक्ति को इस तरह के डिबगिंग दृष्टिकोण की आवश्यकता है, जैसे कि 3rd पार्टी लाइब्रेरी या विरासत कोड में बग ढूंढने के लिए क्योंकि यहां तक ​​कि वेलग्रिंड केवल जंगली पॉइंटर्स ढूंढता है जब वास्तव में उन तक पहुंच हो, उदाहरण के लिए यदि आप नियमित रूप से वैधता के लिए पॉइंटर्स जांचना चाहते हैं एक कैश तालिका में जो आपके कोड में किसी अन्य स्थान से अधिलेखित की गई है ...
lumpidu

यह स्वीकृत उत्तर होना चाहिए। मैंने इसे नॉन-लाइनक्स प्लेटफॉर्म पर सिमलीली किया। मूल रूप से यह प्रक्रिया की जानकारी को ही प्रक्रिया में उजागर कर रहा है। इस पहलू के साथ, यह दिखता है कि विंडोज़ प्रक्रिया की स्थिति एपीआई के माध्यम से अधिक सार्थक जानकारी को उजागर करके लिनक्स की तुलना में बेहतर काम करती है।
मिन्हुआ

31

एक अवैध पॉइंटर में कॉल करने वाले द्वारा भेजे गए क्रैश को रोकना, मूक कीड़े बनाने का एक अच्छा तरीका है जिसे खोजना मुश्किल है।

क्या प्रोग्रामर के लिए अपने एपीआई का उपयोग करके यह स्पष्ट संदेश प्राप्त करना बेहतर है कि उसका कोड उसे छिपाने के बजाय दुर्घटनाग्रस्त करके फर्जी है?


8
हालांकि कुछ मामलों में, एपीआई खराब होने पर तुरंत खराब पॉइंटर की जांच करना कि आप कैसे जल्दी असफल होते हैं। उदाहरण के लिए, क्या होगा यदि एपीआई एक डेटा संरचना में पॉइंटर को संग्रहीत करता है जहां यह केवल बाद में स्थगित हो जाएगा? तब एपीआई को खराब पॉइंटर पास करने से कुछ यादृच्छिक बाद के बिंदु पर दुर्घटना हो जाएगी। उस स्थिति में, एपीआई कॉल पर, जहां खराब मूल्य मूल रूप से पेश किया गया था, जल्द ही विफल होना बेहतर होगा।
पीटरफर्नन

28

Win32 / 64 पर ऐसा करने का एक तरीका है। सूचक को पढ़ने और परिणामी SEH अपवाद को पकड़ने का प्रयास करें जो विफलता पर फेंक दिया जाएगा। यदि यह फेंकता नहीं है, तो यह एक वैध सूचक है।

इस पद्धति के साथ समस्या यह है कि यह सिर्फ रिटर्न देता है या नहीं आप सूचक से डेटा पढ़ सकते हैं। यह प्रकार की सुरक्षा या किसी अन्य आक्रमणकारी के बारे में कोई गारंटी नहीं देता है। सामान्य तौर पर यह विधि "हाँ, मैं उस विशेष स्थान को उस समय पढ़ सकता हूं, जो अब बीत चुका है" कहने के अलावा किसी और चीज़ के लिए अच्छा है।

संक्षेप में, यह मत करो;)

रेमंड चेन का इस विषय पर एक ब्लॉग पोस्ट है: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx


3
@Tim, C ++ में ऐसा करने का कोई तरीका नहीं है।
JaredPar

6
यदि आप "वैध पॉइंटर" को परिभाषित करते हैं तो यह केवल "सही उत्तर" है क्योंकि यह "एक्सेस उल्लंघन / सेगफॉल्ट" का कारण नहीं बनता है। मैं इसे "आपके द्वारा उपयोग किए जा रहे उद्देश्य के लिए आवंटित सार्थक डेटा के बिंदु" के रूप में परिभाषित करना पसंद करूंगा। मैं बहस चाहते हैं कि सूचक वैधता का एक बेहतर परिभाषा है ...;)
jalf

यहां तक ​​कि अगर सूचक वैध है तो इस तरह से जाँच नहीं की जा सकती। थ्रेड 1 () {.. if (IsValidPtr (p)) * p = 7 के बारे में सोचो; ...} थ्रेड 2 () {नींद (1); हटाएं p; ...}
क्रिस्टोफर

2
@ क्रिस्टोफर, बहुत सही। मुझे कहना चाहिए "मैं एक समय में उस विशेष स्थान को स्मृति में पढ़ सकता हूं जो अब बीत चुका है"
जारेपियर

@JaredPar: वास्तव में बुरा सुझाव। एक गार्ड-पेज को ट्रिगर कर सकते हैं, इसलिए बाद में स्टैक का विस्तार नहीं किया जाएगा या कुछ समान रूप से अच्छा होगा।
Deduplicator

16

AFAIK कोई रास्ता नहीं है। आपको स्मृति को मुक्त करने के बाद NULL को हमेशा पॉइंटर्स सेट करके इस स्थिति से बचने का प्रयास करना चाहिए।


4
अशक्त करने के लिए एक पॉइंटर सेट करना आपको कुछ नहीं देता है, सिवाय शायद सुरक्षा की झूठी भावना के।

वह सत्य नहीं है। विशेष रूप से सी ++ में आप यह निर्धारित कर सकते हैं कि क्या सदस्य वस्तुओं को अशक्त करने के लिए हटा दिया जाए। यह भी ध्यान दें कि, C ++ में, यह शून्य-बिंदुओं को हटाने के लिए मान्य है, इसलिए बिना किसी चीज के विनाशकारी वस्तुओं को हटाना लोकप्रिय है।
फर्डिनेंड बेयर

4
int * p = नया int (0); int * P2 = p; हटाएं p; p = NULL; P2 को हटा दें; // दुर्घटना

1
zabzonk, और ?? उन्होंने कहा कि आप एक अशक्त सूचक को हटा सकते हैं। P2 एक अशक्त सूचक नहीं है, लेकिन एक अमान्य सूचक है। आपको इसे पहले खाली करने के लिए सेट करना होगा।
जोहान्स शाउब - १५'०

2
यदि आपके पास इंगित करने के लिए उपनाम हैं, तो उनमें से केवल एक ही नल को सेट किया जाएगा, अन्य उपनाम चारों ओर लटक रहे हैं।
जद्दन

7

इस और इस सवाल पर एक नज़र । स्मार्ट पॉइंटर्स पर भी नज़र डालें ।


7

इस सूत्र में उत्तर के बारे में थोड़ा बताएं:

Windows के लिए IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr ()।

मेरी सलाह है कि उनसे दूर रहें, किसी ने पहले ही यह पोस्ट कर दिया है: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

एक ही विषय पर और उसी लेखक द्वारा एक और पोस्ट (मुझे लगता है) यह एक है: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx ("IsBadXxxPtr वास्तव में CrashProgramRandomly कहा जाता है" ")।

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


शायद एक और तरीका है _CrtIsValidHeapPointer का उपयोग करना । यह फ़ंक्शन TRUE लौटाएगा यदि पॉइंटर मान्य है, और पॉइंटर मुक्त होने पर अपवाद फेंकें। जैसा कि प्रलेखित है, यह फ़ंक्शन केवल डिबग CRT में उपलब्ध है।
15:01 बजे किंग नोव

6

सबसे पहले, मैं खुद को कॉल करने वाले से जानबूझकर दुर्घटना का कारण बनने से बचाने की कोशिश करने का कोई मतलब नहीं देखता। वे स्वयं एक अमान्य सूचक के माध्यम से पहुंचने का प्रयास करके आसानी से ऐसा कर सकते थे। कई अन्य तरीके हैं - वे सिर्फ आपकी मेमोरी या स्टैक को अधिलेखित कर सकते हैं। यदि आपको इस तरह की चीज़ से बचाने की ज़रूरत है, तो आपको संचार के लिए सॉकेट या किसी अन्य आईपीसी का उपयोग करके एक अलग प्रक्रिया में चलने की आवश्यकता है।

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

हम प्रदर्शन / थ्रूपुट आवश्यकताओं और भरोसेमंदता के आधार पर कई विभिन्न तरीकों का उपयोग करते हैं। सबसे पसंदीदा में से:

  • सॉकेट (अक्सर पाठ के रूप में डेटा पास करना) का उपयोग करके अलग-अलग प्रक्रियाएं।

  • साझा मेमोरी का उपयोग करके अलग-अलग प्रक्रियाएं (यदि बड़ी मात्रा में डेटा पास करने के लिए)।

  • एक ही प्रक्रिया संदेश कतार के माध्यम से अलग धागे (यदि लगातार छोटे संदेश)।

  • एक ही प्रक्रिया अलग थ्रेड सभी पास एक स्मृति पूल से आवंटित डेटा पारित कर दिया।

  • प्रत्यक्ष प्रक्रिया कॉल के माध्यम से एक ही प्रक्रिया - एक मेमोरी पूल से आवंटित सभी पारित डेटा।

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

एक मेमोरी पूल का उपयोग ज्यादातर परिस्थितियों में काफी आसान है और अक्षम नहीं होना चाहिए। यदि आप पहली बार में डेटा आवंटित करते हैं, तो आपके द्वारा आवंटित मूल्यों के खिलाफ पॉइंटर्स की जांच करना तुच्छ है। आप मान्य डेटा प्रकार और डेटा ओवररन की जांच करने के लिए डेटा से पहले और बाद में आवंटित लंबाई को स्टोर कर सकते हैं और "जादू" मान जोड़ सकते हैं।


5

यूनिक्स पर आपको कर्नेल syscall का उपयोग करने में सक्षम होना चाहिए जो सूचक की जाँच करता है और EFAULT लौटाता है, जैसे:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdbool.h>

bool isPointerBad( void * p )
{
   int fh = open( p, 0, 0 );
   int e = errno;

   if ( -1 == fh && e == EFAULT )
   {
      printf( "bad pointer: %p\n", p );
      return true;
   }
   else if ( fh != -1 )
   {
      close( fh );
   }

   printf( "good pointer: %p\n", p );
   return false;
}

int main()
{
   int good = 4;
   isPointerBad( (void *)3 );
   isPointerBad( &good );
   isPointerBad( "/tmp/blah" );

   return 0;
}

लौटने:

bad pointer: 0x3
good pointer: 0x7fff375fd49c
good pointer: 0x400793

खुले () [शायद पहुँच] की तुलना में उपयोग करने के लिए शायद एक बेहतर syscall है, क्योंकि वहाँ एक मौका है कि यह वास्तविक फ़ाइल निर्माण कोडपथ, और बाद की करीबी आवश्यकता हो सकती है।


1
यह एक शानदार हैक है। मुझे मेमोरी पर्वतमाला को मान्य करने के लिए अलग-अलग syscalls पर सलाह देखना पसंद होगा, खासकर अगर उन्हें साइड इफेक्ट न होने की गारंटी दी जा सकती है। यदि आप पढ़ने योग्य मेमोरी में बफ़र्स हैं, तो परीक्षण करने के लिए / dev / null को लिखने के लिए आप एक फ़ाइल डिस्क्रिप्टर को खुला रख सकते हैं, लेकिन संभवतः सरल समाधान हैं। सबसे अच्छा मैं पा सकता हूँ सहानुभूति (ptr, "") जो एक गलत पते पर 14 या 2 को एक अच्छे पते पर सेट करेगा, लेकिन कर्नेल परिवर्तन सत्यापन के आदेश को स्वैप कर सकता है।
प्रेस्टन

1
@Preston DB2 में मुझे लगता है कि हम unistd.h की पहुंच () का उपयोग करते थे। मैंने ऊपर खुला () का उपयोग किया है क्योंकि यह थोड़ा कम अस्पष्ट है, लेकिन आप शायद सही हैं कि उपयोग करने के लिए बहुत सारे संभावित सिस्कोल्स हैं। विंडोज में एक स्पष्ट पॉइंटर चेक एपीआई होता था, लेकिन यह थ्रेड सेफ नहीं होता था (मुझे लगता है कि यह एसईएच का उपयोग करके लिखने और फिर मेमोरी रेंज की सीमा को बहाल करने के लिए उपयोग किया जाता है।)
पेटर जूट

4

मुझे आपके प्रश्न के साथ बहुत सहानुभूति मिली है, क्योंकि मैं स्वयं लगभग समान स्थिति में हूं। मैं सराहना करता हूं कि बहुत सारे उत्तर क्या कह रहे हैं, और वे सही हैं - पॉइंटर की आपूर्ति करने वाली दिनचर्या को एक वैध पॉइंटर प्रदान करना चाहिए। मेरे मामले में, यह लगभग असंभव है कि वे सूचक को दूषित कर सकते थे - लेकिन अगर उनके पास था कामयाब रहे, यह मेरी सॉफ्टवेयर होगा कि क्रैश, और मुझे लगता है कि दोष मिलेगा :-(

मेरी आवश्यकता यह नहीं है कि मैं एक विभाजन दोष के बाद जारी रखता हूं - यह खतरनाक होगा - मैं केवल यह रिपोर्ट करना चाहता हूं कि समाप्त होने से पहले ग्राहक के साथ क्या हुआ ताकि वे मुझे दोष देने के बजाय अपने कोड को ठीक कर सकें!

यह मैंने इसे (विंडोज पर) करने के लिए कैसे पाया है: http://www.cplusplus.com/reference/clibrary/csignal/signel/

एक सारांश देने के लिए:

#include <signal.h>

using namespace std;

void terminate(int param)
/// Function executed if a segmentation fault is encountered during the cast to an instance.
{
  cerr << "\nThe function received a corrupted reference - please check the user-supplied  dll.\n";
  cerr << "Terminating program...\n";
  exit(1);
}

...
void MyFunction()
{
    void (*previous_sigsegv_function)(int);
    previous_sigsegv_function = signal(SIGSEGV, terminate);

    <-- insert risky stuff here -->

    signal(SIGSEGV, previous_sigsegv_function);
}

अब यह व्यवहार करने के लिए प्रकट होता है जैसा कि मुझे आशा है कि (यह त्रुटि संदेश को प्रिंट करता है, फिर प्रोग्राम को समाप्त कर देता है) - लेकिन अगर कोई गलती कर सकता है, तो कृपया मुझे बताएं!


उपयोग न करें exit(), यह RAII को दरकिनार करता है और इस प्रकार संसाधन लीक हो सकता है।
सेबेस्टियन मच

दिलचस्प है - क्या इस स्थिति में बड़े करीने से समाप्त करने का एक और तरीका है? और क्या एग्जिट स्टेटमेंट केवल इस तरह से इसे करने में समस्या है? मुझे लगता है कि मैंने "-1" प्राप्त कर लिया है - क्या यह केवल 'बाहर निकलने' के कारण है?
माइक सैडलर

ओह, मुझे पता है कि यह एक असाधारण स्थिति के लिए है। मैंने अभी देखा exit()और मेरा पोर्टेबल सी ++ अलार्म बेल बजने लगा। यह लिनक्स विशिष्ट स्थिति में ठीक होना चाहिए, जहां आपका कार्यक्रम वैसे भी बाहर निकल जाएगा, शोर के लिए क्षमा करें।
सेबेस्टियन मच

1
संकेत (2) पोर्टेबल नहीं है। सिगनेशन (2) का प्रयोग करें। man 2 signalलिनक्स पर एक पैराग्राफ है जो यह बताता है कि क्यों।
rptb1

1
इस स्थिति में मैं आमतौर पर एग्जिट (3) को एग्जिट (3) नहीं कहूंगा क्योंकि यह किसी तरह के डिबगिंग बैकट्रेस का उत्पादन करने की अधिक संभावना है जिसका उपयोग आप समस्या पोस्टमार्टम का निदान करने के लिए कर सकते हैं। अधिकांश यूनिक्स पर, एबॉर्ट (3) कोर डंप करेगा (यदि कोर डंप की अनुमति है) और विंडोज पर यह स्थापित होने पर डिबगर लॉन्च करने की पेशकश करेगा।
rptb1

2

एक सामान्य मामले के रूप में एक पॉइंटर की वैधता के लिए परीक्षण करने के लिए सी ++ में कोई प्रावधान नहीं हैं। कोई स्पष्ट रूप से यह मान सकता है कि NULL (0x00000000) खराब है, और विभिन्न कंपाइलर और लाइब्रेरीज़ यहां "विशेष मान" का उपयोग करना पसंद करते हैं और डिबगिंग को आसान बनाने के लिए (उदाहरण के लिए, अगर मुझे कभी कोई सूचक दृश्य स्टूडियो में 0xCECECECE के रूप में दिखाई देता है तो मुझे पता है) मैंने कुछ गलत किया है) लेकिन सच्चाई यह है कि चूंकि एक पॉइंटर केवल मेमोरी में एक इंडेक्स है, इसलिए पॉइंटर को देखकर यह बताना असंभव है कि क्या यह "राइट" इंडेक्स है।

विभिन्न ट्रिक्स हैं जो आप डायनेमिक_कास्ट और आरटीटीआई के साथ कर सकते हैं जैसे कि यह सुनिश्चित करना कि ऑब्जेक्ट उस प्रकार का है जो आप चाहते हैं, लेकिन उन्हें सभी की आवश्यकता है कि आप पहली बार में मान्य किसी चीज़ की ओर इशारा कर रहे हैं।

यदि आप यह सुनिश्चित करना चाहते हैं कि आप प्रोग्राम "अमान्य" पॉइंटर्स का पता लगा सकते हैं तो मेरी सलाह यह है: प्रत्येक पॉइंटर को सेट करें जिसे आप या तो NULL को घोषित करते हैं या सृजन के तुरंत बाद एक वैध पते पर और उस मेमोरी को मुक्त करने के तुरंत बाद इसे NULL को सेट कर देते हैं। यदि आप इस अभ्यास के बारे में मेहनती हैं, तो NULL की जाँच करना आप सभी की आवश्यकता है।


C ++ (या C, उस मामले के लिए) में एक अशक्त सूचक स्थिरांक एक निरंतर अभिन्न शून्य द्वारा दर्शाया गया है। कार्यान्वयन के बहुत सारे बाइनरी-शून्य का उपयोग करते हैं इसका प्रतिनिधित्व करने के लिए, लेकिन यह कुछ गिनने के लिए नहीं है।
डेविड थॉर्नले

2

ऐसा करने का कोई पोर्टेबल तरीका नहीं है, और इसे विशिष्ट प्लेटफार्मों के लिए करना कठिन और असंभव के बीच कहीं भी हो सकता है। किसी भी स्थिति में, आपको कभी भी ऐसा कोड नहीं लिखना चाहिए जो इस तरह के चेक पर निर्भर करता है - पहली जगह पर अमान्य मानों को इंगित न करने दें।


2

उपयोग करने से पहले और बाद में NULL को सूचक सेट करना एक अच्छी तकनीक है। C ++ में ऐसा करना आसान है यदि आप उदाहरण के लिए एक वर्ग के भीतर संकेत का प्रबंधन करते हैं (एक स्ट्रिंग):

class SomeClass
{
public:
    SomeClass();
    ~SomeClass();

    void SetText( const char *text);
    char *GetText() const { return MyText; }
    void Clear();

private:
    char * MyText;
};


SomeClass::SomeClass()
{
    MyText = NULL;
}


SomeClass::~SomeClass()
{
    Clear();
}

void SomeClass::Clear()
{
    if (MyText)
        free( MyText);

    MyText = NULL;
}



void SomeClass::Settext( const char *text)
{
    Clear();

    MyText = malloc( strlen(text));

    if (MyText)
        strcpy( MyText, text);
}

अपडेट किया गया प्रश्न निश्चित रूप से मेरे उत्तर को गलत बनाता है (या किसी अन्य प्रश्न का उत्तर कम से कम)। मैं उन उत्तरों से सहमत हूं जो मूल रूप से कहते हैं, अगर वे वें आपी को गाली देते हैं तो उन्हें दुर्घटनाग्रस्त होने दें आप अपने आप को अंगूठे से हथौड़े से मारना बंद नहीं कर सकते ...
टिम रिंग

2

सार्वजनिक एपीआई में इनपुट मापदंडों के रूप में मनमाने ढंग से बिंदुओं को स्वीकार करना बहुत अच्छी नीति नहीं है। "सादे डेटा" प्रकार पूर्णांक, एक स्ट्रिंग या एक संरचना की तरह होना बेहतर है (मेरा मतलब सादे डेटा के साथ एक शास्त्रीय संरचना है, निश्चित रूप से; आधिकारिक तौर पर कुछ भी एक संरचना हो सकती है)।

क्यों? ठीक है क्योंकि जैसा कि अन्य कहते हैं कि यह जानने के लिए कोई मानक तरीका नहीं है कि क्या आपको एक वैध सूचक दिया गया है या एक जो रद्दी को इंगित करता है।

लेकिन कभी-कभी आपके पास विकल्प नहीं होता है - आपके एपीआई को एक पॉइंटर स्वीकार करना चाहिए।

इन मामलों में, कॉल करने वाले का कर्तव्य है कि वह एक अच्छे पॉइंटर को पास करे। NULL को मान के रूप में स्वीकार किया जा सकता है, लेकिन रद्दी के लिए पॉइंटर नहीं।

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

// API that does not allow NULL
void PublicApiFunction1(Person* in_person)
{
  assert(in_person != NULL);
  assert(in_person->Invariant());

  // Actual code...
}

// API that allows NULL
void PublicApiFunction2(Person* in_person)
{
  assert(in_person == NULL || in_person->Invariant());

  // Actual code (must keep in mind that in_person may be NULL)
}

पुन: "एक सादा डेटा प्रकार पास करें ... एक स्ट्रिंग की तरह" लेकिन C ++ में स्ट्रिंग को अक्सर वर्ण (चार *) या (कॉन्स्ट चार *) के संकेत के रूप में पारित किया जाता है, इसलिए आप पासिंग पॉइंटर्स पर वापस जाते हैं। और आपका उदाहरण एक संदर्भ के रूप में in_person को पारित करता है, न कि एक संकेतक के रूप में, इसलिए तुलना (in_person! = NULL) का तात्पर्य है कि व्यक्ति वर्ग में परिभाषित कुछ वस्तु / सूचक तुलना है।
जेसी चिशोल्म

@JesseChisholm स्ट्रिंग से मेरा मतलब एक स्ट्रिंग, यानी एक std :: string है। किसी भी तरह से मैं तार को स्टोर करने या उन्हें पास करने के तरीके के रूप में चार * का उपयोग करने की सिफारिश कर रहा हूं। ऐसा मत करो।
डैनियल डारनास

@JesseChisholm किसी कारण से, मैंने पांच साल पहले इस प्रश्न का उत्तर देने में गलती की थी। स्पष्ट रूप से, यह जांचने का कोई मतलब नहीं है कि कोई व्यक्ति और पूर्ण है या नहीं। यह भी संकलन नहीं होगा। मैं संकेत का उपयोग करने के लिए था, संदर्भ नहीं। मैंने अब इसे ठीक कर दिया।
डैनियल डर्नाज़

1

जैसा कि दूसरों ने कहा है, आप एक अवैध सूचक का मज़बूती से पता नहीं लगा सकते। अमान्य पॉइंटर के कुछ रूपों पर विचार करें:

आप एक शून्य सूचक हो सकता है। यह एक है जिसे आप आसानी से जांच सकते हैं और इसके बारे में कुछ कर सकते हैं।

आपके पास मान्य मेमोरी के बाहर कहीं पर एक सूचक हो सकता है। आपके सिस्टम के रन-टाइम वातावरण को पता स्थान सेट करने के तरीके के आधार पर मान्य मेमोरी का गठन होता है। यूनिक्स प्रणालियों पर, यह आमतौर पर एक वर्चुअल एड्रेस स्पेस होता है जो 0 से शुरू होता है और कुछ बड़ी संख्या में मेगाबाइट पर जाता है। एम्बेडेड सिस्टम पर, यह काफी छोटा हो सकता है। यह 0 से शुरू नहीं हो सकता है, किसी भी मामले में। यदि आपका ऐप पर्यवेक्षक मोड या समकक्ष में चल रहा है, तो आपका पॉइंटर एक वास्तविक पते का संदर्भ दे सकता है, जो वास्तविक मेमोरी के साथ बैकअप ले भी सकता है और नहीं भी।

आप अपने डेटा सेगमेंट, bss, स्टैक या हीप के अंदर भी अपनी वैध मेमोरी के अंदर कहीं और एक पॉइंटर रख सकते हैं, लेकिन एक वैध ऑब्जेक्ट की ओर इशारा नहीं करते। इसका एक प्रकार एक सूचक है जो किसी वस्तु के खराब होने से पहले एक वैध वस्तु को इंगित करता था। इस संदर्भ में खराब चीजों में डीलक्लोकेशन, मेमोरी भ्रष्टाचार या पॉइंटर भ्रष्टाचार शामिल हैं।

आपके पास एक फ्लैट-आउट अवैध सूचक हो सकता है, जैसे कि संदर्भित होने वाली चीज़ के लिए अवैध संरेखण के साथ एक सूचक।

समस्या तब और भी बदतर हो जाती है जब आप सेगमेंट / ऑफसेट आधारित आर्किटेक्चर और अन्य अजीब सूचक कार्यान्वयन पर विचार करते हैं। इस प्रकार की चीज़ सामान्य रूप से डेवलपर से अच्छे संकलक और प्रकार के विवेकपूर्ण उपयोग से छिपाई जाती है, लेकिन यदि आप घूंघट को छेदना चाहते हैं और ऑपरेटिंग सिस्टम और संकलक डेवलपर्स को बाहर करने का प्रयास करते हैं, तो आप कर सकते हैं, लेकिन एक सामान्य तरीका नहीं है ऐसा करने के लिए जो आपके द्वारा चलाए जा रहे सभी मुद्दों को संभाल लेंगे।

सबसे अच्छी बात यह है कि आप दुर्घटना की अनुमति दे सकते हैं और कुछ अच्छी नैदानिक ​​जानकारी डाल सकते हैं।


पुन: "कुछ अच्छी नैदानिक ​​जानकारी बाहर रखें", रगड़ है। चूंकि आप पॉइंटर वैधता की जांच नहीं कर सकते हैं, इसलिए आपको जिस जानकारी के लिए उपद्रव करना है वह न्यूनतम है। "यहां एक अपवाद हुआ," आप सभी हो सकते हैं। संपूर्ण कॉल स्टैक अच्छा है, लेकिन अधिकांश C ++ रन टाइम लाइब्रेरी प्रदान करने से बेहतर ढांचे की आवश्यकता होती है।
जेसी चिशोल्म


1

सामान्य तौर पर, ऐसा करना असंभव है। यहाँ एक विशेष रूप से बुरा मामला है:

struct Point2d {
    int x;
    int y;
};

struct Point3d {
    int x;
    int y;
    int z;
};

void dump(Point3 *p)
{
    printf("[%d %d %d]\n", p->x, p->y, p->z);
}

Point2d points[2] = { {0, 1}, {2, 3} };
Point3d *p3 = reinterpret_cast<Point3d *>(&points[0]);
dump(p3);

कई प्लेटफार्मों पर, यह प्रिंट आउट होगा:

[0 1 2]

आप रनटाइम सिस्टम को मेमोरी के बिट्स की गलत व्याख्या करने के लिए मजबूर कर रहे हैं, लेकिन इस मामले में यह क्रैश नहीं होने वाला है, क्योंकि बिट्स सभी समझ में आते हैं। यह (के साथ सी-शैली बहुरूपता पर नज़र भाषा के डिजाइन का हिस्सा है struct inaddr, inaddr_in, inaddr_in6,) ताकि आप मज़बूती से किसी भी मंच पर यह के खिलाफ की रक्षा नहीं कर सकता।


1

यह अविश्वसनीय है कि आप ऊपर दिए गए लेखों में कितनी भ्रामक जानकारी पढ़ सकते हैं ...

और यहां तक ​​कि Microsoft msdn प्रलेखन में IsBadPtr को प्रतिबंधित करने का दावा किया गया है। ओह अच्छी तरह से - मैं दुर्घटनाग्रस्त होने के बजाय काम के आवेदन को प्राथमिकता देता हूं। भले ही टर्म वर्किंग गलत तरीके से काम कर रहा हो (जब तक एंड-यूज़र एप्लिकेशन के साथ जारी रह सकता है)।

Googling द्वारा मुझे विंडोज़ के लिए कोई उपयोगी उदाहरण नहीं मिला - 32-बिट ऐप्स के लिए एक समाधान मिला,

http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsystem%2Fdetect-driver%2F%2FDetectDriverSrc.zip&zep=DetectDriverSrc%2FDetectDriver%2Fsrc%2FdrvCppLib%2Frtti.cpp&obid=58895&obtid=2&ovid = 2

लेकिन मुझे 64-बिट ऐप्स का समर्थन करने की भी आवश्यकता है, इसलिए यह समाधान मेरे लिए काम नहीं करता है।

लेकिन मैंने वाइन के स्रोत कोडों को काटा है, और इसी तरह के कोड को पकाने में कामयाब रहा जो 64-बिट ऐप्स के लिए भी काम करेगा - कोड कोड संलग्न करें:

#include <typeinfo.h>   

typedef void (*v_table_ptr)();   

typedef struct _cpp_object   
{   
    v_table_ptr*    vtable;   
} cpp_object;   



#ifndef _WIN64
typedef struct _rtti_object_locator
{
    unsigned int signature;
    int base_class_offset;
    unsigned int flags;
    const type_info *type_descriptor;
    //const rtti_object_hierarchy *type_hierarchy;
} rtti_object_locator;
#else

typedef struct
{
    unsigned int signature;
    int base_class_offset;
    unsigned int flags;
    unsigned int type_descriptor;
    unsigned int type_hierarchy;
    unsigned int object_locator;
} rtti_object_locator;  

#endif

/* Get type info from an object (internal) */  
static const rtti_object_locator* RTTI_GetObjectLocator(void* inptr)  
{   
    cpp_object* cppobj = (cpp_object*) inptr;  
    const rtti_object_locator* obj_locator = 0;   

    if (!IsBadReadPtr(cppobj, sizeof(void*)) &&   
        !IsBadReadPtr(cppobj->vtable - 1, sizeof(void*)) &&   
        !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator)))  
    {  
        obj_locator = (rtti_object_locator*) cppobj->vtable[-1];  
    }  

    return obj_locator;  
}  

और निम्न कोड यह पता लगा सकता है कि सूचक वैध है या नहीं, आपको कुछ NULL चेकिंग जोड़ने की आवश्यकता है:

    CTest* t = new CTest();
    //t = (CTest*) 0;
    //t = (CTest*) 0x12345678;

    const rtti_object_locator* ptr = RTTI_GetObjectLocator(t);  

#ifdef _WIN64
    char *base = ptr->signature == 0 ? (char*)RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator;
    const type_info *td = (const type_info*)(base + ptr->type_descriptor);
#else
    const type_info *td = ptr->type_descriptor;
#endif
    const char* n =td->name();

इसे पॉइंटर से क्लास का नाम मिलता है - मुझे लगता है कि यह आपकी आवश्यकताओं के लिए पर्याप्त होना चाहिए।

एक बात जो मुझे अभी भी डर रही है वह है पॉइंटर चेकिंग का प्रदर्शन - ऊपर कोड स्निपेट में पहले से ही 3-4 एपीआई कॉल किए जा रहे हैं - समय के लिए महत्वपूर्ण अनुप्रयोगों के लिए ओवरकिल हो सकता है।

अच्छा होगा अगर कोई उदाहरण के लिए C # / प्रबंधित c ++ कॉल की तुलना में पॉइंटर चेकिंग के ओवरहेड को माप सके।


1

वास्तव में, विशिष्ट अवसर के तहत कुछ किया जा सकता है: उदाहरण के लिए यदि आप यह जांचना चाहते हैं कि क्या एक स्ट्रिंग पॉइंटर स्ट्रिंग वैध है, लिखने का उपयोग करके (fd, buf, szie) syscall आपको जादू करने में मदद कर सकता है: तो fd को अस्थायी रूप से एक फ़ाइल बनाने वाला बनाएं फ़ाइल जो आप परीक्षण के लिए बनाते हैं, और आप जिस स्ट्रिंग को टेस कर रहे हैं, उसे इंगित करने के लिए buf इंगित करता है, यदि सूचक अमान्य है () वापस आ जाएगा और गलत तरीके से EFAULT पर सेट होगा जो इंगित करता है कि buf आपके पहुंच योग्य पते स्थान से बाहर है।


1

विंडोज में काम करने के बाद (किसी ने पहले यह सुझाव दिया है):

 static void copy(void * target, const void* source, int size)
 {
     __try
     {
         CopyMemory(target, source, size);
     }
     __except(EXCEPTION_EXECUTE_HANDLER)
     {
         doSomething(--whatever--);
     }
 }

फ़ंक्शन को कुछ वर्ग के स्थिर, स्टैंडअलोन या स्थिर विधि होना चाहिए। केवल-पढ़ने के लिए परीक्षण करने के लिए, स्थानीय बफ़र में डेटा की प्रतिलिपि बनाएँ। सामग्री को संशोधित किए बिना लिखने पर परीक्षण करने के लिए, उन्हें लिखें। आप केवल पहले / अंतिम पते का परीक्षण कर सकते हैं। यदि सूचक अमान्य है, तो नियंत्रण 'doSomething', और फिर कोष्ठक के बाहर पारित किया जाएगा। बस सीएसटीरिंग की तरह विनाशकों की आवश्यकता वाले किसी भी चीज़ का उपयोग न करें।


1

विंडोज पर मैं इस कोड का उपयोग करता हूं:

void * G_pPointer = NULL;
const char * G_szPointerName = NULL;
void CheckPointerIternal()
{
    char cTest = *((char *)G_pPointer);
}
bool CheckPointerIternalExt()
{
    bool bRet = false;

    __try
    {
        CheckPointerIternal();
        bRet = true;
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    }

    return  bRet;
}
void CheckPointer(void * A_pPointer, const char * A_szPointerName)
{
    G_pPointer = A_pPointer;
    G_szPointerName = A_szPointerName;
    if (!CheckPointerIternalExt())
        throw std::runtime_error("Invalid pointer " + std::string(G_szPointerName) + "!");
}

उपयोग:

unsigned long * pTest = (unsigned long *) 0x12345;
CheckPointer(pTest, "pTest"); //throws exception

0

Windows के लिए IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr ()।
ये ब्लॉक की लंबाई के लिए आनुपातिक लगते हैं, इसलिए पवित्रता की जांच के लिए मैं सिर्फ शुरुआती पते की जांच करता हूं।


3
आपको इन तरीकों से बचना चाहिए क्योंकि वे काम नहीं करते हैं। blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx
JaredPar

कभी-कभी उनका काम-काज उनके काम न करने के
आस

0

मैंने देखा है कि विभिन्न पुस्तकालय अप्रतिबंधित स्मृति और इस तरह की जाँच के लिए कुछ विधि का उपयोग करते हैं। मेरा मानना ​​है कि वे बस मेमोरी आवंटन और डील्लोकेशन विधियों (मॉलोक / फ्री) को "ओवरराइड" करते हैं, जिसमें कुछ तर्क हैं जो पॉइंटर्स का ट्रैक रखते हैं। मुझे लगता है कि यह आपके उपयोग के मामले के लिए ओवरकिल है, लेकिन यह इसे करने का एक तरीका होगा।


दुर्भाग्य से स्टैक-आबंटित वस्तुओं के लिए मदद नहीं करता है।
टॉम

0

तकनीकी रूप से आप ऑपरेटर नई (और डिलीट ) को ओवरराइड कर सकते हैं और सभी आवंटित मेमोरी के बारे में जानकारी एकत्र कर सकते हैं, इसलिए आपके पास यह जांचने की एक विधि हो सकती है कि क्या हीप मेमोरी वैध है। परंतु:

  1. आपको अभी भी यह जांचने की ज़रूरत है कि क्या पॉइंटर को स्टैक पर आवंटित किया गया है ()

  2. आपको यह परिभाषित करने की आवश्यकता होगी कि 'मान्य' सूचक क्या है:

a) उस पते पर मेमोरी आवंटित की जाती है

b) उस पते पर मेमोरी शुरू है वस्तु का पता होती है (जैसे पता विशाल सरणी के बीच में नहीं)

ग) उस पते पर स्मृति अपेक्षित प्रकार की वस्तु का पता शुरू करना है

नीचे पंक्ति : प्रश्न में दृष्टिकोण C ++ तरीका नहीं है, आपको कुछ नियमों को परिभाषित करने की आवश्यकता है जो यह सुनिश्चित करते हैं कि फ़ंक्शन वैध संकेत प्राप्त करता है।


0

C ++ में उस चेक को बनाने का कोई तरीका नहीं है। यदि अन्य कोड आपको अमान्य सूचक पास करता है तो आपको क्या करना चाहिए? आपको क्रैश होना चाहिए। क्यों? इस लिंक को देखें: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx


0

अर्जित उत्तर के लिए परिशिष्ट:

मान लें कि आपका पॉइंटर केवल तीन मानों को पकड़ सकता है - 0, 1 और -1 जहां 1 एक वैध पॉइंटर को दर्शाता है, -1 एक अमान्य एक और 0 एक अन्य अमान्य है। संभावना है कि अपने सूचक क्या है है शून्य, सभी मूल्यों को समान रूप से होने की संभावना जा रहा है? 1/3। अब, मान्य केस को बाहर निकालें, इसलिए हर अमान्य मामले के लिए, सभी त्रुटियों को पकड़ने के लिए आपके पास 50:50 का अनुपात है। अच्छा लग रहा है ना? इसे 4-बाइट पॉइंटर के लिए स्केल करें। 2 ^ 32 या 4294967294 संभावित मान हैं। इनमें से, केवल एक मान सही है, एक NULL है, और आपके पास अभी भी 4294967292 अन्य अवैध मामले हैं। पुनर्गणना: आपके पास 1 में से 4 (4294967292+ 1) अमान्य मामले हैं। अधिकांश व्यावहारिक उद्देश्यों के लिए 2.xe-10 या 0 की संभावना। इस तरह NULL चेक की निरर्थकता है।


0

तुम्हें पता है, एक नया ड्राइवर (कम से कम लिनक्स पर) जो इसके लिए सक्षम है वह शायद इतना कठिन नहीं होगा कि वह लिख सके।

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


0

आपको इन तरीकों से बचना चाहिए क्योंकि वे काम नहीं करते हैं। blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx - JaredPar 15 फरवरी '09 को 16:02 बजे

यदि वे काम नहीं करते हैं - तो अगले विंडोज़ अपडेट इसे ठीक कर देंगे? अगर वे कॉन्सेप्ट लेवल पर काम नहीं करते हैं - तो फंक्शन शायद विंडोज एपी से पूरी तरह से हटा दिया जाएगा।

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

लेकिन आपको यह दावा नहीं करना चाहिए कि वे कुछ ब्लॉग के कारण काम नहीं करते हैं। मेरे परीक्षण आवेदन में मैंने सत्यापित किया है कि वे काम करते हैं।


0

ये लिंक सहायक हो सकते हैं

_CrtIsValidPointer सत्यापित करता है कि एक निर्दिष्ट मेमोरी रेंज केवल पढ़ने और लिखने के लिए मान्य है (केवल डीबग संस्करण)। http://msdn.microsoft.com/en-us/library/0w1ekd5e.aspx

_CrtCheckMemory डिबग हीप (केवल डीबग संस्करण) में आवंटित मेमोरी ब्लॉकों की अखंडता की पुष्टि करता है। http://msdn.microsoft.com/en-us/library/e73x0s4b.aspx

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.