Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StackOverflowException without recursion or infinite loop?

Background

I have a DataGridView control which I am using, and I added my handler below to the DataGridView.CellFormatting event so the values in some cells can be made more human-readable. This event handler has been working great, formatting all values without issue.

Recently however, I have discovered a very rare circumstance causes an unusual bug. The column in my DataGridView for the item's due date always has an int value. 0 indicates the event is never due, any other value is a UTC timestamp for the due date. The MySQL db column corresponding doesn't allow nulls. When the user has moved from one DataGridView row with a due date, to another DataGridView row with a due date (at this point everything is still appears fine), and then presses a button which reloads the data from the database (without sending updates, essentially calling DataAdapter.Fill()), the program generates a StackOverflowException**.

No recursion?

What is so unusual to me is that I do not see where the recursion or infinte-looping is. I added int cellFormatCallCount as a class member, and increment it during each call, but at the time the exception is thrown, the debugger shows the value of that int as 1, which I would expect since I wasn't under the impression and recursion was occuring.

Can somebody help me?

How can I view a stack trace? In VS2008 it says: {Cannot evaluate expression because the current thread is in a stack overflow state.}

Best regards,

Robinson

private int cellFormatCallCount = 0;
private void myDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)  {
    try {
        // to format the cell, we will need to know its value and which column its in
        string value = "";
        string column = "";
        
        // the event is sometimes called where the value property is null
        if (e.Value != null) {
            cellFormatCallCount++; // here is my test for recursion, this class member will increment each call

            // This is the line that throws the StackOverflowException
            /* ********************* */
            value = e.Value.ToString();
            /* ********************* */

            column = actionsDataGridView.Columns[e.ColumnIndex].Name;
        } else {
            return; // null values cannont be formatted, so return
        }

        if (column == "id") {
            // different code for formatting each column
        } else if (column == "title") {
            // ...
        } else {
            // ...
        }
    } finally {
        cellFormatCallCount = 0; // after we are done with the formatting, reset our recursion counter
    }
}
like image 870
gnirts Avatar asked Apr 22 '09 20:04

gnirts


People also ask

Can we handle StackOverflowException?

NET Framework 2.0, you can't catch a StackOverflowException object with a try / catch block, and the corresponding process is terminated by default. Consequently, you should write your code to detect and prevent a stack overflow.

What causes StackOverflowException?

A StackOverflowException is thrown when the execution stack overflows because it contains too many nested method calls. using System; namespace temp { class Program { static void Main(string[] args) { Main(args); // Oops, this recursion won't stop. } } }

Does infinite loop causes stack overflow?

The most-common cause of stack overflow is excessively deep or infinite recursion, in which a function calls itself so many times that the space needed to store the variables and information associated with each call is more than can fit on the stack.

Why is recursion not infinite?

If a recursion never reaches a base case, it will go on making recursive calls forever and the program will never terminate. This is known as infinite recursion, and it is generally not considered a good idea. In most programming environments, a program with an infinite recursion will not really run forever.


3 Answers

Apparently e.Value.ToString() invokes the CellFormatting event again. That seems somewhat logical. It should be easy enough to find out with a debugger.

But the actual recursion could be caused somewhere else, like in the per-column formatting that you omitted.

Your recursion check isn't reliable since Value==null will also reset it, and it appears to be shared by all columns. Make it surround the e.Value.ToString() more tightly:

if (e.Value != null) 
{
   cellFormatCallCount++; 
   System.Diagnostics.Debug.Assert(cellFormatCallCount <= 1, "Recursion");
   value = e.Value.ToString();
   cellFormatCallCount--; 
   ...
} 
like image 190
Henk Holterman Avatar answered Sep 22 '22 04:09

Henk Holterman


Totally random guess (with no stack trace it's all I can do)...

Are you attempting to display/format a type which has a potentially recursive ToString()?

public string ToString()
{
   return ... this.ToString() ...
   // or
   return String.Format("The value is {0}", this);
}

A typo/error like that could cause a StackOverflowException...

like image 44
Daniel LeCheminant Avatar answered Sep 19 '22 04:09

Daniel LeCheminant


Given that this is an event, might it be triggering its self?

like image 39
BCS Avatar answered Sep 20 '22 04:09

BCS