2008-09-17 19 views
12

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

उत्तर

7

"कर्नेल" (यह वास्तव में आपके कोड को चलाने वाला कर्नेल नहीं है, यह सीपीयू है) यह नहीं जानता कि आपका कोड उस स्मृति को संदर्भित कर रहा है, जिसे स्पर्श करने वाला नहीं है। यह केवल जानता है कि आपने इसे करने की कोशिश की है।

कोड:

char *x = alloca(100); 
char y = x[150]; 

वास्तव में सीपीयू द्वारा मूल्यांकन नहीं किया जा सकता है के रूप में आप एक्स की सीमा से परे तक पहुँचने के लिए कोशिश कर रहा। BTW

char y = *((char*)(0xdeadbeef)); 

, मैं alloca के उपयोग को हतोत्साहित के बाद से ढेर ढेर (उपयोग malloc बजाय) की तुलना में अधिक सीमित हो जाता है:

आप के साथ ठीक उसी पते के हिट हो सकती है।

+0

हालांकि कट्टर हेरफेर के लिए स्टैकस्पेस बहुत तेज है। बस थोड़ी देर का उपयोग करें। इसके अलावा, किसी भी alloca करने से पहले "Getrlimit" की जांच करें। सुनिश्चित करें कि आपके पास पर्याप्त जगह शेष है! –

5

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

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

सेगफाल्ट डीबग करने के लिए आप जीडीबी में एक प्रोग्राम चला सकते हैं। उदाहरण के लिए, निम्नलिखित सी कार्यक्रम SEGFAULT देगा: # segfault.c # शामिल # शामिल

int main() 
{ 
     printf("Starting\n"); 
     void *foo=malloc(1000); 
     memcpy(foo, 0, 100); //this line will segfault 
     exit(0); 
} 

अगर मैं यह इतना तरह संकलन:

gcc -g -o segfault segfault.c 

और उसके बाद तो जैसे यह चलाएँ:

$ gdb ./segfault 
GNU gdb 6.7.1 
Copyright (C) 2007 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "i686-pc-linux-gnu"... 
Using host libthread_db library "/lib/libthread_db.so.1". 
(gdb) run 
Starting program: /tmp/segfault 
Starting 

Program received signal SIGSEGV, Segmentation fault. 
0x4ea43cbc in memcpy() from /lib/libc.so.6 
(gdb) bt 
#0 0x4ea43cbc in memcpy() from /lib/libc.so.6 
#1 0x080484cb in main() at segfault.c:8 
(gdb) 

मुझे जीडीबी से पता चला कि लाइन 8 पर एक सेगमेंटेशन गलती थी। बेशक एसए को संभालने के अधिक जटिल तरीके हैं सीके ओवरफ्लो और अन्य मेमोरी त्रुटियां, लेकिन यह पर्याप्त होगा।

1

बस Valgrind का उपयोग करें। यह आपकी सभी स्मृति आवंटन गलतियों को उत्तेजित सटीकता के साथ इंगित करेगा।

42

आप वास्तव में सिग्नल हैंडलर का उपयोग करके एक स्टैक ओवरफ़्लो के लिए स्थिति को पकड़ सकते हैं।

  • सेटअप SIGSEGV (segfault) sigaction का उपयोग कर, इस SO_ONSTACK ध्वज सेट करने के लिए एक संकेत हैंडलर:

    ऐसा करने के लिए, आपको दो काम करने चाहिए। यह सिग्नल वितरित करते समय कर्नेल को वैकल्पिक स्टैक का उपयोग करने के लिए निर्देश देता है।

  • एसआईजीएसईजीवी के लिए हैंडलर का उपयोग करने वाले वैकल्पिक स्टैक को सेट करने के लिए सिग्ल्टस्टैक() को कॉल करें।

फिर जब आप ढेर को बहते हैं, तो कर्नेल सिग्नल देने से पहले आपके वैकल्पिक ढेर पर स्विच करेगा। एक बार आपके सिग्नल हैंडलर में, आप उस पते की जांच कर सकते हैं जो गलती का कारण बनता है और यह निर्धारित करता है कि यह एक स्टैक ओवरफ़्लो था, या नियमित गलती थी।

0

एक स्टैक ओवरफ़्लो आवश्यक रूप से क्रैश उत्पन्न नहीं करता है। यह चुपचाप आपके प्रोग्राम के डेटा को मिटा सकता है लेकिन निष्पादित करना जारी रखता है।

मैं SIGSEGV हैंडलर क्लुज का उपयोग नहीं करता बल्कि इसके बजाय मूल समस्या को ठीक करता हूं।

यदि आप स्वचालित सहायता चाहते हैं, तो आप जीसीसी के -स्टैक-रक्षक विकल्प का उपयोग कर सकते हैं, जो रनटाइम पर कुछ ओवरफ्लो दिखाएगा और प्रोग्राम को रोक देगा।

valgrind गतिशील स्मृति आवंटन कीड़े के लिए अच्छा है, लेकिन स्टैक त्रुटियों के लिए नहीं है।

0

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

अन्य लोगों को जो इस समस्या को पाते हैं, उनके लिए एक कंपाइलर ध्वज है जो ढेर पर एक निश्चित आकार के ऊपर अस्थायी varibles डालता है।

संबंधित मुद्दे