예
int *ptr;
*ptr = 1000;
Microsoft 특정을 사용하지 않고 표준 C ++를 사용하여 메모리 액세스 위반 예외를 포착 할 수 있습니까?
답변:
아니. C ++는 성능 저하를 초래할 수있는 나쁜 일을 할 때 예외를 발생시키지 않습니다. 액세스 위반 또는 0으로 나누기 오류와 같은 것은 포착 할 수있는 언어 수준의 것보다 "기계"예외에 가깝습니다.
그것을 읽고 울십시오!
나는 그것을 알아. 핸들러에서 던지지 않으면 핸들러는 계속되고 예외도 계속됩니다.
마법은 당신이 자신의 예외를 던지고 그것을 처리 할 때 발생합니다.
#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
)이 설치 되어서는 안되며 (C ++ 예외 해제 구현이 허용하지 않는 한) 해제 메커니즘 자체를 처리하는 모든 런타임 함수는 신호에 안전해야합니다.
signal(SIGSEGV, SIG_DFL);
try- > catch (...) 블록을 사용하여 Visual Studio 에서 모든 종류의 예외 (0으로 나누기, 액세스 위반 등)를 포착하는 매우 쉬운 방법이 있습니다. 사소한 프로젝트 설정 조정만으로도 충분합니다. 프로젝트 설정에서 / EHa 옵션을 활성화하기 만하면됩니다. 참조 프로젝트 속성 -> C / C ++ -> 코드 생성은 -> 수정은 "예 SEH 예외로"에 C ++ 예외를 활성화합니다 . 그게 다야!
자세한 내용은 http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx를 참조하십시오.
적어도 나에게는 signal(SIGSEGV ...)
다른 답변에서 언급 한 접근 방식 이 Visual C ++ 2015의 Win32에서 작동하지 않았습니다 . 무엇을 했던 나에 대한 작업은 사용하는 것이었다 _set_se_translator()
에서 발견 eh.h
. 다음과 같이 작동합니다.
1 단계 ) 활성화해야합니다 SEH 예외 (/ EHA)와 예 에서 C ++ 예외를 활성화 프로젝트 속성 / C ++ / 코드 생성 / 에 의해이 질문에 대해 언급 한 바와 같이, 볼로디미르 Frytskyy .
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();
};
이러한 유형의 상황은 구현에 따라 다르기 때문에 트랩을 위해 공급 업체별 메커니즘이 필요합니다. Microsoft에서는 SEH가 포함되고 * nix에는 신호가 포함됩니다.
일반적으로 액세스 위반 예외를 포착하는 것은 매우 나쁜 생각입니다. AV 예외에서 복구 할 수있는 방법은 거의 없으며 그렇게 시도하면 프로그램에서 버그를 찾기가 더 어려워집니다.
언급했듯이 Windows 플랫폼에서이 작업을 수행하는 비 Microsoft / 컴파일러 공급 업체 방법은 없습니다. 그러나 오류보고를위한 일반적인 try {} catch (예외 예) {} 방식으로 이러한 유형의 예외를 포착하고 앱을 더 우아하게 종료하는 것은 분명히 유용합니다 (JaredPar가 말했듯이 앱은 이제 문제가있을 수 있음). . 간단한 클래스 래퍼에서 _se_translator_function을 사용하여 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)
원래 수업은이 매우 유용한 기사에서 나왔습니다.
이와 같은 위반은 코드에 심각한 문제가 있으며 신뢰할 수 없음을 의미합니다. 프로그램이 사용자의 데이터가 이미 손상되지 않았 으면하는 바람에 이전 데이터를 덮어 쓰지 않기를 바라는 방식으로 사용자의 데이터를 저장하려고 할 수 있지만 정의상 표준 방법은 없습니다. 정의되지 않은 행동을 다루는 것.