StackOverflowException without recursion or infinite loop? - c#

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

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

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.

#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

It's unrelated to the problem but you can actually have a StackOverflowException without recursion at all just with:
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.

Related

C# variable in a function become randomly not available

I'm not really sure if I will be able to explain this behavior but I'll try. I have a program like a dashboard where some graph modules are initialized at startup, each module has a sole purpose to show a graph has a function passed to it which determine the data shown.
The module building (initializing each module type with the corresponding function) is handled in a separate thread using Task. But randomly some of these functions stop working and the List with the data stop being available as if it was never declared.
This is one of the functions, keep in mind it's kind of random which one throws this error, but one of these will always throw an exception. I really can't track down what could cause this behavior I thought about the resources being deleted by other thread but this List is created at startup and only passed and used as a reference. And nowhere in the program I ever reset this list. The same code work in other project and while debugging step by step... I'm really out of tracks to follow
private static IEnumerable<ICompositeValue> GroupEvent(IEnumerable<Event> events, DateTime referenceDate, Month month)
{
List<ICompositeValue> Values= new List<ICompositeValue>();
foreach (Days day in (Giorni[])Enum.GetValues(typeof(Days)))
{
if (day != Giorni.Sunday)
if (events== null) return null; //this was tried to catch the exception
Values.Add(new ICompositeValue()
{
Argument = day.ToString(),
Valore = event.Count(x => (int)x.DDB_APDATA.Value.DayOfWeek == (int)day && (int)x.DDB_APDATA.Value.Month == (int)month && x.DDB_APDATA.Value.Year == referenceDate.Year)
}); ;
}
return valori;
}
As shown in this image Visual Studio can't even evaluate the List value as if it was never declared
Can someone point me in the right direction?
Thanks to everyone!
I just wanted to thank those who tried to help me.
I still didn't get why the debugger acted the way it did since it showed me "x" was null not the inside property, but I managed to track down the problem. I noticed the object mapping from the DataTable was acting strange with the DateTime type variable and indeed something returned null from time to time
As Jeroen Mostert has suggested it seems like some property in your lambda is unexpectedly null. The reason events is not available is because your debugger context is inside the lambda.
x => (int)x.DDB_APDATA.Value.DayOfWeek == (int)day && (int)x.DDB_APDATA.Value.Month == (int)month && x.DDB_APDATA.Value.Year == referenceDate.Year
So one of either x, DDB_APDATA, or Value will likely be null.

Try-Catch not catching exception in method in C#

I have a search box and button combo in a WPF desktop application. On clicking the search button, it uses a Predicate in the Library.Find() method to search for the precise search term entered. This is all inside of a try-catch block, so that if the search term isn't matched it won't crash the application.
The problem is that the exception isn't caught, rather it still crashes despite the try-catch block. Through debugging, I know the type of the exception is a NullReferenceException. I've also tried catching ArgumentNullException, as this is the type listed for the Library.Find() method, and I've even tried using just a generic Exception type, but nothing is ever caught. Can someone please help explain this? I'm sure it's something simple I'm overlooking, but none of the answers I looked at hada similar situation.
Note: I don't have a try-catch block around the contents of the ShowRecord() method as this method is also used for record navigation buttons (i.e. Next Record, Prev Record, etc), and the ArgumentNull or NullReference don't make sense in that case. I only have the try-catch around the code that could potentially throw the relevant error, as I was always taught.
searchButton Code:
private void searchButton_Click(object sender, RoutedEventArgs e)
{
try
{
ShowRecord(gameLibrary.Find(x => x.GameName == searchBox.Text));
}
catch (ArgumentNullException ex)
{
string term = searchBox.Text;
searchBox.Text = "'" + term + "' was not found in the library. Please try another search term.";
}
}
ShowRecord() Code:
public void ShowRecord(Game game)
{
titleBlock.Text = game.GameName;
systemBlock.Text = game.GameSystem;
formatBlock.Text = game.GameFormat;
completedBlock.Text = game.IsComplete.ToYesNo();
totalledBlock.Text = game.IsTotaled.ToYesNo();
gamepassBlock.Text = game.GamePassStatus;
installedBlock.Text = game.IsInstalled.ToYesNo();
recordNumber.Content = (gameLibrary.FindIndex(x => x == game) + 1).ToString();
recordCount.Content = gameLibrary.Count;
}
EDIT
I was pasting the stack trace as requested in one of the comments, and may have figured out the issue in doing so. As stated in the initial question, the ShowRecord() method is also used for record navigation; as such, there is a segment in it where the TextBoxes are assigned the values for the located record (i.e. TextBox.Text = gameLibrary.GameName). It's at this point that the exception is occurring, so even though it's happening within the ShowRecord() call in the button click event, the issue is actually not related to the List.Find(Predicate) part that the exceptions were supposed to catch. Does this make sense? To add to this, #Tam Bui mentioned adding a second catch block with only Exception being caught, and adding a breakpoint inside this: I did this, and it still didn't stop at the breakpoint, it stopped at the TextBox value assignment.
Assuming this is the cause, thanks to everyone for the help. I saw the exception not being caught by the generic Exception, and the impossibility of that blocked out all other reasoning for me, hence the confusion and missing where the actual break occurred.

