विभाजन दोष (सेगमेंटेशन फॉल्ट)

From Vigyanwiki
Revision as of 15:12, 30 October 2023 by Abhishekkshukla (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

कम्प्यूटिंग में, विभाजन दोष या एक्सेस उल्लंघन दोष (कंप्यूटिंग), या विफलता की स्थिति है, जो मेमोरी सुरक्षा के साथ हार्डवेयर द्वारा उठाया जाता है, ऑपरेटिंग प्रणाली (OS) को सूचित करता है, सॉफ्टवेयर ने प्रतिबंधित क्षेत्र तक पहुंचने का प्रयास किया है। मेमोरी ( मेमोरी एक्सेस उल्लंघन) मानक x86 कंप्यूटरों पर, यह सामान्य सुरक्षा दोष का रूप है। ऑपरेटिंग प्रणाली आधार, प्रतिक्रिया में, सामान्यतः कुछ सुधारात्मक कार्रवाई करता है, सामान्यतः प्रक्रिया को संकेत (कंप्यूटिंग) भेजकर त्रुटि को आपत्तिजनक प्रक्रिया (कंप्यूटिंग) पर भेज देता है। प्रक्रियाएं कुछ स्थितियों में कस्टम सिग्नल हैंडलर स्थापित कर सकती हैं, जिससे उन्हें स्वयं ठीक होने की अनुमति मिलती है,[1] अन्यथा ओएस डिफ़ॉल्ट सिग्नल हैंडलर का उपयोग किया जाता है, सामान्यतः प्रक्रिया की असामान्य समाप्ति (प्रोग्राम क्रैश (कंप्यूटिंग)), एवं कभी-कभी कोर निपात होता है।

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

कई प्रोग्रामिंग भाषा विभाजन दोषों से बचने एवं मेमोरी सुरक्षा में सुधार के लिए चित्रित किए गए तंत्रों को नियोजित कर सकती हैं। उदाहरण के लिए, जंग (प्रोग्रामिंग भाषा) स्वामित्व आधारित को नियोजित करता है।[2] मेमोरी सुरक्षा सुनिश्चित करने के लिए प्रतिरूप[3] अन्य भाषाएँ, जैसे कि लिस्प (प्रोग्रामिंग भाषा) एवं जावा (प्रोग्रामिंग भाषा), जंक संग्रह (कंप्यूटर विज्ञान) को नियोजित करती हैं,[4] जो मेमोरी त्रुटियों के कुछ वर्गों से बचती है, जिससे विभाजन दोष हो सकते हैं।[5]


सिंहावलोकन

मानव जनित सिग्नल का उदाहरण
केडीई डेस्कटॉप वातावरण में विभाजन दोष कृता को प्रभावित कर रहा है।

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

शब्द विभाजन के कंप्यूटिंग में विभिन्न उपयोग हैं; विभाजन दोष के संदर्भ में, 1950 के दशक से उपयोग किया जाने वाला शब्द, यह किसी प्रोग्राम के एड्रेस स्पेस को संदर्भित करता है।[6] मेमोरी सुरक्षा के साथ, केवल प्रोग्राम का स्वयं का स्थान ही पढ़ने योग्य होता है, एवं इसमें से केवल कॉल स्टैक एवं प्रोग्राम के डेटा खंड के लिखने योग्य होता है, जबकि केवल पढ़ने के लिए डेटा एवं कोड खंड लिखने योग्य नहीं होते हैं। इस प्रकार प्रोग्राम के एड्रेस स्पेस के बाहर पढ़ने का प्रयास, या एड्रेस स्पेस के केवल पढ़ने के लिए खंड में लिखने से विभाजन दोष होता है।

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

हार्डवेयर स्तर पर, मेमोरी प्रबंधन इकाई (MMU) द्वारा अवैध पहुंच (यदि संदर्भित मेमोरी उपस्थित है) द्वारा इसकी मेमोरी सुरक्षा सुविधा के भाग के रूप में, या अमान्य पृष्ठ दोष (यदि संदर्भित मेमोरी उपस्थित नहीं है) द्वारा प्रारम्भ में त्रुटि उठाई जाती है। यदि समस्या अमान्य तार्किक पता नहीं है जबकि अमान्य भौतिक पता है, तो इसके अतिरिक्त बस त्रुटि उठाई जाती है, चूंकि ये सदैव भिन्न नहीं होते हैं।

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

कारण

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

विभाजन दोष के कुछ विशिष्ट कारण निम्नलिखित हैं:

  • गैर-उपस्थित मेमोरी पते तक पहुँचने का प्रयास (प्रक्रिया के पता स्थान के बाहर) करता है।
  • मेमोरी तक पहुँचने का प्रयास करने का कार्यक्रम के पास अधिकार नहीं है (जैसे कि प्रक्रिया के संदर्भ में कर्नेल संरचनाएँ)।
  • रीड-ओनली मेमोरी (जैसे कोड खंड) लिखने का प्रयास करता है।

ये परिवर्तन में प्रायः प्रोग्रामिंग त्रुटियों के कारण होते हैं, जिसके परिणाम स्वरूप अमान्य मेमोरी एक्सेस होती है।

  • अशक्त सूचक को संदर्भित करना, जो सामान्यतः ऐसे पते की ओर संकेत करता है जो प्रक्रिया के स्थान का भाग नहीं है।
  • गैर-प्रारंभिक सूचक (जंगली सूचक, जो यादृच्छिक मेमोरी पते को इंगित करता है) को संदर्भित या असाइन करना है
  • फ्रीड सूचक को डिफ्रेंसिंग या असाइन करना (झूलने वाला सूचक, जो उस मेमोरी को इंगित करता है जिसे मुक्त/डिलीट किया गया है)।
  • बफर अधिकता
  • ढेर अधिकता
  • ऐसे प्रोग्राम को निष्पादित करने का प्रयास करना जो उचित रूप से संकलित नहीं होता है।

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

char *p1 = NULL;           // Null pointer
char *p2;                  // Wild pointer: not initialized at all.
char *p3  = malloc(10 * sizeof(char));  // Initialized pointer to allocated memory
                                        // (assuming malloc did not fail)
free(p3);                  // p3 is now a dangling pointer, as memory has been freed

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

संचालन करना

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

कुछ प्रणालियों पर, जैसे कि लिनक्स एवं विंडोज, यह संभव है कि कार्यक्रम स्वयं विभाजन दोष को संभाले।[7] आर्किटेक्चर एवं ऑपरेटिंग प्रणाली के आधार पर, रनिंग प्रोग्राम न केवल ईवेंट को नियंत्रण कर सकता है, इसकी स्थिति के विषय में कुछ जानकारी निकाल सकता है जैसे स्टैक ट्रेस प्राप्त करना, प्रोसेसर रजिस्टर मान, स्रोत कोड की लाइन जब इसे ट्रिगर किया गया था, मेमोरी एड्रेस जो था अमान्य रूप से एक्सेस किया गया[8] एवं क्या कार्रवाई पढ़ी गई या लिखी गई थी।[9] चूंकि विभाजन त्रुटि का सामान्यतः अर्थ है कि प्रोग्राम में बग है जिसे ठीक करने की आवश्यकता है, ऐसी विफलता का कारण परीक्षण, डिबगिंग एवं प्लेटफॉर्म का अनुकरण करना भी संभव है, जहां मेमोरी तक सीधी पहुंच की आवश्यकता है। पश्चात के विषय में, प्रणाली को त्रुटि होने के पश्चात भी प्रोग्राम को चलाने की अनुमति देने में सक्षम होना चाहिए। इस विषय में, जब प्रणाली अनुमति देता है, तो घटना को संभालना एवं निष्पादन निरंतर रखने के लिए असफल निर्देश के लिए प्रोसेसर प्रोग्राम काउंटर को बढ़ाना संभव होता है।[10]


उदाहरण

EMV कीपैड पर विभाजन दोष

रीड ओनली मेमोरी में लिखना

रीड-ओनली मेमोरी में लिखने से विभाजन दोष होता है। कोड त्रुटियों के स्तर पर, यह तब होता है जब प्रोग्राम स्वयं के कोड खंड या डेटा खंड के रीड-ओनली भाग को लिखता है, क्योंकि ये OS द्वारा रीड-ओनली मेमोरी में लोड किए जाते हैं।

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

int main(void)
{
    char *s = "hello world";
    *s = 'H';
}

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

$ gcc segfault.c -g -o segfault
$ ./segfault
Segmentation fault

जीडीबी (GDB) से कोर फ़ाइल का पश्व-अनुरेखन:

Program received signal SIGSEGV, Segmentation fault.
0x1c0005c2 in main () at segfault.c:6
6               *s = 'H';

इस कोड को वर्ण सूचक के अतिरिक्त सरणी का उपयोग करके सही किया जा सकता है, क्योंकि यह ढेर पर मेमोरी आवंटित करता है एवं इसे स्ट्रिंग अक्षर के मान में प्रारंभ करता है।

char s[] = "hello world";
s[0] = 'H';  // equivalently, *s = 'H';

स्ट्रिंग अक्षर को संशोधित नहीं किया जाना चाहिए (यह C मानक में अपरिभाषित व्यवहार है), C में वे हैं static char [] प्रकार,[11][12][13] इसलिए मूल कोड में कोई निहित रूपांतरण नहीं है (जो इंगित करता है a char * उस सरणी में), जबकि C ++ में वे हैं static const char [] प्रकार, एवं इस प्रकार निहित रूपांतरण होता है, इसलिए संकलक सामान्यतः इस विशेष त्रुटि को पकड़ लेते है।

अशक्त सूचक डिरेफरेंस

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

int *ptr = NULL;
printf("%d", *ptr);

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

int *ptr = NULL;
*ptr = 1;

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

int *ptr = NULL;
*ptr;


बफर अधिकता

निम्न कोड वर्ण सरणी तक पहुँचता है,s इसकी ऊपरी सीमा से भिन्न संकलक एवं प्रोसेसर के आधार पर, इसका परिणाम विभाजन दोष हो सकता है।

char s[] = "hello world";
char c = s[20];


स्टैक अधिकता

आधार विषय के बिना उदाहरण प्रत्यावर्तन है।

int main(void)
{
    return main();
}

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

यह भी देखें

  • सामान्य संरक्षण त्रुटि
  • भंडारण उल्लंघन
  • गुरु ध्यान

संदर्भ

  1. Expert C programming: deep C secrets By Peter Van der Linden, page 188
  2. "The Rust Programming Language - Ownership".
  3. "Fearless Concurrency with Rust - The Rust Programming Language Blog".
  4. McCarthy, John (April 1960). "सांकेतिक भावों के पुनरावर्ती कार्य और मशीन द्वारा उनकी गणना, भाग I". Communications of the ACM. 4 (3): 184–195. doi:10.1145/367177.367199. S2CID 1489409. Retrieved 2018-09-22.
  5. Dhurjati, Dinakar; Kowshik, Sumant; Adve, Vikram; Lattner, Chris (1 January 2003). "मेमोरी सुरक्षा रनटाइम चेक या कचरा संग्रह के बिना" (PDF). Proceedings of the 2003 ACM SIGPLAN Conference on Language, Compiler, and Tool for Embedded Systems (in English). ACM. 38 (7): 69–80. doi:10.1145/780732.780743. ISBN 1581136471. S2CID 1459540. Retrieved 2018-09-22.
  6. "डिबगिंग विभाजन दोष और सूचक समस्याएं - Cprogramming.com". www.cprogramming.com. Retrieved 2021-02-03.
  7. "Cleanly recovering from Segfaults under Windows and Linux (32-bit, x86)". Retrieved 2020-08-23.
  8. "Implementation of the SIGSEGV/SIGABRT handler which prints the debug stack trace". GitHub. Retrieved 2020-08-23.
  9. "How to identify read or write operations of page fault when using sigaction handler on SIGSEGV?(LINUX)". Retrieved 2020-08-23.
  10. "LINUX – WRITING FAULT HANDLERS". Retrieved 2020-08-23.
  11. "6.1.4 String literals". ISO/IEC 9899:1990 - Programming languages -- C.
  12. "6.4.5 String literals". ISO/IEC 9899:1999 - Programming languages -- C.
  13. "6.4.5 String literals". ISO/IEC 9899:2011 - Programming languages -- C.
  14. What is the difference between a segmentation fault and a stack overflow? at Stack Overflow


बाहरी संबंध