Now filed on Microsoft Connect; please upvote if you feel it needs fixing. I've also simplified the test case a lot:
byte* data = (byte*) 0x76543210;
uint offset = 0x80000000;
byte* wrong = data + offset;
byte* correct = data + (uint) 0x80000000;
// "wrong" is now 0xFFFFFFFFF6543210 (!)
// "correct" is 0xF6543210
Looking at the IL, as far as I can tell, the C# compiler did everything right, and the bug lies in the JITter.
Original question: What is going on here?
byte* data = (byte*)Marshal.AllocHGlobal(0x100);
uint uioffset = 0xFFFF0000;
byte* uiptr1 = data + uioffset;
byte* uiptr2 = data + (uint)0xFFFF0000;
ulong uloffset = 0xFFFF0000;
byte* ulptr1 = data + uloffset;
byte* ulptr2 = data + (ulong)0xFFFF0000;
Action<string, ulong> dumpValue =
(name, value) => Console.WriteLine("{0,8}: {1:x16}", name, value);
dumpValue("data", (ulong)data);
dumpValue("uiptr1", (ulong)uiptr1);
dumpValue("uiptr2", (ulong)uiptr2);
dumpValue("ulptr1", (ulong)ulptr1);
dumpValue("ulptr2", (ulong)ulptr2);
This test requires a 64-bit OS targeting the x64 platform.
Output:
data: 000000001c00a720 (original pointer) uiptr1: 000000001bffa720 (pointer with a failed carry into the higher dword) uiptr2: 000000011bffa720 (pointer with a correct carry into the higher dword) ulptr1: 000000011bffa720 (pointer with a correct carry into the higher dword) ulptr2: 000000011bffa720 (pointer with a correct carry into the higher dword) ^ look here
So is this a bug or did I mess something up?