Enumeration may not execute exception when changing an independent variable

I have been having an issue lately with a Foreach statement and it throwing an Collection was modified; enumeration operation may not execute exception when changing a variable that shouldn't impact the items being enumerated upon, but it still does. Here is my code so I can continue my explanation:
private static CEconTradeOffer RemoveUndesirables(CEconTradeOffer offer)
{
try
{
CEconTradeOffer returned = offer;
foreach (CEconAsset cEconAsset in offer.ItemsToReceive)
{
string marketHashName = cEconAsset.GetMarketHashName(_config.ApiKey);
if (marketHashName.ToLower().Contains("case") ||
marketHashName.Contains("gut") ||
marketHashName.Contains("falchion") ||
marketHashName.Contains("bayonet") ||
marketHashName.Contains("huntsman") ||
marketHashName.Contains("karambit") ||
marketHashName.Contains("butterfly"))
{
//somehow changes both "offer" and "returned" at once.
returned.ItemsToReceive.Remove(cEconAsset);
continue;
}
MarketValue value = MarketHandler.GetPriceOverview(Convert.ToUInt32(cEconAsset.AppId),
marketHashName);
if (!value.Success || int.Parse(value.Volume, NumberStyles.AllowThousands) <= 20)
returned.ItemsToReceive.Remove(cEconAsset);
}
return returned;
}
catch (Exception e)
{
Write.Exception(e);
return null;
}
}
This function was designed to do exactly what it says; remove undesired items from a trade offer. As you can see, I set CEconTradeOffer returned equal to the passed argument of the same type named offer. Strangely enough, whenever I change something inside of returned it causes the foreach statement to break even though I technically shouldn't be impacting offer.ItemsToReceive in any way. returned is what should be modified. When I use the debugger, I notice that BOTH returned and offer get changed at the line returned.ItemsToReceive.Remove(cEconAsset);. Through my previous experience with C# and browsing related problems, this should not be happening since I am creating a new variable that should be separate from offer. I have tried include setting returned equal to a new CEconTradeOffer() and then setting it equal to offer but to no avail. In my research of this problem, I can only seem to find problems where people fail to create a new variable and modifying that in the foreach statement rather than the enumerated value.
Is there something blatantly obvious I am missing? I do not quite understand why I am getting this particular issue when I create a separate variable to change inside the foreach statement.
I am not using more than one thread, so it can't be impacted outside of its own thread of execution.
Thanks in advance.
whenever I change something inside of returned it causes the foreach statement to break even though I technically shouldn't be impacting offer.ItemsToReceive in any way.
It seems that CEconTradeOffer is a reference type, so then you assign
CEconTradeOffer returned = offer;
you get another reference to exactly the same thing.
So when the items are removed using returned.ItemsToReceive.Remove(cEconAsset) they are removed from the same collection, just via another reference.

Variable changing, but I don't know where or why

I am working on implementing a undo function for my WPF datagrid, however I a running into problems. I am sure it is just a misunderstanding of the C# language and its syntax, but I don't know what the problem is. When the cell edit is ending, I obtain the previous item and display an item value (Z) (for debugging purposes). It contains the item held BEFORE the edit (which is what I want). But when I try to 'undo' it, I display the SAME value (Z) again but it has changed to the current value of that item in the datagrid.
CellEditEnding Handler
private void toolGrid_CellEditEnding(object sender, DataGridVellEditEndingEventArgs e)
{
undoTool = toolsList[selectedToolNdx];
MessageBox.Show(undoTool.Z.ToString());
}
KeyDown Handler
private void toolGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
if (e.Key == Key.Z)
{
MessageBox.Show(undoTool.Z.ToString());
e.Handled = true;
}
}
}
So for instance, I can change the z-value from 3 to 5, and the celleditending event fires and a messagebox shows the value '3' (so far so good). However, I then undo (CTRL-Z) and a messagebox now shows the value '5' even though it should still be 3. Why is the undoTool changing (and why does it seem to be changing by itself)?
The problem is that while 'saving' the old value, it simple saves itself as a reference inside your variable 'undoTool'. Because its a reference it doesn't do anything else then referencing to its base object which is the value you are editing. This means whenever you change the base object all references to it will return the same value as the one you've changed it into.
You should tell specifically tell .NET to create a new object, thus using the new keyword, and then store your variable inside it.
Since you do not know where or how then you must use a debugger or a a thread which has access to the memory space of the variable. In the case of the debugger Add a watch and break on access / read write in the latter use a thread and sleep until something != somethingElse == true; then perform logic after to debug. Depending on the level of access you have in the system you may be able to also ascertain the function call and the caller using some constants but lesser knowns.. How to get the name of the current method from code
or
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
You can also use a the Watch window

