2008-11-26 16 views
8

¿Cómo se obtiene el nombre y/o descripción de una excepción SEHsin teniendo que codificar las cadenas en su aplicación?¿Cómo obtener el nombre/descripción de una excepción?

He intentado utilizar FormatMessage(), pero trunca el mensaje a veces, incluso si se especifica ignorar inserciones:

__asm { // raise access violation 
    xor eax, eax 
    mov eax, [eax] 
} 

genera una excepción con el código 0xC0000005 (EXCEPTION_ACCESS_VIOLATION).

char msg[256]; 
FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, 
    GetModuleHandleA("ntdll.dll"), 0xC0000005, 
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
    msg, sizeof(msg), NULL); 

Rellena msg con la cadena truncada: "The instruction at 0x".

+0

Guau, esto realmente parece roto. Funciona para varios mensajes, pero no puedo hacer que funcione para STATUS_ACCESS_VIOLATION por mi vida. – Charlie

+0

Estoy un poco oxidado con esto ahora, pero ¿has probado FORMAT_MESSAGE_FROM_SYSTEM? – morechilli

+0

morechilli: Sí, ya lo intenté, pero no cambia el resultado. – Sascha

Respuesta

2

códigos estructurado de excepciones se definen a través de números NTSTATUS. Aunque alguien de MS suggests usando FormatMessage() para convertir números NTSTATUS en cadenas, yo no haría esto. La bandera FORMAT_MESSAGE_FROM_SYSTEM se usa para convertir el resultado de GetLastError() en una cadena, por lo que no tiene sentido aquí. El uso del indicador FORMAT_MESSAGE_FROM_HMODULE junto con ntdll.dll dará resultados incorrectos para algunos códigos. Por ejemplo, para EXCEPTION_ACCESS_VIOLATION obtendrá The instruction at 0x, que no es muy informativo :).

Cuando nos fijamos en las cadenas de caracteres que se almacenan en ntdll.dll se hace evidente que muchos de ellos se supone que se utiliza con la función printf(), no con el FormatMessage(). Por ejemplo, la cadena de EXCEPTION_ACCESS_VIOLATION es:

The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

%0 se trata por FormatMessage() como la secuencia de escape que significa mensaje terminador, no un inserto. Las inserciones son% 1 a% 99. Es por eso que flag FORMAT_MESSAGE_IGNORE_INSERTS no hace ninguna diferencia.

Es posible que desee cargar la cadena de ntdll.dll y pasarlo a vprintf pero se necesita para preparar argumentos exactamente como está previsto por la cadena (por ejemplo, para EXCEPTION_ACCESS_VIOLATION es unsigned long, unsigned long, char*). Y este enfoque tiene un gran inconveniente: cualquier cambio en el número, orden o tamaño de los argumentos en ntdll.dll puede romper su código.

Por lo tanto, es más seguro y fácil codificar las cadenas en su propio código. Me parece peligroso usar cadenas preparadas por otra persona sin coordinación conmigo :) y, además, para otra función. Esta es solo una posibilidad más de mal funcionamiento.

+0

Esto está tan roto, pero es demasiado tarde para cambiar. – davidbak

+0

@davidbak ¿Qué está roto? – 4LegsDrivenCat

+1

Que tenían inicialmente todas las oportunidades (cuando se creó NT) para crear estas cadenas de registro de eventos apropiadas (formato de estilo% 1) y en su lugar las imprimieron en cadenas de formato. Y luego nunca proporcionaron un sustituto. Debe haber cientos de programas, si no miles, que tienen un código especial para formatear los AV con fines de registro. – davidbak

Cuestiones relacionadas