2013-04-15 14 views
10

प्रिंट करें मान लें कि मेरे पास एक कोड है जो सेगमेंटेशन गलती का कारण बनता है।सेगमेंटेशन गलती कारण

char * ptr = NULL; 
*ptr = "hello"; /* this will cause a segmentation fault */ 

मैं क्रम पर प्रिंट कैसे करूं, स्मृति में पता है कि विभाजन गलती हुई, और विभाजन गलती के लिए कारण (निषिद्ध स्मृति क्षेत्र, या कुछ और करने के लिए एक्सेस करने वाले)।

मैंने कोर डंप फ़ाइलों के बारे में पढ़ा है, लेकिन मुझे यकीन नहीं है कि यह सही समाधान है या नहीं।

मैं यह कैसे कर सकता हूं?

पीएस, मुझे यह तथ्य पता है कि मैं इसे जीडीबी, या एक अन्य डीबगर का उपयोग करके प्राप्त कर सकता हूं, लेकिन इसका उद्देश्य कोड का उपयोग करके और केवल कोड का उपयोग करना है।

+3

आप ['backtrace'] (http://linux.die.net/man/3/backtrace) फ़ंक्शन का उपयोग कर सकते हैं। लेकिन मैं वास्तव में आपको अपने प्रोग्राम को डीबगर में चलाने की सलाह देता हूं, यह आपको केवल बैकट्रैक न देखने की अनुमति देगा, लेकिन कॉल-स्टैक पर चलने और चर की जांच करने की अनुमति देगा। –

+2

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

+0

हम्म .. '* पीआरटी' का प्रकार' char' है, लेकिन "हैलो" का प्रकार 'char *' है। आपको शायद एक वर्ण ('* ptr = 'h';') असाइन करना चाहिए या सही होने के लिए उदाहरण के लिए 'memmove() 'या समान का उपयोग करना चाहिए।जैसा कि है, यह स्ट्रिंग स्थिरांक का पता लेता है, इसे पूर्णांक में रखता है, इसे 1 बाइट तक दबा देता है, और फिर इसे * * ptr' – SingleNegationElimination

उत्तर

4

यदि आप जानना चाहते हैं कि आप एक एसआईजी पंजीकृत कर सकते हैं एनएएल हैंडलर, की तरह कुछ:

void handler(int signum, siginfo_t *info, void *context) 
{ 
    struct sigaction action = { 
    .sa_handler = SIG_DFL, 
    .sa_sigaction = NULL, 
    .sa_mask = 0, 
    .sa_flags = 0, 
    .sa_restorer = NULL 
    }; 

    fprintf(stderr, "Fault address: %p\n", info->si_addr); 
    switch (info->si_code) { 
    case SEGV_MAPERR: 
    fprintf(stderr, "Address not mapped.\n"); 
    break; 

    case SEGV_ACCERR: 
    fprintf(stderr, "Access to this address is not allowed.\n"); 
    break; 

    default: 
    fprintf(stderr, "Unknown reason.\n"); 
    break; 
    } 

    /* unregister and let the default action occur */ 
    sigaction(SIGSEGV, &action, NULL); 
} 

और फिर कहीं आप इसे रजिस्टर करने की आवश्यकता:

struct sigaction action = { 
    .sa_handler = NULL, 
    .sa_sigaction = handler, 
    .sa_mask = 0, 
    .sa_flags = SA_SIGINFO, 
    .sa_restorer = NULL 
    }; 


    if (sigaction(SIGSEGV, &action, NULL) < 0) { 
    perror("sigaction"); 
    } 

मूल रूप से आप एक संकेत है कि आग जब SIGSEGV वितरित किया जाता है, और आप कुछ अतिरिक्त जानकारी प्राप्त कर रजिस्टर, उद्धृत करने के लिए आदमी पेज:

The following values can be placed in si_code for a SIGSEGV signal: 

     SEGV_MAPERR address not mapped to object 

     SEGV_ACCERR invalid permissions for mapped object 

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

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

2

के रूप में पहले से ही यहाँ उत्तर दिया: How to generate a stacktrace when my gcc C++ app crashes

आप (लिनक्स/बीएसडी साथ जीसीसी के मामले में कम से कम) इस काफी आसान कर सकते हैं:

उदाहरण कोड:

#include <stdio.h> 
#include <execinfo.h> 
#include <signal.h> 
#include <stdlib.h> 


void handler(int sig) { 
    void *array[10]; 
    size_t size; 

    // get void*'s for all entries on the stack 
    size = backtrace(array, 10); 

    // print out all the frames to stderr 
    fprintf(stderr, "Error: signal %d:\n", sig); 
    backtrace_symbols_fd(array, size, 2); 
    exit(1); 
} 

int main(int argc, char **argv) { 
    signal(SIGSEGV, handler); // install our handler 

    char * ptr = NULL; 
    *ptr = "hello"; /* this will cause a segmentation fault */ 
} 

उदाहरण आउटपुट :

# gcc -g -rdynamic -o test test.c 
# ./test 
Error: signal 11: 
0 test        0x000000010e99dcfa handler + 42 
1 libsystem_c.dylib     0x00007fff95c1194a _sigtramp + 26 
2 ???         0x0000000000000000 0x0 + 0 
3 libdyld.dylib      0x00007fff8fa177e1 start + 0 
4 ???         0x0000000000000001 0x0 + 1 
+0

यह अब कोर डंप का उत्पादन नहीं करेगा, कम से कम एक त्रुटि के मूल कारण के साथ नहीं। ठीक है, आपके पास कुछ प्रकार का स्टैकट्रैक है, लेकिन बहुत कम मूल्य के साथ। कोई अपराध नहीं, आप केवल ओपीएस प्रश्न का उत्तर दे रहे हैं, लेकिन चेतावनियां वैसे भी लागू होती हैं ;-)। साथ ही, 'spintf'' के संयोजन का उपयोग करने पर विचार करें और 'fprintf' से बचने के लिए' लिखें (2, buf, ...) 'सिग्नल हैंडलर (कम से कम एसिंक सिग्नल के लिए) में मुश्किल हो सकता है। इसके अलावा, मैं 'निकास()' पर कॉल नहीं करता लेकिन केवल '_exit()' या 'abort()'। लेकिन वाईएमएमवी। –

+0

मैं आपसे ईसाई से सहमत हूं, तर्कसंगत रूप से आप इसे कुछ निश्चित बनाने के लिए सक्षम कर सकते हैं यदि आप _really_ कोर डंप नहीं भेजना चाहते हैं। लेकिन व्यक्तिगत रूप से मैं केवल एक स्क्रिप्ट में निष्पादन योग्य को लपेटूंगा जो जीडीबी (यदि उपलब्ध हो) उत्पन्न जेनरेट कोर डंप से स्टैकट्रैक दिखाता है ... एक और अधिक समझदार समाधान लगता है। – Wolph

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