Beispiel
int *ptr;
*ptr = 1000;
Kann ich eine Ausnahme von Speicherzugriffsverletzungen mit Standard-C ++ abfangen, ohne Microsoft-spezifisch zu verwenden?
Beispiel
int *ptr;
*ptr = 1000;
Kann ich eine Ausnahme von Speicherzugriffsverletzungen mit Standard-C ++ abfangen, ohne Microsoft-spezifisch zu verwenden?
Antworten:
Nee. C ++ löst keine Ausnahme aus, wenn Sie etwas Schlechtes tun, das zu einem Leistungseinbruch führen würde. Dinge wie Zugriffsverletzungen oder Division durch Null-Fehler sind eher "Maschinen" -Ausnahmen als Dinge auf Sprachebene, die Sie abfangen können.
Lies das und weine!
Ich habe es herausgefunden. Wenn Sie nicht vom Handler werfen, fährt der Handler einfach fort, ebenso wie die Ausnahme.
Die Magie passiert, wenn Sie Ihre eigene Ausnahme auslösen 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");
}
sigaltstack
) installiert sein (es sei denn, die C ++ - Ausnahme-Abwicklungsimplementierung erlaubt dies), und jede Laufzeitfunktion, die den Abwicklungsmechanismus selbst handhabt, sollte signal-sicher sein.
signal(SIGSEGV, SIG_DFL);
Es gibt eine sehr einfache Möglichkeit, jede Art von Ausnahme (Division durch Null, Zugriffsverletzung usw.) in Visual Studio mit dem Block try -> catch (...) abzufangen. Eine geringfügige Änderung der Projekteinstellungen ist ausreichend. Aktivieren Sie einfach die Option / EHa in den Projekteinstellungen. Siehe Projekteigenschaften -> C / C ++ -> Codegenerierung -> Ändern Sie die 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
Zumindest für mich funktionierte dersignal(SIGSEGV ...)
in einer anderen Antwort erwähnte Ansatz unter Win32 mit Visual C ++ 2015 nicht . Was tat Arbeit für mich war zu verwenden _set_se_translator()
gefunden eh.h
. Es funktioniert so:
Schritt 1 ) Stellen Sie sicher, dass Sie Ja mit SEH-Ausnahmen (/ EHa) in Projekteigenschaften / C ++ / Codegenerierung / C ++ - Ausnahmen aktivieren aktivieren , wie in der Antwort von Volodymyr Frytskyy erwähnt .
Schritt 2 ) Aufruf _set_se_translator()
, in einem Funktionszeiger Passing (oder Lambda) für den neuen Ausnahmesetzer . Es wird als Übersetzer bezeichnet, da es im Grunde genommen nur die Ausnahme auf niedriger Ebene nimmt und sie erneut als etwas abfängt, das leichter zu fangen ist, wie zum Beispiel :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 ) Fangen Sie die Ausnahme wie gewohnt ab:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
Diese Art von Situation ist implementierungsabhängig und erfordert folglich einen herstellerspezifischen Mechanismus, um zu fangen. Bei Microsoft handelt es sich um SEH und bei * nix um ein Signal
Im Allgemeinen ist es jedoch eine sehr schlechte Idee , eine Ausnahme für Zugriffsverletzungen abzufangen . Es gibt fast keine Möglichkeit, sich von einer AV-Ausnahme zu erholen. Wenn Sie dies versuchen, wird es nur schwieriger, Fehler in Ihrem Programm zu finden.
Wie bereits erwähnt, gibt es auf der Windows-Plattform keine Möglichkeit, dies von Nicht-Microsoft- / Compiler-Anbietern zu tun. Es ist jedoch offensichtlich nützlich, diese Arten von Ausnahmen auf die normale try {} catch (Ausnahme ex) {} -Methode abzufangen, um Fehler zu melden und Ihre App ordnungsgemäß zu beenden (wie JaredPar sagt, ist die App jetzt wahrscheinlich in Schwierigkeiten). . Wir verwenden _se_translator_function in einem einfachen Klassen-Wrapper, 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:
Nicht der Ausnahmebehandlungsmechanismus, aber Sie können den signal () -Mechanismus verwenden, der vom C bereitgestellt wird.
> man signal
11 SIGSEGV create core image segmentation violation
Das Schreiben in einen NULL-Zeiger wird wahrscheinlich ein SIGSEGV-Signal verursachen
signal()
ist Teil des Posix-Standards. Windows implementiert den Posix-Standard (wie auch Linux und Unix)
Eine solche Verletzung bedeutet, dass etwas ernsthaft mit dem Code nicht stimmt und unzuverlässig ist. Ich kann sehen, dass ein Programm möglicherweise versuchen möchte, die Daten des Benutzers so zu speichern, dass man hofft, dass sie nicht über vorherige Daten schreiben, in der Hoffnung, dass die Daten des Benutzers nicht bereits beschädigt sind, aber es gibt per Definition keine Standardmethode mit undefiniertem Verhalten umzugehen.