简体   繁体   中英

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
    }
}

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--; 
   ...
} 

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 ...

@Daniel: If that were the issue, wouldn't it already raise the exception in the line:

if (e.Value != null) {

@gnirts: Could you post the full method and stack trace too?

@BCS (below): I think that might be it, but it might easily be in some of the code that is not shown in the deo posted.

PS. I'm sorry, this should have been a comment, but I have not enough reps :-D

鉴于这是一个事件,它可能会引发它的自我吗?

Try making the cellFormatCallCount variable static so that it shared by all instances of the class. I suspect that somehow the event is triggering itself but you aren't seeing it because cellFormatCallCount is only local to each instance of the class handling the event and thus is never incremented beyond 1. If that's the case, then the actual trigger for the stackoverflow (recursion) could be anywhere in the method and it just happens to run out of stack space at that line.

Once you've made the variable static, you could throw an exception when it exceeds a certain (small) value, like 2. That exception should leave a viewable stack trace around.

它与问题无关,但实际上你可以实现一个StackOverflowException而不需要递归,只需:

throw new StackOverflowException();

I Have just had a similar problem of stackoverflow with no trace details.

My problem was due to a instance of an object which should not have been instantiated. I removed the offending new object and all was fine.

In the circumstance above without seeing any more code, ensure multiple events are not fired using the =- to cancel the events accordingly.

I hope this might help someone.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM