2012-04-18 10 views
23

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

क्या यह संभव है?

void SignalInit(void) 
{ 

struct sigaction sigIntHandler; 

sigIntHandler.sa_handler = mysighandler; 
sigemptyset(&sigIntHandler.sa_mask); 
sigIntHandler.sa_flags = 0; 
sigaction(SIGINT, &sigIntHandler, NULL); 
sigaction(SIGSEGV, &sigIntHandler, NULL); 

} 

और हैंडलर इस तरह से चला जाता है।

void mysighandler() 
{ 
MyfreeBuffers(); /*related to my applciation*/ 
} 

विभाजन गलती संकेत के लिए यहाँ, हैंडलर कई बार और के रूप में स्पष्ट MyfreeBuffers() कहा जाता है की जा रही है मुझे पहले से ही मुक्त कर दिया स्मृति को मुक्त कराने के लिए त्रुटियों को देता है। मैं सिर्फ एक बार मुक्त करना चाहता हूं लेकिन अभी भी आवेदन से बाहर निकलना नहीं चाहता हूं।

कृपया मदद करें।

उत्तर

28

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

तो पहला स्थान अनुदेश कि SIGSEGV में हुई और ठीक करने के लिए यह (आप हैंडलर में backtrace() की तरह कुछ कहते हैं और खुद के लिए देखते हैं कि क्या गलत हो गया था सकता है) इसके अलावा

कोशिश, POSIX मानक का कहना है कि,

के बाद यह से सामान्य रूप से वापस आने वाले [XSI] SIGBUS, SIGFPE, SIGILL के लिए एक संकेत को पकड़ने समारोह, या SIGSEGV संकेत है कि मार(), [आरटीएस] sigqueue द्वारा उत्पन्न नहीं कर रहा था

एक प्रक्रिया के व्यवहार अपरिभाषित है(), या raise()।

तो, आदर्श बात यह है कि पहले से ही अपने सेगफॉल्ट को ठीक करना है। segfault के लिए हैंडलर अंतर्निहित त्रुटि स्थिति

बायपास करने के लिए तो सबसे अच्छा सुझाव है- होगा SIGSEGV पकड़ नहीं है मतलब नहीं है। इसे कोर डंप करने दें। कोर का विश्लेषण करें। अमान्य स्मृति संदर्भ को ठीक करें और वहां आप जाओ!

0

ठीक है आप एक राज्य चर सेट कर सकते हैं और केवल सेट होने पर ही मुफ्त मेमोरी सेट कर सकते हैं। सिग्नल हैंडलर हर बार बुलाया जाएगा, आप उस AFAIK को नियंत्रित नहीं कर सकते हैं।

9

तो फिर SIGSEGV आग, स्पष्ट निष्कर्ष MyfreeBuffers(); करने के लिए कॉल नहीं मूल समस्या तय किया है (और अगर है कि समारोह वास्तव में केवल free() कुछ आबंटित स्मृति करता है, मुझे यकीन है कि तुम क्यों यह लगता होगा नहीं कर रहा हूँ होगा)।

असफल, एक SIGSEGV आग लगती है जब एक पहुंच योग्य स्मृति पते तक पहुंचने का प्रयास किया जाता है। यदि आप एप्लिकेशन से बाहर नहीं जा रहे हैं, तो आपको या तो उस मेमोरी एड्रेस को सुलभ बनाना होगा, या longjmp() के साथ निष्पादन पथ को बदलना होगा।

6

आपको SIG_SEGV के बाद जारी रखने की कोशिश नहीं करनी चाहिए। इसका मूल रूप से मतलब है कि आपके आवेदन का वातावरण किसी भी तरह से दूषित हो गया है। ऐसा हो सकता है कि आपने अभी एक शून्य सूचक का वर्णन किया है, या यह हो सकता है कि कुछ बग ने आपके प्रोग्राम को अपने ढेर या ढेर या कुछ पॉइंटर चर को दूषित कर दिया है, आपको बस पता नहीं है। केवल सुरक्षित करने के लिए कार्यक्रम को समाप्त कर दिया गया है।

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

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

0

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

8

मैं कथन के साथ सहमत नहीं हूं "SIGSEGV को पकड़ें"

अप्रत्याशित शर्तों से निपटने के लिए यह एक बहुत अच्छा प्रैटिस है। और NULL पॉइंटर्स (जैसा कि मॉलोक विफलताओं द्वारा दिया गया है) के साथ setjmp/longjmp से जुड़े सिग्नल तंत्र के साथ, आपके कोड के साथ त्रुटि स्थिति प्रबंधन वितरित करने के लिए यह बहुत साफ है।

नोट तथापि यदि आप SEGV पर '' sigaction '' का उपयोग करें, आप भूल जाते हैं कि नहीं करना चाहिए SA_NODEFERsa_flags में कहने के लिए - या तथ्य यह है SEGV सिर्फ एक बार अपने हैंडलर ट्रिगर किया जाएगा से निपटने के लिए एक और रास्ता खोजने।

#include <setjmp.h> 
#include <signal.h> 
#include <stdio.h> 
#include <string.h> 

static void do_segv() 
{ 
    int *segv; 

    segv = 0; /* malloc(a_huge_amount); */ 

    *segv = 1; 
} 

sigjmp_buf point; 

static void handler(int sig, siginfo_t *dont_care, void *dont_care_either) 
{ 
    longjmp(point, 1); 
} 

int main() 
{ 
    struct sigaction sa; 

    memset(&sa, 0, sizeof(sigaction)); 
    sigemptyset(&sa.sa_mask); 

    sa.sa_flags  = SA_NODEFER; 
    sa.sa_sigaction = handler; 

    sigaction(SIGSEGV, &sa, NULL); /* ignore whether it works or not */ 

    if (setjmp(point) == 0) 
    do_segv(); 

    else 
    fprintf(stderr, "rather unexpected error\n"); 

    return 0; 
} 
+0

यह एक अच्छा समाधान है। मुझे विशेष रूप से पसंद नहीं आया "इसे क्रैश करने दें और फिर कोर डंप का विश्लेषण करें।" – dturvene

0

लगता है कि कम से कम लिनक्स के तहत -न-कॉल-अपवाद विकल्प के साथ चाल का उपयोग समाधान हो सकता है। यह सिग्नल को सामान्य C++ अपवाद में बदलने और सामान्य तरीके से इसे संभालने की क्षमता प्रदान करेगा। उदाहरण के लिए linux3/gcc46: "-fnon-call-exceptions", which signals are trapping instructions? देखें।

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