S h o r t S t o r i e s

// Tales from software development

Different number of stack frames between Debug and Release builds

with one comment

I’ve recently been making some enhancements to a tracing and logging library that was written about four years ago. The tracing functionality uses the StackTrace class to get the stack frame of the caller and then logs information about the caller.

The updated code passed its unit tests and I created a new releae build but a few days later I found that the code repeatedly threw a NullReferenceException when called from the Main() method of a Windows console application.

After a few hours of debugging and head scratching the cause eventually became clear. The problem only occured with Release mode compiled code and initially I thought the problem might be due to code optimisation. After ruling this out by disabling optimisation in Release mode compiles, I realised that it was the Debug Info setting that is accessed using the Advanced button on the Build tab of the project properties page. The problem didn’t occur when this was set to Full (as used in Debug mode builds) but did occur when it was set to PDB Only (used in Release mode builds) or None.

Using the debugger to step through the tracing code it became clear that when Debug Info is set to Full there is an extra frame on the stack between the stack frame for Main() and the tracing code’s constructor. Presumably, the Full setting causes some interception code to be generated by the C# compiler that results in the additional stack frame. So, in Release mode builds the tracing code was stepping too far up the call stack and when the caller was the program entry point this caused a NullReferenceException.

I considered updating the tracing code to examine the stack frames and determine how far up the call stack it needed to step but was concerned that this might add a significant performance overhead when tracing is active. Instead, I decided to define conditional compilation constants to indicate which Debug Info setting is active. The stack frame constant is then defined conditionally. The tracing code needs to step nine frames up the call stack when Debug Info is set to Full or eight when set to PDB Only or None:

#if DEBUGINFO_FULL
        private const int BaseStackFrameOffset = 9;
#endif
#if DEBUGINFO_PDBONLY || DEBUGINFO_NONE
        private const int BaseStackFrameOffset = 8;
#endif
Advertisements

Written by Sea Monkey

September 14, 2011 at 8:00 pm

Posted in Debugging, Development

Tagged with , ,

One Response

Subscribe to comments with RSS.

  1. Hi, I’m from Chile, your a master! You post works for me, I have X project and Y project, that X project reference to Y.

    X project send to Log to Y project. In my Y project I get the name of called method:

    int framesQty = 2; //it was defined in constant variable
    MethodBase mb = new StackFrame(framesQty + 1, true).GetMethod();

    And the “mb” object in Release mode only, not worked, is null!.

    Now thanks you post, I put:
    #if DEBUG
    framesQty += 1;
    #endif
    MethodBase mb = new StackFrame(framesQty, true).GetMethod();

    In the Project properties / Build / Advanced. I not changed nothing (“PDB Only”)

    AND WORKS! After 2 days.

    Hernaldo Gonzalez

    August 20, 2014 at 3:48 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: