web-dev-qa-db-fra.com

Attraper les exceptions de violation d'accès?

Exemple

int *ptr;
*ptr = 1000;

puis-je intercepter une exception de violation d'accès à la mémoire en utilisant C++ standard sans utiliser de Microsoft spécifique.

80
Ahmed Said

Nan. C++ ne lève pas d'exception lorsque vous faites quelque chose de mal, ce qui entraînerait un impact sur les performances. Des choses comme les violations d'accès ou la division par zéro erreurs ressemblent plus à des exceptions "machine", plutôt qu'à des choses de niveau linguistique que vous pouvez intercepter.

36
unwind

Lit ça et pleure!

Je l'ai compris. Si vous ne lancez pas à partir du gestionnaire, le gestionnaire continuera simplement, de même que l'exception.

La magie se produit lorsque vous lancez votre propre exception et gérez cela.

#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");

}
102
Juxta

Il existe un moyen très simple de détecter tout type d'exception (division par zéro, violation d'accès, etc.) dans Visual Studio en utilisant try -> catch ( ...) bloquer. Une modification mineure des paramètres du projet suffit. Activez simplement l'option/EHa dans les paramètres du projet. Voir Propriétés du projet -> C/C++ -> Génération de code -> Modifiez les Activer les exceptions C++ en "Oui avec les exceptions SEH" . C'est ça!

Voir les détails ici: http://msdn.Microsoft.com/en-us/library/1deeycx5 (v = vs.80) .aspx

63
Volodymyr Frytskyy

Ce type de situation dépend de l'implémentation et, par conséquent, il faudra un mécanisme spécifique au fournisseur pour être piégé. Avec Microsoft, cela impliquera SEH, et * nix impliquera un signal

En général, cependant, intercepter une exception de violation d'accès est une très mauvaise idée. Il n'y a presque aucun moyen de récupérer d'une exception AV et tenter de le faire entraînera simplement des difficultés pour trouver les bogues dans votre programme.

8
JaredPar

Au moins pour moi, l'approche signal(SIGSEGV ...) mentionnée dans une autre réponse ne fonctionnait pas sur Win32 avec Visual C++ 2015. Ce que a fait pour moi était d'utiliser _set_se_translator() trouvée dans eh.h. Cela fonctionne comme ceci:

Étape 1) Assurez-vous d'activer Oui avec les exceptions SEH (/ EHa) dans Propriétés du projet/C++/Génération de code/Activer les exceptions C++ , comme mentionné dans la réponse de Volodymyr Frytskyy .

Étape 2) Appelez _set_se_translator(), en passant un pointeur de fonction (ou lambda) pour le nouveau traducteur d'exception . Il est appelé un traducteur, car il prend simplement l'exception de bas niveau et la renvoie comme quelque chose de plus facile à attraper, comme 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());
});

Étape) Saisissez l'exception comme vous le feriez normalement:

try{
    MakeAnException();
}
catch(std::exception ex){
    HandleIt();
};
7
Michael

Comme indiqué, il n'existe aucun moyen non Microsoft/fournisseur de compilateur de le faire sur la plate-forme Windows. Cependant, il est évidemment utile d'attraper ces types d'exceptions de la manière normale try {} catch (exception ex) {} pour le rapport d'erreurs et plus une sortie gracieuse de votre application (comme le dit JaredPar, l'application est maintenant probablement en difficulté) . Nous utilisons _se_translator_function dans un wrapper de classe simple qui nous permet d'attraper les exceptions suivantes dans un gestionnaire try:

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 classe d'origine est issue de cet article très utile:

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

7
Damien

Pas le mécanisme de gestion des exceptions, mais vous pouvez utiliser le mécanisme signal () fourni par le C.

> man signal

     11    SIGSEGV      create core image    segmentation violation

L'écriture sur un pointeur NULL va probablement provoquer un signal SIGSEGV

3
Martin York