it-swarm.com.de

Ausnahmen für Zugriffsverletzungen abfangen?

Beispiel

int *ptr;
*ptr = 1000;

kann ich mit Standard-C++ eine Ausnahme für die Verletzung des Speicherzugriffs abfangen, ohne Microsoft-spezifisch zu verwenden?.

80
Ahmed Said

Nee. C++ löst keine Ausnahme aus, wenn Sie etwas Schlechtes tun, das einen Leistungseinbruch zur Folge hätte. Dinge wie Zugriffsverletzungen oder Fehler bei der Division durch Null sind eher "Maschinen" -Ausnahmen als Dinge auf Sprachebene, die Sie abfangen können.

36
unwind

Lies das und weine!

Ich habe es herausgefunden. Wenn Sie nicht vom Handler werfen, fährt der Handler einfach fort und die Ausnahme auch.

Die Magie passiert, wenn Sie Ihre eigene Ausnahme werfen und damit umgehen.

#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");

}
102
Juxta

Es gibt eine sehr einfache Möglichkeit, eine Ausnahme (Division durch Null, Zugriffsverletzung usw.) in Visual Studio mit try -> catch (abzufangen. ...) Block. Eine kleine Änderung der Projekteinstellungen ist ausreichend. Aktivieren Sie einfach die Option/EHa in den Projekteinstellungen. Siehe Projekteigenschaften -> C/C++ -> Codegenerierung -> Ändern Sie die Option "C++ - Ausnahmen aktivieren" in "Ja mit SEH-Ausnahmen" . Das ist es!

Details finden Sie hier: http://msdn.Microsoft.com/en-us/library/1deeycx5 (v = vs.80) .aspx

63

Diese Art von Situation ist implementierungsabhängig und erfordert daher einen herstellerspezifischen Mechanismus, um eine Falle zu stellen. Bei Microsoft handelt es sich um SEH und bei * nix um ein Signal

Im Allgemeinen ist das Erkennen einer Zugriffsverletzungsausnahme eine sehr schlechte Idee. Es gibt fast keine Möglichkeit, eine AV-Ausnahme zu beheben, und der Versuch, dies zu tun, führt nur dazu, dass es schwieriger wird, Fehler in Ihrem Programm zu finden.

8
JaredPar

Zumindest für mich hat der in einer anderen Antwort erwähnte Ansatz signal(SIGSEGV ...) unter Win32 mit Visual C++ 2015 nicht funktioniert. Was für mich funktioniert hat, war die Verwendung von _set_se_translator() in eh.h. Das funktioniert so:

Schritt 1) Stellen Sie sicher, dass Sie Ja mit SEH-Ausnahmen (/ EHa) in Projekteigenschaften/C++/Codegenerierung/Aktivieren aktivieren C++ - Ausnahmen , wie in der Antwort von Volodymyr Frytskyy erwähnt.

Schritt 2) Rufe _set_se_translator() auf und übergebe einen Funktionszeiger (oder Lambda) für den neuen Exception-Übersetzer . Es wird als Übersetzer bezeichnet, weil es im Grunde genommen nur die Low-Level-Ausnahme akzeptiert und sie erneut auslöst, als etwas, das leichter zu fangen ist, wie 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());
});

Schritt 3) Fang die Ausnahme, wie du es normalerweise tun würdest:

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

Wie bereits erwähnt, gibt es keine Möglichkeit, dies auf der Windows-Plattform zu tun, die nicht von Microsoft/Compiler angeboten wird. Es ist jedoch offensichtlich nützlich, diese Arten von Ausnahmen in der normalen Methode {} catch (exception ex) {} für die Fehlerberichterstattung abzufangen und Ihre App ordnungsgemäß zu beenden (wie JaredPar sagt, ist die App jetzt wahrscheinlich in Schwierigkeiten). . Wir verwenden _se_translator_function in einem einfachen Klassenwrapper, mit dem wir die folgenden Ausnahmen in einem try-Handler abfangen können:

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)

Die ursprüngliche Klasse stammt aus diesem sehr nützlichen Artikel:

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

7
Damien

Nicht der Ausnahmebehandlungsmechanismus. Sie können jedoch den vom C bereitgestellten signal () -Mechanismus verwenden.

> man signal

     11    SIGSEGV      create core image    segmentation violation

Das Schreiben in einen NULL-Zeiger wird wahrscheinlich ein SIGSEGV-Signal verursachen

3
Martin York