Condividi tramite


Eseguire il debug degli errori Stack Overflow

Un'eccezione StackOverflowException viene lanciata quando si verifica un overflow dello stack di esecuzione a causa di troppe chiamate di metodo annidate. Ciò si verifica molto spesso perché i metodi chiamano tra loro in modo ricorsivo.

Si supponga, ad esempio, di avere un'app come indicato di seguito:

using System;

namespace temp
{
    class Program
    {
        static void Main(string[] args)
        {
            Main(args); // Oops, this recursion won't stop.
        }
    }
}

Il metodo Main si chiamerà continuamente fino a esaurire lo spazio dello stack. Una volta che non è disponibile più spazio dello stack, l'esecuzione non può continuare e quindi genererà un StackOverflowException.

> dotnet run
Stack overflow.
   at temp.Program.Main(System.String[])
   at temp.Program.Main(System.String[])
   at temp.Program.Main(System.String[])
   at temp.Program.Main(System.String[])
   at temp.Program.Main(System.String[])
   at temp.Program.Main(System.String[])
   <this output repeats many more times>

Quando viene visualizzata l'uscita dal programma con un output simile a questo, è possibile trovare il codice sorgente dei metodi ripetuti e analizzare la logica che causa l'elevato numero di chiamate.

Uso del debugger

Spesso è sufficiente vedere questo stack di chiamate nella console precedente per identificare il codice problematico. Tuttavia, se il problema non è ancora chiaro, è possibile eseguire il debug ulteriormente.

Questo esempio crea un dump principale quando si verifica StackOverflowException, quindi carica il dump in lldb (un debugger della riga di comando Linux comune) ed esegue il debug.

  1. Esegui l'applicazione configurata per raccogliere un dump in caso di crash.

    > export DOTNET_DbgEnableMiniDump=1
    > dotnet run
    Stack overflow.
    Writing minidump with heap to file /tmp/coredump.6412
    Written 58191872 bytes (14207 pages) to core file
    

    Nota

    .NET 6 standardizza il prefisso DOTNET_ anziché COMPlus_ per le variabili di ambiente che configurano il comportamento di runtime di .NET. Tuttavia, il prefisso COMPlus_ continuerà a funzionare. Se si usa una versione precedente del runtime .NET, è comunque consigliabile usare il prefisso COMPlus_ per le variabili di ambiente.

  2. Installare l'estensione SOS usando dotnet-sos.

    dotnet-sos install
    
  3. Aprire il dump in lldb e usare il comando bt (backtrace) per visualizzare lo stack.

    lldb --core /temp/coredump.6412
    (lldb) bt
    ...
        frame #261930: 0x00007f59b40900cc
        frame #261931: 0x00007f59b40900cc
        frame #261932: 0x00007f59b40900cc
        frame #261933: 0x00007f59b40900cc
        frame #261934: 0x00007f59b40900cc
        frame #261935: 0x00007f5a2d4a080f libcoreclr.so`CallDescrWorkerInternal at unixasmmacrosamd64.inc:867
        frame #261936: 0x00007f5a2d3cc4c3 libcoreclr.so`MethodDescCallSite::CallTargetWorker(unsigned long const*, unsigned long*, int) at callhelpers.cpp:70
        frame #261937: 0x00007f5a2d3cc468 libcoreclr.so`MethodDescCallSite::CallTargetWorker(this=<unavailable>, pArguments=0x00007ffe8222e7b0, pReturnValue=0x0000000000000000, cbReturnValue=0) at callhelpers.cpp:604
        frame #261938: 0x00007f5a2d4b6182 libcoreclr.so`RunMain(MethodDesc*, short, int*, PtrArray**) [inlined] MethodDescCallSite::Call(this=<unavailable>, pArguments=<unavailable>) at callhelpers.h:468
    ...
    
  4. La cornice superiore 0x00007f59b40900cc viene ripetuta più volte. Usare il comando ip2mdSOS per determinare quale metodo gestito si trova nell'indirizzo 0x00007f59b40900cc.

    (lldb) ip2md 0x00007f59b40900cc
    MethodDesc:   00007f59b413ffa8
    Method Name:          temp.Program.Main(System.String[])
    Class:                00007f59b4181d40
    MethodTable:          00007f59b4190020
    mdToken:              0000000006000001
    Module:               00007f59b413dbf8
    IsJitted:             yes
    Current CodeAddr:     00007f59b40900a0
    Version History:
      ILCodeVersion:      0000000000000000
      ReJIT ID:           0
      IL Addr:            0000000000000000
         CodeAddr:           00007f59b40900a0  (MinOptJitted)
         NativeCodeVersion:  0000000000000000
    Source file:  /temp/Program.cs @ 9
    
  5. Esamina il metodo indicato temp.Program.Main(System.String[]) e il file sorgente "/temp/Program.cs @ 9" per capire cosa sta sbagliando il codice. Se sono necessarie informazioni aggiuntive, è possibile usare un altro debugger o comandi SOS per controllare il processo.