कैच एक्सेस उल्लंघन उल्लंघन?


89

उदाहरण

int *ptr;
*ptr = 1000;

क्या मैं किसी भी Microsoft विशिष्ट का उपयोग किए बिना मानक C ++ का उपयोग करके मेमोरी एक्सेस उल्लंघन अपवाद को पकड़ सकता हूं।

जवाबों:


42

नहीं। जब आप कुछ बुरा करते हैं, तो C ++ अपवाद नहीं फेंकता है, जिससे प्रदर्शन प्रभावित होगा। भाषा-स्तरीय चीज़ों के बजाय शून्य त्रुटियों द्वारा एक्सेस उल्लंघन या विभाजन जैसे त्रुटि "मशीन" अपवादों की तरह हैं।


मुझे पता है कि यह एचडब्ल्यू अपवाद है, लेकिन माइक्रोसॉफ्ट के विशिष्ट कीवर्ड हैं जो इसे संभालते हैं (__ प्रयास __except)?
अहमद ने

2
@ अहम्: हाँ, लेकिन यदि आप उनका उपयोग करते हैं, तो 'असंभव' चीजें हो सकती हैं। उदाहरण के लिए, कोड की एवी लाइन के बाद के कुछ बयान पहले ही निष्पादित हो सकते हैं, या एवी से पहले के बयान निष्पादित नहीं हुए हैं।
आरोन

नीचे दिए गए मेरे जवाब को देखें कि नियमित प्रयास का उपयोग करके ऐसे अपवादों को कैसे सक्षम किया जाए ... VC ++ में ब्लॉक को पकड़ें।
वलोडिमिर फ्राइत्स्की

@ क्या आप "असंभव चीजें हो रही हैं" भाग पर विस्तार से बता सकते हैं? यह संकलक और / या सीपीयू के पुन: निर्देश के कारण है?
वेपेंग एल

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

108

इसे पढ़ें और रोएं!

मैं यह समझ गया। यदि आप हैंडलर से नहीं फेंकते हैं, तो हैंडलर बस जारी रहेगा और इसलिए अपवाद होगा।

जादू तब होता है जब आप खुद को अपवाद फेंकते हैं और संभालते हैं।

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>

void SignalHandler(int signal)
{
    printf("Signal %d",signal);
    throw "!Access Violation!";
}

int main()
{
    typedef void (*SignalHandlerPointer)(int);

    SignalHandlerPointer previousHandler;
    previousHandler = signal(SIGSEGV , SignalHandler);
    try{
        *(int *) 0 = 0;// Baaaaaaad thing that should never be caught. You should write good code in the first place.
    }
    catch(char *e)
    {
        printf("Exception Caught: %s\n",e);
    }
    printf("Now we continue, unhindered, like the abomination never happened. (I am an EVIL genius)\n");
    printf("But please kids, DONT TRY THIS AT HOME ;)\n");

}

अच्छा टिप, विशेष रूप से क्योंकि __try / __ को छोड़कर एवी या तो नहीं पकड़ेगा।
फेबियो सेकोनेलो

16
यह gcc में काम नहीं करता है लेकिन VC ++ में काम करता है लेकिन केवल "डीबग" बिल्ड में। फिर भी एक दिलचस्प समाधान के लिए upvoting। सिग्नल हैंडलर को बुलाया जाएगा, लेकिन अपवाद नहीं फेंका जाएगा।
नेटली एडम्स

2
यह पोर्टेबल काम नहीं करता है। जब एक सिग्नल हैंडलर को स्टैक फ्रेम में लगाया जाता है और रजिस्टर मुंगिंग तब नहीं होता है जब एक सामान्य फ़ंक्शन स्टैक फ्रेम (यह कुछ सिस्टम पर समान स्टैक का उपयोग भी नहीं कर सकता है)। सिग्नल हैंडलर को सक्रिय करने के लिए एक ध्वज जो आप कर सकते हैं वह सबसे अच्छा है। फिर उस ध्वज और फेंक के लिए अपने कोड परीक्षण में।
मार्टिन

2
यह अपरिभाषित व्यवहार शुरू करने का एक उच्च मौका है। इसके लिए POSIX पर काम करने के लिए, कोई भी वैकल्पिक सिग्नल स्टैक ( sigaltstack) स्थापित नहीं होना चाहिए (जब तक कि C ++ अपवाद को लागू नहीं करता है), और हर रनिंग फ़ंक्शन को अनइंडिंग सिस्टम को स्वयं सिग्नल-सुरक्षित होना चाहिए।
मिनिमैक्सवग

