Manejo estructurado de excepciones

El manejo estructurado de excepciones ( SEH  - Structured Exception Handling ) es un mecanismo para manejar excepciones de software y hardware en el sistema operativo Microsoft Windows que permite a los programadores controlar el manejo de excepciones y también es una herramienta de depuración [1] .

Excepciones y manejo de excepciones

Una excepción es un evento durante la ejecución del programa que hace que se comporte de manera anormal o incorrecta. Hay dos tipos de excepciones: hardware, que son generadas por el procesador , y software, generado por el sistema operativo y los programas de aplicación . El mecanismo estructurado de manejo de excepciones le permite manejar las excepciones de software y hardware de la misma manera.

Implementación

Palabras clave

Microsoft solo admite el mecanismo en el nivel del compilador a través de la implementación de construcciones de sintaxis no __tryestándar __excepty __finally. La palabra clave se __tryusa para resaltar una sección de código en la que el lanzamiento de una excepción será manejado por uno o más bloques __except. El código en el bloque __finallysiempre se ejecutará independientemente de otros bloques __tryy __except[2] .

Ejemplo de uso en C y C++

__intentar { // código protegido, // que se coloca en un marco SEH } __excepto ( filtro de excepción ) { // manejador de excepciones } __ finalmente { // código para ejecutar de todos modos }

Los filtros de excepción pueden ser funciones ordinarias que devuelven tres expresiones constantes: [3]

  • EXCEPTION_EXECUTE_HANDLER - indica la capacidad de este controlador para manejar la excepción. Al recibir dicho valor, el sistema operativo deja de buscar controladores de excepción relevantes y, después de desenrollar la pila, transfiere el control al primero que devolvió EXCEPTION_EXECUTE_HANDLER

  • EXCEPTION_CONTINUE_EXECUTION - indica una corrección de errores. El sistema volverá a transferir el control a la instrucción que lanzó la excepción, porque se espera que esta vez no lance una excepción. [cuatro]
  • EXCEPTION_CONTINUE_SEARCH - indica que se puede encontrar un controlador adecuado más arriba en la pila. Al mismo tiempo, devolver este valor puede indicar que el error no se ha manejado. [3]

Estructuras y mecanismos utilizados

Cada subproceso en cualquier proceso utiliza un registro ( selector de 16 bits ) fspara almacenar un puntero a una estructura de datos de bloque de información de subprocesos que contiene información sobre ese subproceso. Esta estructura almacena un puntero a la última estructura _EXCEPTION_REGISTRATION_RECORD registrada en la lista vinculada , que incluye un puntero al controlador de excepciones y un puntero a la entrada _EXCEPTION_REGISTRATION_RECORD anterior . [5] Cuando se crea un subproceso, el sistema operativo agrega un controlador de excepciones predeterminado llamado por . kernel32!UnhandledExceptionFilter

El prototipo de la función del controlador de devolución de llamada es el siguiente:

EXCEPCIÓN_DISPOSICIÓN __cdecl _excepto_controlador ( estructura _EXCEPTION_RECORD * Registro de excepción , vacío * EstablecimientoMarco , struct_CONTEXT * ContextRecord , _ vacío * DispatcherContext );

Cada vez que el programador usa la construcción , se agrega a la pila__try del subproceso una nueva instancia de la estructura _EXCEPTION_REGISTRATION_RECORD, que apunta a la función _except_handler3 de la biblioteca msvcrt.dll . El código de bloque se llama desde _except_handler3. Al final del bloque , el compilador agrega código que elimina la entrada _EXCEPTION_REGISTRATION_RECORD actual y restaura el valor del puntero a la entrada anterior. __except__finally__tryfs:0

Cuando ocurre una excepción, el sistema itera a través de toda la cadena de controladores de interrupción en secuencia. Cada controlador devuelve un valor que indica si puede manejar esta excepción o no. El puntero al final de la lista de controladores de excepciones disponibles es el valor FFFFFFFFubicado en la pila después del último controlador. Si el sistema encuentra el controlador deseado, se le transfiere el control. Al mismo tiempo, después de encontrar el controlador relevante para la excepción que ha surgido, el sistema operativo no le transfiere el control de inmediato, sino que una vez más llama secuencialmente a todos los controladores a lo largo de la cadena con la bandera EH_UNWINDINGpara limpiar (llamar al destructor ) . [4] Si ninguno de los filtros del controlador de excepciones establecido por el programador devolvió EXCEPTION_EXECUTE_HANDLER o EXCEPTION_CONTINUE_EXECUTION, entonces se ejecuta el UnhandledExceptionFilter filtro del controlador de excepciones predeterminado, que se registra cuando el subproceso se prepara para ejecutarse.

Llamada al controlador

Cuando ocurre una excepción, el sistema operativo no llama directamente al filtro de excepciones (que es responsable de si un controlador en particular manejará o no la excepción que ha ocurrido), sino que pasa su dirección a la función _except_handler3, desde donde se llama a la función de filtro. . Utiliza la siguiente estructura de datos: [6]

estructura _EXCEPCIÓN_REGISTRO { estructura _EXCEPCIÓN_REGISTRO * anterior ; vacío ( * controlador )( PEXCEPTION_RECORD , PEXCEPTION_REGISTRO , PCONTEXTO , PEXCEPCIÓN_REGISTRO ); struct scopetable_entry * scopetable ; int nivel de prueba ; int_ebp ; _ PEXCEPTION_POINTERS punteros x ; };

El campo *scopetableapunta a la dirección de una matriz de estructuras scopetable_entryy el campo entero de nivel de prueba apunta a un índice en esta matriz. El campo _ebpcontiene el valor del puntero del marco de pila que existía antes de la creación de la estructura EXCEPTION_REGISTRATION. [7] La ​​función _except_handler3llama al filtro requerido y, antes de llamar al controlador, desenrolla (limpia) la pila mediante la función ntdll.dll!RtlUnwind.

Si ninguno de los controladores instalados por el programador aceptó manejar la excepción, se llama a una función UnhandledExceptionFilterque verifica si el proceso se está ejecutando bajo el depurador y le informa si está disponible. [7] A continuación, la función llama al filtro de controlador predeterminado (que establece la función SetUnhandledExceptionFiltery que siempre devuelve EXCEPTION_EXECUTE_HANDLER). [7] Luego, según la configuración del sistema operativo, se llama al depurador o a la función NtRaiseHardError, que muestra un mensaje de error. [7]

Notas

  1. Manejo estructurado de excepciones (Windows) . Consultado el 5 de mayo de 2010. Archivado desde el original el 25 de septiembre de 2010.
  2. Acerca del manejo estructurado de excepciones (Windows) . Consultado el 5 de mayo de 2010. Archivado desde el original el 28 de febrero de 2011.
  3. 1 2 Introducción al manejo estructurado de excepciones de SEH (enlace muerto) . Fecha de acceso: 26 de diciembre de 2012. Archivado desde el original el 27 de marzo de 2014. 
  4. 1 2 WASM.IN Win32 SEH Inside (Parte 1) . Consultado el 5 de abril de 2018. Archivado desde el original el 5 de abril de 2018.
  5. Operando SEH en un entorno Win32 . Consultado el 1 de mayo de 2010. Archivado desde el original el 24 de septiembre de 2015.
  6. WASM.IN Win32 SEH desde el interior (parte 2) . Consultado el 5 de abril de 2018. Archivado desde el original el 5 de abril de 2018.
  7. 1 2 3 4 WASM.IN Win32 SEH desde el interior (parte 3) . Consultado el 5 de abril de 2018. Archivado desde el original el 5 de abril de 2018.