Example
int *ptr;
*ptr = 1000;
can I catch memory access violation exception using standard C++ without using any microsoft specific.
Example
int *ptr;
*ptr = 1000;
can I catch memory access violation exception using standard C++ without using any microsoft specific.
Nope. C++ does not throw an exception when you do something bad, that would incur a performance hit. Things like access violations or division by zero errors are more like "machine" exceptions, rather than language-level things that you can catch.
Read it and weep!
I figured it out. If you don't throw from the handler, the handler will just continue and so will the exception.
The magic happens when you throw you own exception and handle that.
#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
) installed (unless the C++ exception unwinding implementation allows it), and every runtime function handling the unwinding mechanism itself should be signal-safe. –
Willable signal(SIGSEGV, SIG_DFL);
–
Citric There is a very easy way to catch any kind of exception (division by zero, access violation, etc.) in Visual Studio using try -> catch (...) block. A minor project settings tweaking is enough. Just enable /EHa option in the project settings. See Project Properties -> C/C++ -> Code Generation -> Modify the Enable C++ Exceptions to "Yes With SEH Exceptions". That's it!
See details here: https://learn.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160
Nope. C++ does not throw an exception when you do something bad, that would incur a performance hit. Things like access violations or division by zero errors are more like "machine" exceptions, rather than language-level things that you can catch.
At least for me, the signal(SIGSEGV ...)
approach mentioned in another answer did not work on Win32 with Visual C++ 2015. What did work for me was to use _set_se_translator()
found in eh.h
. It works like this:
Step 1) Make sure you enable Yes with SEH Exceptions (/EHa) in Project Properties / C++ / Code Generation / Enable C++ Exceptions, as mentioned in the answer by Volodymyr Frytskyy.
Step 2) Call _set_se_translator()
, passing in a function pointer (or lambda) for the new exception translator. It is called a translator because it basically just takes the low-level exception and re-throws it as something easier to catch, such as 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());
});
Step 3) Catch the exception like you normally would:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
This type of situation is implementation dependent and consequently it will require a vendor specific mechanism in order to trap. With Microsoft this will involve SEH, and *nix will involve a signal
In general though catching an Access Violation exception is a very bad idea. There is almost no way to recover from an AV exception and attempting to do so will just lead to harder to find bugs in your program.
catch
handler could do anything including spawning the dreaded nasal daemon and erase your hard drive. –
Dupuis As stated, there is no non Microsoft / compiler vendor way to do this on the windows platform. However, it is obviously useful to catch these types of exceptions in the normal try { } catch (exception ex) { } way for error reporting and more a graceful exit of your app (as JaredPar says, the app is now probably in trouble). We use _se_translator_function in a simple class wrapper that allows us to catch the following exceptions in a a try handler:
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)
The original class came from this very useful article:
Not the exception handling mechanism, But you can use the signal() mechanism that is provided by the C.
> man signal
11 SIGSEGV create core image segmentation violation
Writing to a NULL pointer is probably going to cause a SIGSEGV signal
signal()
is part of the posix standard. Windows implements the posix standard (as does Linux and unix) –
Eliathas Yes, all things are possible. Catching CPU exceptions (interrupts) (async exceptions) are possible. I have an example that catches NPE/AV, DivByZero, FPE, Stack Overflow. Tested with Windows and Linux. Unfortunately it does require some specific Windows API on Windows. The signal() function on Windows does not catch all hardware exceptions, and Windows does not support sigaction() yet.
/*
Test : Catching all hardware exceptions.
Windows : cl main.cpp
Linux : gcc -std=c++11 main.cpp -lstdc++ -lm
*/
#include <cstdio>
#include <cstdlib>
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <errhandlingapi.h>
#include <malloc.h>
#include <float.h>
#else
#include <signal.h>
#include <math.h>
#include <fenv.h>
#endif
#define count (16)
#define stack (4 * 1024)
extern "C" {
jmp_buf buf; //NOTE : this should be thread local in a multi-threaded app (and stored in a queue if nested try / catch blocks are used)
#ifdef _WIN32
bool was_stack_overflow = false; //NOTE : this should be thread local in a multi-threaded app
LONG exception_filter(_EXCEPTION_POINTERS *ExceptionInfo) {
was_stack_overflow = ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW;
longjmp(buf, 1);
return 0;
}
#else
void handler(int sig,siginfo_t *info, void *context) {
longjmp(buf, 1);
}
#endif
void func1(int z) {
printf("func1:%d\n", z);
}
void func1f(float z) {
printf("func1f:%f\n", z);
}
void func2(const char* msg, int z) {
printf("%s:%d\n", msg, z);
}
void func3() {
printf("done!\n");
}
int recursive(int val) {
int data[1024];
return recursive(val + 1);
}
//after a catch some cleanup is required
void after_catch() {
#ifdef _WIN32
if (was_stack_overflow) {
_resetstkoflw();
//see this website for explaination of _resetstkoflw() https://jeffpar.github.io/kbarchive/kb/315/Q315937/
}
#else
//on Linux need to re-enable FPEs after a longjmp()
feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
#endif
}
}
int main(int argc, const char **argv) {
int z = 0;
float fz = 0.0f;
#ifdef _WIN32
printf("Win32 setup\n");
SetUnhandledExceptionFilter(exception_filter);
//enable floating point exceptions
unsigned int control_word;
_controlfp_s(&control_word, _MCW_DN, 0xffff);
#else
printf("Linux setup\n");
stack_t altstack;
altstack.ss_sp = malloc(stack);
altstack.ss_flags = 0;
altstack.ss_size = stack;
sigaltstack(&altstack, NULL);
//NOTE : sigaltstack with SA_ONSTACK is required to catch stack overflows
struct sigaction act = { 0 };
act.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
act.sa_sigaction = &handler;
sigaction(SIGSEGV, &act,NULL);
sigaction(SIGFPE, &act,NULL);
// sigaction(SIGILL, &act,NULL);
//enable float point exceptions
feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
#endif
int jmp;
int cntr;
cntr=0;
for(int a=0;a<count;a++) {
jmp = setjmp(buf);
if (jmp == 0) {
// try : div by zero
int x = 123;
int y = 0;
z = x / y;
func1(z);
} else {
//catch block
after_catch();
cntr++;
}
}
func2("/0", cntr);
cntr=0;
for(int a=0;a<count;a++) {
jmp = setjmp(buf);
if (jmp == 0) {
//try : NPE
int *p = NULL;
*p = 0;
func1(z);
} else {
//catch block
after_catch();
cntr++;
}
}
func2("NPE", cntr);
cntr=0;
for(int a=0;a<count;a++) {
jmp = setjmp(buf);
if (jmp == 0) {
//try : FPE
float fx = 123.0f;
float fy = 0.0f;
fz = fx / fy;
func1f(fz);
} else {
//catch block
after_catch();
cntr++;
}
}
func2("FPE", cntr);
cntr=0;
for(int a=0;a<count;a++) {
jmp = setjmp(buf);
if (jmp == 0) {
//try : stack overflow
recursive(0);
func1(z);
} else {
//catch block
after_catch();
cntr++;
}
}
func2("StackOverflow", cntr);
func3();
return 0;
}
C++ Exceptions are "software" exceptions and would not catch these hardware exceptions. There is no "portable" way to achieve this yet. Hopefully the next C++ edition would add support to the standard try / catch but don't hold your breath.
Note : this solution using longjmp() which may cause memory leaks since dtors may not get called. Code inside try blocks should be very small. Was unable to reliably throw a C++ software exception in the handlers.
I think they are called 'async exceptions' because floating point exceptions occur on the floating point unit which runs parallel to the main CPU. An 'fwait' causes the CPU to wait for the FPU to finish processing.
Posting this here since other related questions redirect here.
Thanks,
A violation like that means that there's something seriously wrong with the code, and it's unreliable. I can see that a program might want to try to save the user's data in a way that one hopes won't write over previous data, in the hope that the user's data isn't already corrupted, but there is by definition no standard method of dealing with undefined behavior.
© 2022 - 2024 — McMap. All rights reserved.