Is IntPtr(long) truncating?
The short answer is: No, not when it matters
A colleague and I were discussing a particular scenario around IntPtr,PInvoke and 64 bit correctness. Eventually our discussion lead us to the IntPtr constructor which takes a long. To my surprise the code for the constructor is the following.
The problem is long value is arbitrarily truncated to an int. This has the effect of essentially losing any address over the 4 GB range (in other words, no 64 bit addresses). This much to big of a hole to actually be the real behavior so I decided to see if it was a bug in the disassembler. I was using .Net Reflector so I switched to IL mode.
L_0000: ldarg.0 L_0001: ldarg.1 L_0002: conv.ovf.i4 L_0003: conv.i L_0004: stfld void* System.IntPtr::m_value L_0009: ret
This confirmed it is indeed truncating the value (and doing an overflow check to boot). But wait, mscorlib.dll is a processor specific DLL so perhaps this is just a 32 bit OS thing. I switched over to a 64 bit machine, fired up Reflctor and found to my dismay that it had the exact same code.
After a few minutes I thought to open up task manager and to my surprise reflector was running in a WoW64 bit process. This meant it was still loading up the 32 bit version of mscorlib.dll. Next I fired up ildasm, loaded up a 64 bit mscorlib and confirmed that the code will not truncate on 64 bit machines.
IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: conv.u IL_0003: stfld void* System.IntPtr::m_value IL_0008: ret
The conv.u code is a conversion to unsigned native platform int. On a 64 bit machine this will be an unsigned 8 byte number(see OpCodes.Conv_U for more details).
So what does this mean for the developer. Essentially IntPtr(long) will do the right thing independently of the platform a developer is using. On a 32 bit platform it will (correctly) throw exceptions if a non-4GB address is passed in. In 64 bit land it will essentially do nothing and rely on the programmer to give correct addresses.