1
यदि आप डिफॉल्ट हैंडलर को सिग्नल (इस मामले में SIGSEGV) लौटना चाहते हैं, तो ज्यूस निम्नलिखित का उपयोग करें:signal(SIGSEGV, SIG_DFL);
कोकिका

67

किसी भी प्रकार के अपवाद को पकड़ने का एक बहुत ही आसान तरीका है विजुअल स्टूडियो में प्रयास (> कैच ... (...) ब्लॉक का उपयोग करके। एक मामूली परियोजना सेटिंग्स ट्विकिंग पर्याप्त है। प्रोजेक्ट सेटिंग्स में बस सक्षम / ईएचए विकल्प। प्रोजेक्ट गुण देखें -> C / C ++ -> कोड जेनरेशन -> सक्षम करें C ++ एक्सेप्शन को "हाँ, SEH अपवाद के साथ" संशोधित करें । बस!

यहां देखें विवरण: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx


Visual Studio .NET 2003 में ऐसा कोई सेटिंग मान नहीं है, केवल "नहीं" और "Yes (/ EHsc)" हैं। क्या आप स्पष्ट कर सकते हैं कि इस सेटिंग को सक्षम करने के लिए आपको विजुअल स्टूडियो का कौन सा न्यूनतम संस्करण चाहिए?
izogfif

यह लिंक "विजुअल स्टूडियो 2005" निर्दिष्ट करने के लिए प्रकट होता है
ड्रू डेलानो

2
क्या होगा अगर gcc या MinGW के साथ?
user1024

10

कम से कम मेरे लिए, signal(SIGSEGV ...)एक अन्य उत्तर में वर्णित दृष्टिकोण विजुअल C ++ 2015 के साथ Win32 पर काम नहीं किया । क्या किया था मेरे लिए काम का उपयोग किया गया _set_se_translator()में पाया eh.h। यह इस तरह काम करता है:

चरण 1 ) सुनिश्चित करें कि आप प्रोजेक्ट गुणों / सी ++ / कोड जनरेशन / सक्षम सी ++ अपवादों में एसईएच अपवादों (/ ईएचए) के साथ हां को सक्षम करते हैं , जैसा कि वलोडिमिर फ्रायत्स्की द्वारा जवाब में उल्लेख किया गया है ।

चरण 2 ) कॉल _set_se_translator(), नए अपवाद अनुवादक के लिए एक फ़ंक्शन पॉइंटर (या लैम्ब्डा) में गुजर रहा है । इसे एक अनुवादक कहा जाता है क्योंकि यह मूल रूप से केवल निम्न-स्तरीय अपवाद लेता है और इसे पकड़ने में आसान के रूप में पुन: फेंकता है, जैसे std::exception:

#include <string>
#include <eh.h>

// Be sure to enable "Yes with SEH Exceptions (/EHa)" in C++ / Code Generation;
_set_se_translator([](unsigned int u, EXCEPTION_POINTERS *pExp) {
    std::string error = "SE Exception: ";
    switch (u) {
    case 0xC0000005:
        error += "Access Violation";
        break;
    default:
        char result[11];
        sprintf_s(result, 11, "0x%08X", u);
        error += result;
    };
    throw std::exception(error.c_str());
});

चरण 3 ) सामान्य रूप से आप जैसे अपवाद को पकड़ेंगे:

try{
    MakeAnException();
}
catch(std::exception ex){
    HandleIt();
};

1
इस साइट में _set_se_translator () के तरीकों और मेरे लिए काम करने वाले, msdn.microsoft.com/en-us/library/5z4bw5h5.aspx
Dash

8

इस प्रकार की स्थिति कार्यान्वयन पर निर्भर है और फलस्वरूप इसे फँसाने के लिए एक विक्रेता विशिष्ट तंत्र की आवश्यकता होगी। Microsoft के साथ इसमें SEH शामिल होगा, और * nix में एक सिग्नल शामिल होगा

सामान्य तौर पर हालांकि एक एक्सेस उल्लंघन अपवाद को पकड़ना एक बहुत बुरा विचार है। एवी अपवाद से उबरने का लगभग कोई रास्ता नहीं है और ऐसा करने का प्रयास करने से आपके कार्यक्रम में बग ढूंढना मुश्किल हो जाएगा।


1
तो आपकी सलाह यह जानना है कि एवी अपवाद का कारण क्या है?
अहमद ने

