C # intercepte une exception de dépassement de stack

J’ai reçu un appel récursif à une méthode qui lance une exception de dépassement de stack. Le premier appel est entouré d’un bloc try catch mais l’exception n’est pas interceptée.

L’exception de débordement de stack se comporte-t-elle d’une manière particulière? Puis-je attraper / manipuler correctement l’exception?

NB: le cas échéant:

  • l’exception n’est pas lancée dans le thread principal

  • l’object où le code lance l’exception est chargé manuellement par Assembly.LoadFrom (…). CreateInstance (…)

À partir de la version 2.0, une exception StackOverflow ne peut être interceptée que dans les cas suivants.

  1. Le CLR est exécuté dans un environnement hébergé où l’hôte autorise spécifiquement le traitement des exceptions StackOverflow
  2. L’exception stackoverflow est renvoyée par le code utilisateur et non par une situation de débordement de stack réelle ( référence )

Le bon moyen est de corriger le débordement, mais ….

Vous pouvez vous donner une plus grande stack: –

 using System.Threading; Thread T = new Thread(threadDelegate, stackSizeInBytes); T.Start(); 

Vous pouvez utiliser la propriété System.Diagnostics.StackTrace FrameCount pour compter les frameworks que vous avez utilisés et générer votre propre exception lorsqu’une limite de cadre est atteinte.

Ou, vous pouvez calculer la taille de la stack restante et lancer votre propre exception lorsqu’elle tombe en dessous d’un seuil: –

 class Program { static int n; static int topOfStack; const int stackSize = 1000000; // Default? // The func is 76 bytes, but we need space to unwind the exception. const int spaceRequired = 18*1024; unsafe static void Main(ssortingng[] args) { int var; topOfStack = (int)&var; n=0; recurse(); } unsafe static void recurse() { int remaining; remaining = stackSize - (topOfStack - (int)&remaining); if (remaining < spaceRequired) throw new Exception("Cheese"); n++; recurse(); } } 

Attrape juste le fromage. 😉

De la page MSDN sur StackOverflowException s:

Dans les versions antérieures du .NET Framework, votre application pouvait intercepter un object StackOverflowException (par exemple, pour récupérer d’une récursivité illimitée). Cependant, cette pratique est actuellement déconseillée, car un code supplémentaire important est requirejs pour intercepter de manière fiable une exception de dépassement de capacité de la stack et poursuivre l’exécution du programme.

À partir de .NET Framework version 2.0, un object StackOverflowException ne peut pas être intercepté par un bloc try-catch et le processus correspondant est arrêté par défaut. Par conséquent, les utilisateurs sont invités à écrire leur code pour détecter et empêcher un débordement de stack. Par exemple, si votre application dépend de la récursivité, utilisez un compteur ou une condition d’état pour terminer la boucle récursive. Notez qu’une application qui héberge le CLR (Common Language Runtime) peut spécifier que le CLR décharge le domaine d’application où se produit l’exception de dépassement de capacité de la stack et laisse le processus correspondant se poursuivre. Pour plus d’informations, voir Interface ICLRPolicyManager et Hébergement du Common Language Runtime.

Comme plusieurs utilisateurs l’ont déjà dit, vous ne pouvez pas intercepter l’exception. Cependant, si vous avez du mal à savoir où cela se produit, vous pouvez configurer Visual Studio pour qu’il se brise au lancement.

Pour ce faire, vous devez ouvrir les parameters d’exception à partir du menu “Débogage”. Dans les anciennes versions de Visual Studio, il s’agit de ‘Debug’ – ‘Exceptions’; dans les nouvelles versions, c’est à ‘Debug’ – ‘Windows’ – ‘Exception Settings’.

Une fois les parameters ouverts, développez «Exceptions Common Language Runtime», développez «System», faites défiler et cochez «System.StackOverflowException». Ensuite, vous pouvez regarder la stack d’appels et rechercher le motif récurrent d’appels. Cela devrait vous donner une idée de l’endroit où chercher pour corriger le code à l’origine du débordement de la stack.

Comme mentionné ci-dessus à plusieurs resockets, il n’est pas possible d’attraper une StackOverflowException qui a été déclenchée par le système en raison d’un état de processus corrompu. Mais il existe un moyen de noter l’exception en tant qu’événement:

http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

À partir de .NET Framework version 4, cet événement n’est pas déclenché pour les exceptions qui altèrent l’état du processus, telles que les dépassements de stack ou les violations d’access, à moins que l’atsortingbut HandleProcessCorruptedStateExceptionsAtsortingbute ne soit critique pour la sécurité.

Néanmoins, votre application se terminera après avoir quitté la fonction événement (une solution de contournement TRES sale consistait à redémarrer l’application dans cet événement haha, mais cela n’a jamais été fait et ne le fera jamais). Mais c’est assez bon pour l’enregistrement!

Dans les versions 1.0 et 1.1 du .NET Framework, une exception non gérée qui se produit dans un thread autre que le thread principal de l’application est interceptée par le runtime et ne provoque donc pas l’arrêt de l’application. Ainsi, il est possible que l’événement UnhandledException soit déclenché sans que l’application se termine. À partir de .NET Framework version 2.0, ce backstop pour les exceptions non gérées dans les threads enfants a été supprimé, car l’effet cumulatif de ces échecs silencieux comprenait la dégradation des performances, des données corrompues et des blocages difficiles à déboguer. Pour plus d’informations, y compris une liste des cas dans lesquels le moteur d’exécution ne se termine pas, consultez Exceptions dans les threads gérés.

Oui, le dépassement de capacité de la stack CLR 2.0 est considéré comme une situation irrécupérable. Ainsi, le runtime ferme toujours le processus.

Pour plus d’informations, consultez la documentation http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx

Vous ne pouvez pas Le CLR ne vous laissera pas faire. Un dépassement de stack est une erreur fatale et ne peut pas être récupéré.

Vous ne pouvez pas comme la plupart des messages expliquent, laissez-moi append un autre domaine:

Sur de nombreux sites Web, vous constaterez que la manière d’éviter cela consiste à utiliser un AppDomain différent. Si cela se produit, le domaine sera déchargé. Cela est absolument faux (sauf si vous hébergez votre CLR), car le comportement par défaut du CLR déclenchera un événement KillProcess, entraînant la perte de votre AppDomain par défaut.

C’est impossible, et pour une bonne raison (pour un, pensez à tous ces catch (Exception) {}).

Si vous souhaitez continuer l’exécution après un débordement de stack, exécutez un code dangereux dans un AppDomain différent. Les règles CLR peuvent être définies pour mettre fin à AppDomain actuel en cas de dépassement de capacité sans affecter le domaine d’origine.