100 votes

Attraper les exceptions de violation d'accès ?

Exemple

int *ptr;
*ptr = 1000;

Puis-je attraper une exception de violation d'accès à la mémoire en utilisant le C++ standard sans utiliser de logiciel spécifique à Microsoft ?

116voto

Lisez-le et pleurez !

J'ai compris. Si tu ne lances pas le gestionnaire, le gestionnaire continuera et l'exception aussi.

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

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

}

72voto

Il existe un moyen très simple d'attraper n'importe quel type d'exception (division par zéro, violation d'accès, etc.) en Visual Studio en utilisant le bloc try -> catch (...). Une petite modification des paramètres du projet est suffisante. Il suffit d'activer l'option /EHa dans les paramètres du projet. Voir Project Properties -> C/C++ -> Code Generation -> Modifier l'option Enable C++ Exceptions en "Yes With SEH Exceptions". . C'est ça !

Voir les détails ici : https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160

0 votes

Cette valeur de paramètre n'existe pas dans Visual Studio .NET 2003, il n'y a que "No" et "Yes (/EHsc)". Pouvez-vous préciser de quelle version minimale de Visual Studio vous avez besoin pour pouvoir activer ce paramètre ?

0 votes

Le lien semble spécifier "Visual Studio 2005".

2 votes

Et si avec gcc ou MinGW ?

46voto

unwind Points 181987

Nope. Le C++ ne lève pas d'exception lorsque vous faites quelque chose de mal, ce qui aurait un impact sur les performances. Les choses comme les violations d'accès ou les erreurs de division par zéro sont plutôt des exceptions "machine", plutôt que des choses au niveau du langage que vous pouvez attraper.

0 votes

Je sais qu'il s'agit d'exceptions HW, mais il existe des mots-clés spécifiques à Microsoft pour gérer cela (__try __except) ?

2 votes

@Ahmed : oui, mais si vous les utilisez, des choses "impossibles" peuvent se produire. Par exemple, certaines des déclarations après la ligne de code AV peut avoir déjà été exécutée, ou les déclarations avant l'AV n'ont pas été exécutées.

0 votes

Voir ma réponse ci-dessous pour savoir comment activer la gestion de telles exceptions en utilisant le bloc try...catch régulier en VC++.

14voto

Michael Points 1337

En tout cas pour moi, le signal(SIGSEGV ...) approche mentionnée dans une autre réponse ne fonctionne pas sur Win32 avec Visual C++ 2015 . Qu'est-ce que hizo pour moi, c'était d'utiliser _set_se_translator() trouvé dans eh.h . Cela fonctionne comme suit :

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

Étape 2 ) Appel _set_se_translator() en passant un pointeur de fonction (ou lambda) pour la nouvelle exception. traducteur . On l'appelle un traducteur parce qu'il prend l'exception de bas niveau et la renvoie sous une forme plus facile à attraper, par exemple 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 3 ) Attrapez l'exception comme vous le feriez normalement :

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

10voto

JaredPar Points 333733

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

En général, cependant, attraper une exception de violation d'accès est une très mauvaise idée. Il n'y a pratiquement aucun moyen de se remettre d'une exception AV et toute tentative en ce sens ne fera qu'entraîner des bogues plus difficiles à trouver dans votre programme.

1 votes

Votre conseil est donc de savoir quelle est la cause de l'exception AV, n'est-ce pas ?

4 votes

Absolument. Les AV sont représentatives d'un bug dans votre code et attraper l'exception ne fera que cacher le problème.

1 votes

Pour clarifier, la norme C++ fait une distinction entre undefined, unspecified, et implementation defined. Implementation defined signifie que l'implémentation doit spécifier ce qui se passe. Le code dans la question est indéfini, ce qui signifie que tout peut arriver, et être différent à chaque fois.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X