C # cattura un’eccezione di overflow dello stack

Ho ricevuto una chiamata ricorsiva a un metodo che genera un’eccezione di overflow dello stack. La prima chiamata è circondata da un blocco catch try ma l’eccezione non viene rilevata.

L’eccezione di overflow dello stack si comporta in modo particolare? Posso prendere / gestire correttamente l’eccezione?

NB: se rilevante:

A partire da 2.0 un’eccezione StackOverflow può essere rilevata solo nelle seguenti circostanze.

  1. Il CLR viene eseguito in un ambiente ospitato in cui l’host consente specificamente di gestire le eccezioni di StackOverflow
  2. L’eccezione stackoverflow viene generata dal codice utente e non a causa di una situazione di overflow dello stack effettivo ( riferimento )

Il modo giusto è quello di correggere l’overflow, ma ….

Puoi darti uno stack più grande: –

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

È ansible utilizzare la proprietà System.Diagnostics.StackTrace FrameCount per contare i fotogrammi utilizzati e generare la propria eccezione quando viene raggiunto un limite di frame.

Oppure, puoi calcolare la dimensione della pila rimanente e lanciare la tua eccezione quando cade al di sotto di una soglia: –

 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(string[] 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(); } } 

Prendi il formaggio. 😉

Dalla pagina MSDN su StackOverflowException s:

Nelle versioni precedenti di .NET Framework, l’applicazione poteva catturare un object StackOverflowException (ad esempio, per ripristinare la ricorsione illimitata). Tuttavia, tale pratica è attualmente scoraggiata perché è necessario un codice aggiuntivo significativo per intercettare in modo affidabile un’eccezione di overflow dello stack e continuare l’esecuzione del programma.

A partire da .NET Framework versione 2.0, un object StackOverflowException non può essere catturato da un blocco try-catch e il processo corrispondente viene terminato per impostazione predefinita. Di conseguenza, si consiglia agli utenti di scrivere il loro codice per rilevare e prevenire un overflow dello stack. Ad esempio, se l’applicazione dipende dalla ricorsione, utilizzare un contatore o una condizione di stato per terminare il ciclo ricorsivo. Si noti che un’applicazione che ospita Common Language Runtime (CLR) può specificare che il CLR scarica il dominio dell’applicazione in cui si verifica l’eccezione di overflow dello stack e lascia che il processo corrispondente continui. Per ulteriori informazioni, vedere ICLRPolicyManager Interface e Hosting Common Language Runtime.

Come molti utenti hanno già detto, non puoi cogliere l’eccezione. Tuttavia, se stai lottando per scoprire dove sta accadendo, potresti voler configurare lo studio visivo per interrompere quando viene lanciato.

Per fare ciò, devi aprire Impostazioni eccezione dal menu ‘Debug’. Nelle versioni precedenti di Visual Studio, questo è in “Debug” – “Eccezioni”; nelle versioni più recenti, è in “Debug” – “Windows” – “Impostazioni di eccezione”.

Una volta aperte le impostazioni, espandere ‘Common Language Runtime Exceptions’, espandere ‘System’, scorrere verso il basso e selezionare ‘System.StackOverflowException’. Quindi puoi guardare lo stack delle chiamate e cercare lo schema ripetuto delle chiamate. Questo dovrebbe darti un’idea di dove cercare di correggere il codice che sta causando l’overflow dello stack.

Come già detto più volte, non è ansible rilevare una StackOverflowException che è stata generata dal sistema a causa di uno stato del processo corrotto. Ma c’è un modo per notare l’eccezione come un evento:

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

A partire da .NET Framework versione 4, questo evento non viene generato per eccezioni che corrompono lo stato del processo, quali overflow dello stack o violazioni dell’accesso, a meno che il gestore eventi non sia critico per la sicurezza e abbia l’attributo HandleProcessCorruptedStateExceptionsAttribute.

Ciononostante, l’applicazione si interromperà dopo essere usciti dalla funzione evento (una soluzione MOLTO sporca, è stato il riavvio dell’app all’interno di questo evento haha, non lo ha fatto e mai lo farà). Ma è abbastanza buono per la registrazione!

Nelle versioni .NET Framework 1.0 e 1.1, un’eccezione non gestita che si verifica in un thread diverso dal thread dell’applicazione principale viene rilevata dal runtime e pertanto non causa la chiusura dell’applicazione. Pertanto, è ansible che l’evento UnhandledException venga generato senza che l’applicazione termini. A partire da .NET Framework versione 2.0, questo blocco di sicurezza per le eccezioni non gestite nei thread secondari è stato rimosso, poiché l’effetto cumulativo di tali errori silenziosi includeva degrado delle prestazioni, dati danneggiati e blocchi, tutti difficili da eseguire il debug. Per ulteriori informazioni, incluso un elenco di casi in cui il runtime non termina, vedere Eccezioni nei thread gestiti.

Sì dall’overflow dello stack CLR 2.0 è considerato una situazione non recuperabile. Quindi il runtime continua a interrompere il processo.

Per i dettagli, consultare la documentazione http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx

Non puoi Il CLR non ti lascerà. Un overflow dello stack è un errore irreversibile e non può essere ripristinato da.

Non puoi, come la maggior parte dei post stanno spiegando, permettimi di aggiungere un’altra area:

Su molti siti Web troverai persone che dicono che il modo per evitare questo è l’utilizzo di un diverso AppDomain, quindi se ciò accade il dominio verrà scaricato. Ciò è assolutamente sbagliato (a meno che non si ospiti il ​​CLR) poiché il comportamento predefinito del CLR solleva un evento KillProcess, facendo cadere il tuo AppDomain predefinito.

È imansible, e per una buona ragione (per esempio, pensa a tutte quelle catture (Eccezione) {} in giro).

Se si desidera continuare l’esecuzione dopo l’overflow dello stack, eseguire codice pericoloso in un diverso AppDomain. È ansible impostare i criteri CLR per terminare l’AppDomain corrente in overflow senza influire sul dominio originale.