.NET Stack Traces And Anonymous Methods

I learned a little more about stack traces in .NET today… in a very painful manner… but, lesson learned! Hopefully someone else will be able to learn this lesson without having to spend 4 hours on it like I did. Take a look at this stack trace that I was getting in my Compact Framework app, today:

   1: System.NullReferenceException

   2:       Message="NullReferenceException"

   3:       StackTrace:

   4:            at TrackAbout.Mobile.UI.CustomControls.TABaseUserControl.<EndInit>b__8(Object o, EventArgs e)

   5:            at System.ComponentModel.Component.Dispose(Boolean disposing)

   6:            at System.Windows.Forms.Control.Dispose(Boolean disposing)

   7:            at TrackAbout.Mobile.UI.Views.BaseForms.TAForm.Dispose(Boolean disposing)

   8:            at TrackAbout.Mobile.UI.Views.GeneralActions.SetExpirationDateView.Dispose(Boolean disposing)

   9:            at System.ComponentModel.Component.Dispose()

  10:            etc.

  11:            etc.

  12:            ...

In this stack trace, on line 4, is one very important detail: an anonymous method signature and the parent method that defines it. After several hours of debugging and finally turning on the “catch all” feature for CLR exceptions in Visual Studio, I discovered that line 4 actually translates to this code:

   1: public virtual void EndInit()

   2: {

   3:     ParentForm = FormUtils.GetParentFormOf(this) as TAForm;

   4:     if (ParentForm == null) return;

   5:  

   6:     ParentForm.Closing += FormClose;

   7:     ParentForm.Activated += (o, e) => ParentActivatedHandler(o, e);

   8:     ParentForm.Deactivate += (o, e) => ParentDeactivateHandler(o, e);

   9:     ParentForm.Disposed += (o, e) => ParentDisposedHandler(o, e); 

  10:  

  11:     if (ControlEndInit != null)

  12:     {

  13:         ControlEndInit(this, EventArgs.Empty);

  14:     }

  15: }

Let me translate this line stack trace into this method… the namespace in the stacktrace is obvious… so is the username. The first part to note is the <EndInit>. Apparently this means that the EndInit method contains the code that is throwing the exception, but is not actually firing the code that is causing the exception. The next part is where we find what is throwing the exception. Apparently b__8(Object o, EventArgs e) tells me that the failing code in question is an anonymous method. The CLR naming of this method seems cryptic, but also seems like it might be something useful…

Examining the entire method call: TrackAboutControl.<EndInit>b__8(Object o, EventArgs e) what I understand this to be saying is “The EndInit method is defining an anonymous method with a standard event signature at line 8 of the method.” Now I’m not entire sure that “line 8 of the method” is what this anonymous method name means… but it fits in this case… it matches up to the line that was causing the problem.

The problem in this specific case was that this line had a null reference: ParentForm.Disposed += (o, e) => ParentDisposedHandler(o, e);

The ParentDisposedHandler is defined as an event earlier in the class, and since it had no subscribers, it was null. That was easy to fix… just add a null ref check or define the event with a default value of “= delegate{ }”.

So… 4 hours into debugging this issue, it turned out to be 1 line of anonymous method calls. The stack trace was cryptic and confusing to me at first. I hope to retain this lesson and hope to be able to pass this on to someone else that sees a cryptic stack trace such as this, and same someone the same heartache and headache that I went through today.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, C#, Debugging, Stack Trace. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://hinternets.blogspot.com Quick Joe Smith

    I’m not sure why debugging this took you four hours, or why you thought it was so cryptic. I agree that b__8 isn’t meaningful, but after one or two attempts, surely you’d have placed a breakpoint on the entrance to EndInit and put 2 and 2 together.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @joe,

    yeah, i thought it would be easy, too. the first thing i did was put a breakpoint on that method. you’d be surprised at how wrong you are. :)

    the problem is that the line of code in question will execute perfectly fine when the EndInit method runs…. after all, i’m just subscribing to an event with an anonymous method. that’s nearly impossible to screw up and there’s no bugs in my code for the subscription part.

    it’s a deceptive bug because the null reference issue does not occur until the parent form fires it’s dispose method, which is handled by line 9 in that code snippet. the form does not get disposed during the lifetime of the EndInit method… it is disposed after the form closes… which can be anywhere form a second to infinite length of time later, based on the user actions on the screen.

    when the form disposes and that event is fired, the EndInit method is no longer in scope, so the only way i would have been able to get a breakpoint in there would be to set the breakpoint directly on the “ParentDisposedHandler(o,e);” call on line 9… it simply did not occur to me to do that, because I didn’t understand what the stacktrace was telling me.

    the real deception came from the NRE being thrown immediately after the dispose method of a different class (a Form that held a control with the EndInit method in that control). since the NRE was fired after the final } of the dispose method on that form, it was not obvious that the NRE was being thrown from here, inspite of the stack trace.

    now that I know what the stack trace’s contents are telling me, the solution is obvious. it’s a situation where the solution is obvious once it has been solved… but horrendously deceptive and difficult to track down if you don’t know what that stack trace means.

  • http://internets.blogspot.com Quick Joe Smith

    I have also had some issues before with VS highlighting the wrong line when an exception is generated, so I see where you are coming from now. I too once spent an inordinate amount of time wondering why a ‘if (var % 2 == 0)’ condition was ostensibly passing when ‘var’ was odd.

    Out of interest, since the signatures match, is there a reason you’re using anonymous methods rather than the more direct approach:

    ParentForm.Deactivate += ParentDeactivateHandler;

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    not sure about the signature and method group vs. lambda, actually. i didn’t write the code. i was just debugging it. :)

  • http://internets.blogspot.com Quick Joe Smith

    Actually it just occurred to me about 5 minutes after posting. Without the lambda, you would have to have already subscribed to that event prior to EndInit, which wouldn’t be very convenient.

  • http://www.johncoder.com/ John Nelson

    I found this problem while debugging earlier this week, and the tip off was that when the debugger displayed the exception the quick watch had no reference to any local variables. Once I moved back one item on the stack trace, it was painfully obvious where the exception came from. The exception was actually thrown from inside of a LINQ query using the keywords.

  • http://neilmosafi.blogspot.com Neil Mosafi

    Should be fairly easy to find that cause of this, no? One of

    1. Put the lambda’s body on a the next line to the => and you can set a breakpoint on the actual lambda

    2. Compile in debug code so you get line numbers in your stack traces

    3. Attach the debugger and stop of first chance exceptions – you’ll break on the exact line where it failed