Samstag, 06. Dezember 2008, Christoph Ertl
A few days ago I had a problem at a .NET 1.1 project where the release version of the application had a different behavior than the debug version. I felt like in the old days when developing with C++ and struggling through precompiler instructions.
The beginning
Tried to reproduce the bug with a Unit test which was not possible. Had a detailed look at the production data and refined the unit test. No success. At this point I had the suspicion that this could' be a debug vs. release problem. Tried the unit test in release mode and the test failed.
OK. There's a difference but how to find out where and what is the difference? And if found, why is there a difference?
Where's the difference?
Even with the information from the unit test it's not easy to find out why there is a difference. First of all we have to find the location of the difference. To find the location I used a profiler while running the unit test in debug and in release mode.
Then I compared the two call stacks and within seconds I got the method where the difference was located.
callstack (orderd by execution time) as expected in the debug execution.

different callstack (ordered by execution time) in the release execution.
What's the difference?
Now we know the method were the difference is located. The next step is to compare the code of the release and debug assembly. This is best done using Redgate's .NET reflector.
Comparing the methods is an easy task with .NET Reflector. If your method is too large you can use an add-in which supports comparing two assemblies.
Why is there a difference?
While comparing the two version of the code you see in detail what's different. But why?
The difference can be caused by some reasons:
- Removed code in release assembly because of the Conditional attribute.
Check the method which is missing in the callstack if it is marked with this attribute. - The difference can also be caused by a compiler optimization like inlining etc. but this should not lead to a different behavior unless there is an
- Error in the compiler
In this case you must try to change your code and see what's the result. A detailed inspection and understanding of the differences can help.
The found bug
For the sake of completeness the details about the bug I found. This bug only arises with the compiler shipped with Visual Studio .NET 2003. With Visual Studio .NET 2005/2008 there were no problems.
The code written in the editor:
private static void DoIt(bool flag) {
if(flag) {
using(MyDisposable d = DoItNormal()) {
}
}
else {
DoItDifferent();
}
}
The debug version inspected with .NET Reflector:
The release version inspected with .NET Reflector:
Removing the empty using block and calling Dispose() explicitly solves the problem.
References