Bitness of .NET Assembly
The product that I work on is almost a decade old and uses .NET Framework. Its early versions were compiled for 32-bit processors using the x86
compiler option. When product was migrated to 64-bit processor architecture, the compiler option was switched to AnyCPU
. We did not use the option x64
because we had to support both architectures during the transition period. Using AnyCPU
ensures the assembly get JIT-compiled to match the bitness of the process that launched it. That is —
At runtime, byte code of an AnyCPU .NET assembly of type DLL would get compiled to 32-bit machine code when launched by 32-bit process. Like wise, translated to 64-bit machine code if launched by 64-bit process.
A .NET assembly can also be an executable (.exe). And when such an executable is of type
AnyCPU
, it would be launched as a 32-bit process on 32-bit processor/OS and as 64-bit process on a 64-bit processor.
The runtime exception that occurs when there is mismatch of bitness of process and assembly is System.BadImageFormatException
System.BadImageFormatException: Could not load file or assembly ‘Some Assembly Signature>’ or one of its dependencies. An attempt was made to load a program with an incorrect format
Once in a while, we encounter this exception in our old customer deployments that use 32-bit version of our product. Due to unavailability of 64-bit version of certain third-party libraries, developers explicitly switch the flag to x86
. Sometimes this happens inadvertently during build and patch creation and an incorrect assembly is deployed — leading to the above exception. When this happens how do you go about troubleshooting?
First Step: Find bitness of the process
To find the bitness of the process that is throwing the exception, look into Task Manager on Windows OS. Click ‘Details’ tab, if the ‘Platform’ column is not shown, right-click
on any column name and choose Select columns
menu option and from the popup chose Platform
, From Task Manager you can find this information looking at the ‘Platform’ column as shown below.
If your application is web app hosted by IIS, then you should check w3p.exe which is worker process that hosts the web app (IIS Worker process bitness is controlled by the ‘Enable 32-bit Application’ settings of the Application Pool configured for your Web App is running).
Second Step: Find bitness of .NET assembly
There are couple of options based on the situation.
From Source Code
If the culprit assembly belongs to your app and have access to the source of the version deployed, you could load the project is Visual Studio and check Platform target
property of the project as shown below.
Probing the Assembly using corflags
Visual Studio and .NET SDK has a tool called corflags
. You can probe your assembly using this tool.
Launch Developer Command Prompt for Visual Studio and then type command corflags <FullPathAndFileNameOfYourAssembly>
. The output would consist of few flags which can be interpreted as follows.
If PE = PE32 & 32BITREQ = 1 Then
Assembly will run as x86 (32-bit) only.
If PE = PE32+ Then
Assembly will run as x64 (64-bit) only.
If PE = PE32 & 32BITREQ = 0 and 32BITPREF = 0 Then
Assembly will run as AnyCPU (32-bit/64-bit depending on launching bitness of launching process)
If PE = PE32 & 32BITREQ = 0 and 32BITPREF = 1 Then
Assembl will run as 32-bit on a 64-bit processor.
Disassemble the Assembly!
In the absence of Visual Studio or .NET SDK, free or Open Source decompilers like ILSpy (Open source) or Jetbrains dotPeek (Free) can be used to browse reverse engineered source of .NET assembly. These tools also show the bitness of loaded assembly.
Additional References
Back to Basics: 32-bit and 64-bit confusion around x86 and x64 and the .NET Framework and CLR
How to interpret the CorFlags flags?
My Post — Decompiler Tools — A friend in need, to know a little more about ILSpy and dotPeek