¿Capturar excepciones de violación de acceso?

10 minutos de lectura

Ejemplo

int *ptr;
*ptr = 1000;

¿Puedo detectar una excepción de violación de acceso a la memoria usando C++ estándar sin usar ningún programa específico de Microsoft?

¡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 sucede 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");

}

  • Buen consejo, especialmente porque __try/__except tampoco detectará AV.

    – Fabio Ceconello

    6 de abril de 2011 a las 16:32

  • Esto NO funciona en gcc pero sí en VC++ pero solo en la compilación “Depuración”. Todavía votando por una solución interesante. Se llamaría al controlador de señal, pero no se lanzaría la excepción.

    – Natalia Adams

    22/09/2013 a las 17:05

  • Eso no funciona portátil. Cuando se invoca un manejador de señales, el marco de pila y la manipulación de registros no son lo mismo que cuando se invoca un marco de pila de función normal (es posible que ni siquiera use la misma pila en algunos sistemas). Lo mejor que puede hacer es establecer una bandera para indicar que el controlador de señales se ha activado. Luego, en su código, pruebe esa bandera y tírela.

    – Martín York

    31 de julio de 2015 a las 15:57


  • Esto tiene una alta probabilidad de introducir un comportamiento indefinido. Para que esto funcione en POSIX, no debe haber pilas de señales alternativas (sigaltstack) instalado (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 maneje el mecanismo de desenrollado en sí mismo debe ser seguro para la señal.

    – mínimo máximo promedio

    25 de noviembre de 2017 a las 16:51


  • Si desea devolver el controlador predeterminado a la señal (SIGSEGV en este caso), use lo siguiente: signal(SIGSEGV, SIG_DFL);

    – kocica

    9 de agosto de 2018 a las 12:46


¿Capturar excepciones de violacion de acceso
Volodymyr Frytskyy

Hay una manera muy fácil de detectar cualquier tipo de excepción (división por cero, violación de acceso, etc.) en Estudio visual usando el bloque try -> catch (…) Un ajuste menor de la configuración del proyecto es suficiente. Simplemente habilite la opción /EHa en la configuración del proyecto. Ver Propiedades del proyecto -> C/C++ -> Generación de código -> Modificar Habilitar excepciones de C++ a “Sí con excepciones de SEH”. ¡Eso es todo!

Ver detalles aquí:
https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160

  • No existe tal valor de configuración en Visual Studio .NET 2003, solo hay “No” y “Sí (/EHsc)”. ¿Puede aclarar qué versión mínima de Visual Studio necesita para poder habilitar esta configuración?

    – izogfif

    28/07/2014 a las 17:30


  • El enlace parece especificar “Visual Studio 2005”

    –Drew Delano

    29 de julio de 2015 a las 22:37

  • ¿y si con gcc o MinGW?

    – usuario1024

    14 de agosto de 2018 a las 3:24

No. C ++ no lanza una excepción cuando hace algo mal, eso incurriría en un impacto en el rendimiento. Cosas como infracciones de acceso o errores de división por cero son más como excepciones de “máquina”, en lugar de cosas de nivel de idioma que puede detectar.

  • Sé que son excepciones de HW, pero hay palabras clave específicas de Microsoft que manejan esto (__intentar __excepto)?

    – Ahmed

    19 de enero de 2009 a las 13:35

  • @Ahmed: sí, pero si los usa, pueden suceder cosas ‘imposibles’. Por ejemplo, algunas de las afirmaciones después es posible que la línea de código AV ya se haya ejecutado, o que las declaraciones anteriores al AV no se hayan ejecutado.

    – Aarón

    19 de enero de 2009 a las 19:55

  • Vea mi respuesta a continuación sobre cómo habilitar el manejo de tales excepciones usando el bloque try… catch regular en VC++.

    – Volodymyr Frytskyy

    15/10/2013 a las 19:35

  • @Aaron, ¿puede dar más detalles sobre la parte de “suceden cosas imposibles”? ¿Se debe a las instrucciones de reordenación del compilador y/o de la CPU?

    – Weipeng L

    25/06/2018 a las 22:00

  • El sistema operativo subyacente a menudo proporcionará mecanismos para detectar tales problemas y no incurrirá en ningún costo, ya que la arquitectura de la CPU genera la excepción. Esto se evidencia por la forma en que los depuradores pueden atrapar excepciones para permitirle depurar, sin ralentizar la ejecución del código.

    – Dino Dini

    30 de marzo de 2019 a las 11:13


¿Capturar excepciones de violacion de acceso
Miguel

Al menos para mí, la signal(SIGSEGV ...) enfoque mencionado en otra respuesta no funcionó en Win32 con Visual C++ 2015. Qué hizo el trabajo para mí era 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 de C++como se menciona en la respuesta de Volodymyr Frytskyy.

Paso 2) Llamada _set_se_translator()pasando un puntero de función (o lambda) para la nueva excepción traductor. 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 capturar, 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) Captura la excepción como lo harías 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 interceptar. Con Microsoft, esto involucrará a SEH, y *nix involucrará una señal

