Today I tried to run a small .NET application, that I am using for more than 5 years already. It serves a small but very important purpose in my personal data management. I guess the author of this app, which I have great respect of, will be really surprised to find out anyone is still using his app out there.
When I started the application I’ve got the following error message:
In case you are missing Debug the program option you need to install some JIT debugger like Visual Studio, WinDbg or other. I will get into details of how this works in Windows in another post.
If you open the details of this crash you will get almost no meaningful information:
Problem Event Name: APPCRASH
Application Name: pwm.exe
Application Version: 184.108.40.206
Application Timestamp: 48014697
Fault Module Name: KERNELBASE.dll
Fault Module Version: 6.1.7601.17651
Fault Module Timestamp: 4e21213c
Exception Code: e0434f4d
Exception Offset: 000000000000cacd
OS Version: 6.1.7601.2.1.0.256.1
Locale ID: 1033
We can see from the above that the program stopped working (we’ve kind of knew that already) and that the exception goes from within kernelbase.dll. Given that I know upfront this is a managed application, having a crash at kernelbase.dll does not feel good.
I have Visual Studio installed already so I just selected Debug the program option and then Yes on Visual Studio Just-in-Time debugger dialog.
From the dialog box above you can now see the exception type in top level text saying: An unhandled exception (‘System.BadImageFormatException’) occurred in pwm.exe .
Digging through MSDN does not help much either: Troubleshooting Exceptions: System.BadImageFormatException - A BadImageFormatException exception is thrown when the file image of a DLL or executable program is not valid. Make sure the file image is a valid managed assembly or module. This exception is thrown when unmanaged code is passed to for loading.
At this place I stopped for a moment. I didn’t want to go into the debugger if the problem is not requiring it. As a general rule, use the right tool for the right job. Or you might spent countless hours trying to solve the problem with the wrong tool.
Tip: In case you read my previous blog post you may want to try your SOS skills and debug the application using Visual Studio after all :) Chances are that you will get the following error after you run .load sos command: Unable to evaluate the expression. This error comes to say that at point of the execution of the program there is no managed code loaded yet. In short – loading sos does not make sense here and Visual Studio can not load the debugging extension. I am with you that a better error message should be provided.
So I have BadImageFormatException and MSDN saying that the image may not be valid. I tried restoring the files in the folder from my backup drive. That did not change anything though.
I also tried looking at the assembly binding log using Assembly Binding Log Viewer aka FUSLOGVW. One of my theories was that the machine was missing some of the .NET binaries. Fusion log showed that the problem was situated in an assembly called NativeHelpers:
Double clicking on the particular trace, give you more details on the problem:
The operation failed.
Bind result: hr = 0x8007000b. An attempt was made to load a program with an incorrect format.
In case you want to know more about Fusion log viewer please read the all time blog post from Suzanne Cook - Debugging Assembly Loading Failures. And in order to keep this post short and focused I will write more about Fusion log viewer in another post.
Then I asked myself a question – what changed that it was working before and now it is not working. Well, that was obvious to tell, at least to me. Last night I finally managed to reinstall my laptop with fresh new installation of Windows 7. However this time I decided to go with x64 edition as opposed to the x86 version. The last one I was running for more than an year. After small memory upgrade it was about the time for me to make the switch.
Suddenly it occurred to me that BadImageFormatException might actually mean that the assembly is not built to run in x64 environment. So I decided to try a small trick. There a tool in .NET Framework SDK that allows you to change the bitness of the assembly. It is called CorFlags.exe and is usually located at C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin. Your mileage may vary.
So I went ahead and run corflags.exe /32BIT+ pwm.exe. That is the main executable of the application. The parameter /32BIT+ sets the 32 bit of the assembly. Short example on how to use corflags with 32BIT parameter you may find in the Corflags.exe in 64-bit Environment blog post from Matevz Gacnik.
Volla! My application got running and life’s good again. I happen to have the sources of the app so I loaded the project in Visual Studio just to verify the root cause of the problem. I found out that NativeHelpers is a managed C++ project. As such this project is built using the Win32 configuration. Managed C++ projects doesn’t have Any CPU configuration type as C# managed projects do. Needless to say all the rest of the projects were configured as Any CPU type. Hence CLR started pwm.exe as x64 process (like the OS type it was running on) and then CLR tried to load NativeHelpers as a x86 assembly. That causes file format incompatibility and BadImageFormatException is thrown by CLR.
What does it mean to you as a developer – learn what project configurations are for in Visual Studio. Learn how to deal with deployment on x86 and x64 platforms. Also learn what Any CPU means. A nice resource wrapping up all these topics is located at Moving from 32-bit to 64-bit application development on .NET Framework blog post from Gaurav Seth. Pay attention to the resources at the end of the blog post too.