47

Scenario:

I've just been on a roll and implemented a bunch of code, but when I execute it I get thrown a StackOverflowException? The StackOverflowException doesn't have a stacktrace so I'm stuck. I know why a stack overflow might occur, but to fix it I need to know where it's root is.

All I'm getting is:

An unhandled exception of type 'System.StackOverflowException' occurred in tag-you're-it.dll

Options:

  1. Scan through all the changes and try to pin point the problem. (could be slow)
  2. Use a debugger and step through till you find the problem. (probably better than 1.)
  3. Use a profile and look for the most called methods.
  4. ?

PS:

This is a hypothetical situation (although not too uncommon) and therefore no code is available.

2
  • Print out the stacktrace? VS tends to choke when confronted with a stackoverflow exception.
    – leppie
    Commented Jan 19, 2011 at 11:32
  • Code which causes this is publised in link in question stackoverflow.com/questions/39004357/…
    – Andrus
    Commented Aug 18, 2016 at 7:53

11 Answers 11

31

WinDbg can get the job done, including even getting a sensible (clr) stack trace. You'll need to get WinDbg unless you've already installed it with Visual Studio or Windows SDK. Note: "WinDbg Preview" with the new GUI has worked fine for me.

I suggest to start your process from WinDbg, but of course you can also attach it to a running process if this suits you better.

Note: Right after starting the process, the CLR is not loaded, and .loadby SOS.dll clr will fail ("unable to find module 'clr'). You have to wait for the CLR to be loaded. To stop execution once that happens perform:

  • sxe ld clr

Once the CLR is loaded you'll have to perform the following steps to break on StackOverflowException (enter in the command window / line):

  • .loadby SOS.dll clr (not .loadby sos clr—this can lead to the extension being loaded twice)
  • !stoponexception -create System.StackOverflowException
  • g (continues debugging)

trigger the StackOverflowException / wait for it to happen

  • !clrstack (will print the stacktrace)

Notable sources:

7
  • Nice! I'll give it a go the next time in run into this.
    – Christo
    Commented Apr 17, 2018 at 16:13
  • 1
    I had to replace .loadby SOS.dll clr with just .loadby SOS.dll
    – LOST
    Commented May 16, 2018 at 1:47
  • I am using WinDbg Preview from the store, and none of these commands work properly, except g :(
    – LOST
    Commented May 16, 2018 at 1:57
  • @LOST what do you do exactly, what commands are you using and what response do you get for these? Commented May 16, 2018 at 5:09
  • 1
    @BatteryBackupUnit, nvm, figured my issue out. I did not know at the start of .NET program from WinDBG CLR is not loaded yet, and .loadby SOS.dll clr would print a confusing message: "unable to find module 'clr'", which I assumed to be a problem with SOS, but actually it meant I had to somehow break after CLR is loaded and run these commands above.
    – LOST
    Commented May 16, 2018 at 18:07
17

This is almost always due to recursion. Either a method calling itself, or a method calling a method that calls it back and so on.

To find it:

  • UPDATED: I didn't realise, but apparently you can't get the stack trace for a StackOverflowException (I guess something to do with not being able to catch one, either). However there are ways to get a dump as mentioned here.
  • ReSharper will show methods that call themselves (it puts a little green circle in the sidebar for recursive calls) though it won't catch recursion where two or more methods are involved.
  • Use a tool like ANTS Profiler to see which methods are called the most times.
  • Keep an eye out for events that fire that might call code that means the same event fires again, causing a loop.

Occasionally you'll get typos like this, too:

private string name;

public string Name
{
    get { return Name; } // Ooops! This is recursive, all because of a typo...
}

Which is one reason why I personally now prefer to use automatic properties.

2
  • 5
    1. You don't get a stacktrace with a SO exception. 2. Recursion is probably the culprit and resharper could help, but then it doesn't always help to find circular loops due to other constructs. 3. A profile looks like a good option.
    – Christo
    Commented Jan 19, 2011 at 11:10
  • stackoverflow.com/questions/39004357/… shows that this is not caused by recursion. How to debug SOexception in this case? This answer assumes that this is caused by recursion.
    – Andrus
    Commented Aug 18, 2016 at 7:55
7

Go to Debug, exceptions and check the thrown checkbox at 'Common Language Runtime Exceptions'. Now when you cause the stackoverflow exception, the debugger will stop (eventually) and show you the call stack.

3
  • 4
    Are you sure that it works on stack overflow exceptions? They are a bit special in how they are handled. Commented Mar 8, 2012 at 17:52
  • 5
    Perhaps worth emphasizing you need to look at Visual Studio's Call Stack window not the Exception's StackTrace which won't be set (probably because once the stack is full, it can't do anything that would need further stack usage).
    – Appetere
    Commented Feb 5, 2016 at 9:14
  • The maximum number of stack frames supported by Visual Studio has been exceeded.
    – CMS
    Commented Jun 26, 2020 at 8:11
7

The ProcDump utility has helped us to debug the issue as described in details here. Steps:

  1. Download the tool
  2. Run the process, note its ID
  3. Attach the debugger by running procdump -accepteula -e 1 -f C00000FD.STACK_OVERFLOW -g -ma <process ID> d:\home\DebugTools\Dumps (the directory must exist)
  4. Make the exception to happen and the procdump will make you a dump.
  5. Open the dump file in the Visual Studio. For my sample app right after opening the dump file the VS has highlighted the line on which the SO happened.

We can use the same technique on Azure by enabling the CrashDiagnoser extension, like described here. Basically it performs the same steps as above. The dump file it generates could be downloaded and opened within the Visual Studio.

5

You can execute the program on debug mode and pause it. On the current callstack you can see that there are a method or a group of method that appears several times, these are the problematic methods. Put a break point on this method and look what its calling itself all the time.

2
  • True, I'll add step through debugging as another option.
    – Christo
    Commented Jan 19, 2011 at 11:14
  • Thanks! I only hit gnarly errors occasionally and so I'm not in the habit of using the Call Stack. I was sure that I didn't have a recursion problem but, of course, I had a recursion problem in an unexpected location and fixing was easy once I stopped just trying to intuit what was wrong. :-)
    – clweeks
    Commented Jun 20, 2014 at 14:11
3

I suspect if the stack size of the thread that caused the stack overflow is larger than some threshold that Visual Studio debugger can track, then the call stack is unavailable.

A workaround is to spawn a thread who's stack size is smaller than the default stack size, thus Visual Studio debugger can track the call stack.

        (new Thread(delegate ()
        {
            ProduceAStackOverFlowHere() ;
        }, 256 * 1024)).Start();//Default size for 32 bit process is 1MB, 64 bit process is 4MB. So I'll set the size at 256KB.
1

At the method that is the "entry point" to the operation that fails, put a breakpoint. Step through the code and watch for occurrences of the same sequence of method calls happening over and over in an identical pattern so the call stack gets deeper and deeper.

As soon as you notice that, put a breakpoint at the current location, wherever that is. Continue execution (F5 in Visual Studio) - if you're on the right track then the debugger will stop very quickly at the same location, and the call stack will be even deeper.

Now you have a "live" stack frame you can examine, in order to figure out how to ensure that this recursion will properly terminate.

2
  • Other way around (sort answers by 'Oldest') Commented Jan 19, 2011 at 12:24
  • ;-) Jip, guess my sorting was wrong. I did initially vote yours up as well, just in case i got the ordering wrong.
    – Christo
    Commented Jan 20, 2011 at 6:15
1

Personally, I like to narrow it down as much as possible to a certain section of code. For example, I just had one. The odd thing was it was only happening on the machine I couldn't directly debug.

I had two threads running in parallel, so I stopped one from running(or you could unparallelize it).

Then I went through my functions and added like print out functions, such as: Just as function starts:

Console.WriteLine("<Enter method: {0}", DebuggingHelper.GetCurrentMethod());

Just before function returns:

Console.WriteLine(">Exit method: {0}", DebuggingHelper.GetCurrentMethod());

Where GetCurrentMethod is defined as:

[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCurrentMethod()
{
    StackTrace st = new StackTrace();
    StackFrame sf = st.GetFrame(1);
    return sf.GetMethod().Name;
}

Then I run it, maybe I don't add to all functions, but enough to narrow down where in the code it's happening. Then within that section, add more.

You could also add checkpoint as it runs through certain methods.

Then run it again, what you'll find is that the StackOverFlow exception will occur between those statements. Keep narrowing down till you find it.

Fairly simply and quick to find where it's happening this way.

1

Just wanted to add to the answer about using WinDbg, with what I found for debugging a dotnet core application

  1. make sure you have windbg installed
  2. start your application via command line with dotnet run
  3. attach to the running process with windbg
  4. from the command line enter .loadby sos coreclr (this should detect the version of .net core that you are using, but if not you can use .load C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\sos where 2.05 is the version of .netcore you are using
  5. commands are now available by entering !help
  6. Use !dso to get a dump of the stack

In my case that told me exactly where the stackoverflow exception was occurring

0

If you have the code and are able to run your program from Visual Studio it should break in the debugger (if first-chance exceptions are enabled) when it encounters the System.StackOverflowException. From there you can examine the call stack and see which calls are blowing the stack. enter image description here

I've confirmed that this works for Visual Studio 2010 and Visual C# 2010 Express.

0

During the course of the development of IKVM.MET, I figured out a trick to debug stack overflow bugs in both static and dynamic assemblies, since IKVM.NET makes extensive use of dynamic assemblies. I would run the executable in the Visual Studio debugger, and when a stack overflow occurs, the Visual Studio debugger would suspend the process, instead of terminating it. Then, I used dotnet-dump to obtain a core dump, and finally, I would terminate the process to free up RAM and analyze the core dump using dotnet-dump. Note that this only works on .NET core applications.

Command to create the core dump

dotnet-dump collect -p <Process ID here>

The process ID can be obtained using the Task Manager. Command to view the stack trace:

dotnet-dump analyze <file name of dump> -c clrstack -all

How to use dotnet-dump, if you want to do further debugging

Note: This debugging technique is risky, since the process could be corrupted, and may not work every single time.

Not the answer you're looking for? Browse other questions tagged or ask your own question.