En general, aunque la captura de 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 conducirá a errores más difíciles de encontrar en su programa.

  • Entonces, su consejo es saber cuál es la causa de la excepción AV, ¿no es así?

    – Ahmed

    19 de enero de 2009 a las 13:37

  • Absolutamente. Los AV son representativos de un error en su código y detectar la excepción solo ocultará el problema.

    – JaredPar

    19 de enero de 2009 a las 13:59

  • Para aclarar, el estándar C++ hace una distinción entre no definido, no especificado y definido por la implementación. Implementación definida significa que la implementación debe especificar lo que sucede. El código en la pregunta no está definido, lo que significa que cualquier cosa puede pasar y ser diferente cada vez.

    – KeithB

    19 de enero de 2009 a las 14:27

  • Detectar una infracción de acceso no es una mala idea, es bueno para la experiencia del usuario. Sin embargo, lo único significativo que hago en este caso es generar otro proceso con la GUI de informe de errores e intentar crear un volcado de proceso actual. La generación de un proceso siempre es una operación exitosa. Luego, hago TerminateProcess() para suicidarme.

    – Петър Петров

    11/09/2013 a las 15:34

  • Es una mala idea capturar una excepción e ignorarla silenciosamente. Es una muy buena idea, cuando sea posible, detectar una excepción y registrar información sobre el estado de la aplicación con fines de diagnóstico. Una vez escribí una interfaz de usuario para una biblioteca de gráficos back-end que necesitaba algo de depuración. Cada vez que fallaba, la gente acudía a mí porque sabían que yo escribí la interfaz de usuario. Puse una trampa de firmas alrededor del backend que apareció una alerta que le decía al usuario que la biblioteca colapsó. La gente empezó a ir al autor de la biblioteca.

    – Kent

    4 de noviembre de 2014 a las 1:32

1646961312 851 ¿Capturar excepciones de violacion de acceso
Damián

Como se indicó, no existe una forma que no sea de Microsoft / proveedor de compiladores para hacer esto en la plataforma de Windows. Sin embargo, obviamente es útil detectar este tipo de excepciones en la forma normal de intento { } captura (excepción ex) { } para informar errores y más una salida elegante de su aplicación (como dice JaredPar, la aplicación ahora probablemente esté en problemas) . Usamos _se_translator_function en un contenedor de clase simple que nos permite detectar 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 vino de este artículo muy útil:

http://www.codeproject.com/KB/cpp/exception.aspx

  • Entonces, su consejo es saber cuál es la causa de la excepción AV, ¿no es así?

    – Ahmed

    19 de enero de 2009 a las 13:37

  • Absolutamente. Los AV son representativos de un error en su código y detectar la excepción solo ocultará el problema.

    – JaredPar

    19 de enero de 2009 a las 13:59

  • Para aclarar, el estándar C++ hace una distinción entre no definido, no especificado y definido por la implementación. Implementación definida significa que la implementación debe especificar lo que sucede. El código en la pregunta no está definido, lo que significa que cualquier cosa puede pasar y ser diferente cada vez.

    – KeithB

    19 de enero de 2009 a las 14:27

  • Detectar una infracción de acceso no es una mala idea, es bueno para la experiencia del usuario. Sin embargo, lo único significativo que hago en este caso es generar otro proceso con la GUI de informe de errores e intentar crear un volcado de proceso actual. La generación de un proceso siempre es una operación exitosa. Luego, hago TerminateProcess() para suicidarme.

    – Петър Петров

    11/09/2013 a las 15:34

  • Es una mala idea capturar una excepción e ignorarla silenciosamente. Es una muy buena idea, cuando sea posible, detectar una excepción y registrar información sobre el estado de la aplicación con fines de diagnóstico. Una vez escribí una interfaz de usuario para una biblioteca de gráficos back-end que necesitaba algo de depuración. Cada vez que fallaba, la gente acudía a mí porque sabían que yo escribí la interfaz de usuario. Puse una trampa de firmas alrededor del backend que apareció una alerta que le decía al usuario que la biblioteca colapsó. La gente empezó a ir al autor de la biblioteca.

    – Kent

    4 de noviembre de 2014 a las 1:32

1646961313 307 ¿Capturar excepciones de violacion de acceso
martín york

No es el mecanismo de manejo de excepciones, pero puede usar el mecanismo de señal () que proporciona C.

> man signal

     11    SIGSEGV      create core image    segmentation violation

Escribir en un puntero NULL probablemente provocará una señal SIGSEGV

  • @maidamai signal() es parte del estándar posix. Windows implementa el estándar posix (al igual que Linux y Unix)

    – Martín York

    23 de julio de 2019 a las 7:45

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad