Przykład
int *ptr;
*ptr = 1000;
czy mogę przechwycić wyjątek naruszenia dostępu do pamięci przy użyciu standardowego C ++ bez użycia jakichkolwiek specyficznych dla firmy Microsoft.
Przykład
int *ptr;
*ptr = 1000;
czy mogę przechwycić wyjątek naruszenia dostępu do pamięci przy użyciu standardowego C ++ bez użycia jakichkolwiek specyficznych dla firmy Microsoft.
Odpowiedzi:
Nie. C ++ nie zgłasza wyjątku, gdy robisz coś złego, co spowodowałoby spadek wydajności. Takie rzeczy jak naruszenia zasad dostępu lub błędy dzielenia przez zero są bardziej jak wyjątki „maszynowe”, a nie rzeczy na poziomie języka, które można wykryć.
Przeczytaj i płacz!
Rozgryzłem to. Jeśli nie wyrzucisz z handlera, handler będzie kontynuował, podobnie jak wyjątek.
Magia dzieje się, gdy rzucasz własny wyjątek i radzisz sobie z tym.
#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");
}
sigaltstackzainstalowane żadne alternatywne stosy sygnałów ( ) (chyba, że implementacja cofania wyjątku C ++ na to pozwala), a każda funkcja środowiska uruchomieniowego obsługująca sam mechanizm rozwijania powinna być bezpieczna dla sygnałów.
signal(SIGSEGV, SIG_DFL);
Istnieje bardzo łatwy sposób na wychwycenie dowolnego rodzaju wyjątku (dzielenie przez zero, naruszenie zasad dostępu itp.) W programie Visual Studio przy użyciu bloku try -> catch (...). Wystarczy drobna zmiana ustawień projektu. Po prostu włącz opcję / EHa w ustawieniach projektu. Zobacz Właściwości projektu -> C / C ++ -> Generowanie kodu -> Zmodyfikuj opcję Włącz wyjątki C ++ na „Tak z wyjątkami SEH” . Otóż to!
Zobacz szczegóły tutaj: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx
Przynajmniej dla mnie signal(SIGSEGV ...)podejście wymienione w innej odpowiedzi nie działało na Win32 z Visual C ++ 2015 . Co zrobiłem pracę dla mnie było wykorzystanie _set_se_translator()znaleźć w eh.h. Działa to tak:
Krok 1 ) Upewnij się, że włączyłeś Tak z SEH Exceptions (/ EHa) we właściwościach projektu / C ++ / Code Generation / Enable C ++ Exceptions , jak wspomniano w odpowiedzi Volodymyr Frytskyy .
Krok 2 ) Wywołaj _set_se_translator(), przekazując wskaźnik funkcji (lub lambda) dla nowego translatora wyjątków . Nazywa się to tłumaczem, ponieważ po prostu bierze wyjątek niskiego poziomu i ponownie rzuca go jako coś łatwiejszego do złapania, na przykład 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());
});
Krok 3 ) Złap wyjątek tak, jak zwykle:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
Tego typu sytuacja jest zależna od implementacji, w związku z czym pułapka będzie wymagała specjalnego mechanizmu dostawcy. W przypadku Microsoftu będzie to wiązało się z SEH, a * nix będzie wiązało się z sygnałem
Ogólnie jednak wyłapywanie wyjątku naruszenia zasad dostępu jest bardzo złym pomysłem. Nie ma prawie żadnego sposobu na odzyskanie po wyjątku AV, a próba wykonania tego spowoduje trudniejsze znalezienie błędów w programie.
Jak wspomniano, nie ma sposobu, w jaki producent inny niż Microsoft / kompilator może to zrobić na platformie Windows. Jednak ewidentnie przydatne jest wychwycenie tego typu wyjątków w normalny sposób try {} catch (wyjątek ex) {} do raportowania błędów i bardziej wdzięcznego wyjścia z aplikacji (jak mówi JaredPar, aplikacja prawdopodobnie ma teraz kłopoty) . Używamy _se_translator_function w prostym opakowaniu klasy, które pozwala nam wychwycić następujące wyjątki w obsłudze aa try:
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)
Oryginalna klasa pochodzi z tego bardzo przydatnego artykułu:
Nie mechanizm obsługi wyjątków, ale możesz użyć mechanizmu signal (), który jest udostępniany przez C.
> man signal
11 SIGSEGV create core image segmentation violation
Zapis do wskaźnika NULL prawdopodobnie spowoduje sygnał SIGSEGV
signal()jest częścią standardu POSIX . Windows implementuje standard POSIX (podobnie jak Linux i unix)
Takie naruszenie oznacza, że z kodem jest coś poważnego i jest on zawodny. Widzę, że program może chcieć spróbować zapisać dane użytkownika w sposób, który ma nadzieję, że nie zostanie zapisany na poprzednich danych, w nadziei, że dane użytkownika nie są już uszkodzone, ale z definicji nie ma standardowej metody radzenia sobie z niezdefiniowanym zachowaniem.