Ejemplo
int *ptr;
*ptr = 1000;
¿Puedo detectar una excepción de infracción de acceso a la memoria usando C ++ estándar sin usar ningún microsoft específico?
Ejemplo
int *ptr;
*ptr = 1000;
¿Puedo detectar una excepción de infracción de acceso a la memoria usando C ++ estándar sin usar ningún microsoft específico?
Respuestas:
¡No! C ++ no lanza una excepción cuando haces algo malo, que incurriría en un impacto en el rendimiento. Cosas como las infracciones de acceso o la división por errores cero son más como excepciones de "máquina", en lugar de cosas a nivel de idioma que puede detectar.
¡Léelo y llora!
Me lo imaginé. Si no lanza desde el controlador, el controlador simplemente continuará y también lo hará la excepción.
La magia ocurre cuando lanzas tu propia excepción y manejas eso.
#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
) instalada (a menos que la implementación de desenrollado de excepción de C ++ lo permita), y cada función de tiempo de ejecución que maneja el mecanismo de desenrollado debe ser segura para señales.
signal(SIGSEGV, SIG_DFL);
Hay una manera muy fácil de detectar cualquier tipo de excepción (división por cero, violación de acceso, etc.) en Visual Studio usando el bloque try -> catch (...). Un pequeño ajuste de la configuración del proyecto es suficiente. Simplemente habilite la opción / EHa en la configuración del proyecto. Consulte Propiedades del proyecto -> C / C ++ -> Generación de código -> Modifique Habilitar excepciones C ++ a "Sí con excepciones SEH" . ¡Eso es!
Vea los detalles aquí: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx
Al menos para mí, el signal(SIGSEGV ...)
enfoque mencionado en otra respuesta no funcionó en Win32 con Visual C ++ 2015 . Lo que funcionó para mí fue usar _set_se_translator()
encontrado en eh.h
. Funciona así:
Paso 1 ) Asegúrese de habilitar Sí con excepciones SEH (/ EHa) en Propiedades del proyecto / C ++ / Generación de código / Habilitar excepciones C ++ , como se menciona en la respuesta de Volodymyr Frytskyy .
Paso 2 ) Llame _set_se_translator()
, pasando un puntero de función (o lambda) para el nuevo traductor de excepciones . Se llama traductor porque básicamente solo toma la excepción de bajo nivel y la vuelve a lanzar como algo más fácil de atrapar, como 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());
});
Paso 3 ) Capture la excepción como lo haría normalmente:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
Este tipo de situación depende de la implementación y, en consecuencia, requerirá un mecanismo específico del proveedor para realizar la captura. Con Microsoft esto involucrará SEH, y * nix involucrará una señal
En general, detectar una excepción de infracción de acceso es una muy mala idea. Casi no hay forma de recuperarse de una excepción de AV e intentar hacerlo solo hará que sea más difícil encontrar errores en su programa.
Como se indicó, no existe una forma que no sea de Microsoft / proveedor de compiladores para hacer esto en la plataforma Windows. Sin embargo, obviamente es útil detectar este tipo de excepciones de la manera normal try {} catch (excepción ex) {} para informar de errores y más una salida elegante de su aplicación (como dice JaredPar, la aplicación ahora probablemente tenga problemas) . Usamos _se_translator_function en un contenedor de clase simple que nos permite capturar las siguientes excepciones en un controlador de prueba:
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)
La clase original provino de este artículo muy útil:
No es el mecanismo de manejo de excepciones, pero puede usar el mecanismo signal () proporcionado por C.
> man signal
11 SIGSEGV create core image segmentation violation
Escribir en un puntero NULL probablemente provocará una señal SIGSEGV
signal()
es parte del estándar posix. Windows implementa el estándar posix (al igual que Linux y Unix)
Una infracción como esa significa que hay algo muy mal con el código y no es confiable. Puedo ver que un programa puede querer intentar guardar los datos del usuario de una manera que uno espera que no se escriban sobre los datos anteriores, con la esperanza de que los datos del usuario no estén ya corruptos, pero por definición no existe un método estándar. de lidiar con un comportamiento indefinido.