NullReferenceException when function returns

I am getting a NullReferenceException when running my multi-threaded application, but only when I run in Release mode outside of the debugger. The stack trace gets logged, and it always points to the same function call. I put several logging statements in the function to try to determine how far it would get, and every statement gets logged, including one on the last line of the function. What is interesting is that when the NullReferenceException occurs, the statement after the function call does not get logged:
// ...
logger.Log( "one" ); // logged
Update( false );
logger.Log( "eleven" ); // not logged when exception occurs
}
private void Update( bool condition )
{
logger.Log( "one" ); // logged
// ...
logger.Log( "ten" ); // logged, even when exception occurs
}
The exception does not occur every time the function is called. Is it possible that the stack is being corrupted either before or during execution of the function such that the return address is lost, resulting in the null reference? I didn't think that sort of thing was possible under .NET, but I guess stranger things have happened.
I tried replacing the call to the function with the contents of the function, so everything happens inline, and the exception then occurs on a line that looks like this:
foreach ( ClassItem item in classItemCollection )
I have verified through logging that the "classItemCollection" is not null, and I also tried changing the foreach to a for in case the IEnumerator was doing something funny, but the exception occurs on the same line.
Any ideas on how to investigate this further?
Update: Several responders have suggested possible solutions having to do with making sure the logger isn't null. To be clear, the logging statements were added for debugging purposes after the exception started happening.
I found my null reference. Like Fredrik and micahtan suggested, I didn't provide enough information for the community to find a solution, so I figured I should post what I found just to put this to rest.
This is a representation of what was happening:
ISomething something = null;
//...
// the Add method returns a strong reference to an ISomething
// that it creates. m_object holds a weak reference, so when
// "this" no longer has a strong reference, the ISomething can
// be garbage collected.
something = m_object.Add( index );
// the Update method looks at the ISomethings held by m_object.
// it obtains strong references to any that have been added,
// and puts them in m_collection;
Update( false );
// m_collection should hold the strong reference created by
// the Update method.
// the null reference exception occurred here
something = m_collection[ index ];
return something;
The problem turned out to be my use of the "something" variable as a temporary strong reference until the Update method obtained a permanent one. The compiler, in Release mode, optimizes away the "something = m_object.Add();" assignment, since "something" isn't used until it is assigned again. This allowed the ISomething to be garbage collected, so it no longer existed in m_collection when I tried to access it.
All I had to do was ensure that I held a strong reference until after the call to Update.
I am doubtful that this will be of any use to anyone, but in case anyone was curious, I didn't want to leave this question unanswered.
The fact that it logs "ten" would make me look first at:
is logger ever assigned... is this perhaps becoming null somehow
is the bug inside Log itself
Hard to tell without enough context for either - but that is how I'd investigate it. You could also add a simple null test somewhere; as a cheeky approach, you could rename the Log method to something else, and add an extension method:
[Conditional("TRACE")]
public static void Log(this YourLoggerType logger, string message) {
if(logger==null) {
throw new ArgumentNullException("logger",
"logger was null, logging " + message);
} else {
try {
logger.LogCore(message); // the old method
} catch (Exception ex) {
throw new InvalidOperationException(
"logger failed, logging " + message, ex);
}
}
}
Your existing code should call the new Log extension method, and the exception will make it clear exactly where it barfed. Maybe change it back once fixed... or maybe leave it.
Agree w/Fredrik -- more details are necessary. One place to maybe start looking: you mention multi-threaded application and the error happening in release but not debug. You might be running into a timing issue with multiple threads accessing the same object references.
Regardless, I'd also probably put a:
Debug.Assert(classItemCollection != null);
right before the loop iteration. It won't help you in release mode, but it may help you catch the problem if (when?) it happens in Debug.
I'd look for code that's setting logger or one of its dependents to null. Are there properties of logger that, when set to null, might trigger this? Release mode sometimes speeds up application execution which can reveal synchronization problems that are masked by the performance penalty of debug mode and/or the debugger.
The fact that "eleven" isn't getting logged leads me to believe that logger is being set to null just before that call is made. Can you wrap it in a try/catch and see if it hits the catch portion of the block? Maybe you can insert a MessageBox.Show or write something to a known file when that happens.
Are you modifying classItemCollection from multiple threads? If you change the collection in another thread you may be invalidating the iterator which might lead to your exception. You may need to protect access with a lock.
edit:
Can you post more info about the types of ClassItem and classItemCollection?
Another possibility is that ClassItem is a value type and classItemCollection is a generic collection and somehow a null is getting added to the collection. The following throws a NullReferenceException:
ArrayList list=new ArrayList();
list.Add(1);
list.Add(2);
list.Add(null);
list.Add(4);
foreach (int i in list)
{
System.Diagnostics.Debug.WriteLine(i);
}
This particular problem can be resolved by int? i or Object i in the foreach or using a generic container.

Categories