4
पूर्ण रूप से। एवी आपके कोड में एक बग का प्रतिनिधि है और अपवाद को पकड़ने से समस्या को छिपाया जाएगा।
JaredPar

1
स्पष्ट करने के लिए, C ++ मानक परिभाषित अपरिभाषित, अनिर्दिष्ट और कार्यान्वयन के बीच अंतर करता है। परिभाषित कार्यान्वयन का मतलब है कि कार्यान्वयन को निर्दिष्ट करना चाहिए कि क्या होता है। प्रश्न में कोड अपरिभाषित है, जिसका अर्थ है कि कुछ भी हो सकता है, और हर बार अलग हो सकता है।
कीथबी

15
एक्सेस उल्लंघन का उल्लंघन करना बुरा विचार नहीं है - यह उपयोगकर्ता के अनुभव के लिए अच्छा है। हालाँकि, इस मामले में एकमात्र सार्थक बात यह है - बग रिपोर्टिंग GUI के साथ एक और प्रक्रिया स्पॉन करना और वर्तमान प्रक्रिया डंप बनाने का प्रयास करना। एक प्रक्रिया पैदा करना हमेशा सुपाच्य ऑपरेशन होता है। फिर, मैं आत्म-हत्या के लिए टर्मिनेटप्रोसेस () करता हूं।
Пет13р Петров

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

8

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

DECLARE_EXCEPTION_CLASS(datatype_misalignment)
DECLARE_EXCEPTION_CLASS(breakpoint)
DECLARE_EXCEPTION_CLASS(single_step)
DECLARE_EXCEPTION_CLASS(array_bounds_exceeded)
DECLARE_EXCEPTION_CLASS(flt_denormal_operand)
DECLARE_EXCEPTION_CLASS(flt_divide_by_zero)
DECLARE_EXCEPTION_CLASS(flt_inexact_result)
DECLARE_EXCEPTION_CLASS(flt_invalid_operation)
DECLARE_EXCEPTION_CLASS(flt_overflow)
DECLARE_EXCEPTION_CLASS(flt_stack_check)
DECLARE_EXCEPTION_CLASS(flt_underflow)
DECLARE_EXCEPTION_CLASS(int_divide_by_zero)
DECLARE_EXCEPTION_CLASS(int_overflow)
DECLARE_EXCEPTION_CLASS(priv_instruction)
DECLARE_EXCEPTION_CLASS(in_page_error)
DECLARE_EXCEPTION_CLASS(illegal_instruction)
DECLARE_EXCEPTION_CLASS(noncontinuable_exception)
DECLARE_EXCEPTION_CLASS(stack_overflow)
DECLARE_EXCEPTION_CLASS(invalid_disposition)
DECLARE_EXCEPTION_CLASS(guard_page)
DECLARE_EXCEPTION_CLASS(invalid_handle)
DECLARE_EXCEPTION_CLASS(microsoft_cpp)

मूल वर्ग इस बहुत उपयोगी लेख से आया है:

http://www.codeproject.com/KB/cpp/exception.aspx


8
मैं देखता हूं कि Microsoft कंपाइलर का उपयोग करना एक अवैध निर्देश या पहुंच उल्लंघन के समान है। दिलचस्प।
डेविड थॉर्नले

3

अपवाद हैंडलिंग तंत्र नहीं है, लेकिन आप सिग्नल () तंत्र का उपयोग कर सकते हैं जो सी द्वारा प्रदान किया गया है।

> man signal

     11    SIGSEGV      create core image    segmentation violation

NULL पॉइंटर पर लिखना संभवतः SIGSEGV सिग्नल का कारण बनता है


@maidamai पॉज़िक्स signal()मानक का हिस्सा है। विंडोज पॉज़िक्स मानक को लागू करता है (जैसा कि लिनक्स और यूनिक्स करता है)
मार्टिन

-1

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


6
पहुंच उल्लंघन से पुनर्प्राप्ति संभव हो सकती है। ईआईपी जंप वॉयलेशन से पुनर्प्राप्त करना कभी भी संभव नहीं है जब तक कि आप डॉगी न हों और असेंबली लेवल इंस्ट्रक्शन पॉइंटर्स रखें। हालाँकि, बग उल्लंघन GUI सुविधा के लिए किसी अन्य प्रक्रिया को स्पॉइन करने के लिए एक्सेस उल्लंघन को पकड़ना अच्छा है।
Пет13р Петров
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.