[英]Why does this addition of byte* and uint fail to carry into the higher dword?
Now filed on Microsoft Connect ; 现在提交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. 看看IL,就我所知,C#编译器做的一切都正确,错误在于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. 此测试需要针对x64平台的64位操作系统。
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? 那么这是一个错误还是我搞砸了什么?
I think you are encountering this C# compiler bug: https://connect.microsoft.com/VisualStudio/feedback/details/675205/c-compiler-performs-sign-extension-during-unsigned-pointer-arithmetic 我认为您遇到了这个C#编译器错误: https : //connect.microsoft.com/VisualStudio/feedback/details/675205/c-compiler-performs-sign-extension-during-unsigned-pointer-arithmetic
Which was filed as a result of this question: 64-bit pointer arithmetic in C#, Check for arithmetic overflow changes behavior 这是由于这个问题提出的: C#中的64位指针算法,检查算术溢出改变行为
(Answer under construction) (正在建设中的答案)
I checked the emitted x64 asm and these are my observations: 我检查了发出的x64 asm,这些是我的观察结果:
Base pointer: 基指针:
data:
00000000024539E0
Pointer with correct carry: 带正确携带的指针:
data + (uint)0xFFFF0000:
00000001024439E0
Disassembly of the instructions: 拆卸说明:
byte* ptr2 = data + ((uint)0xFFFF0000); // redundant cast to be extra sure
00000084 mov ecx,0FFFF0000h
00000089 mov rax,qword ptr [rsp+20h]
0000008e add rax,rcx
00000091 mov qword ptr [rsp+38h],rax
Pointer with incorrect carry: 携带不正确的指针:
data + offset:
00000000024439E0
Disassembly of the instructions: 拆卸说明:
uint offset = 0xFFFF0000;
0000006a mov dword ptr [rsp+28h],0FFFF0000h
byte* ptr1 = data + offset;
00000072 movsxd rcx,dword ptr [rsp+28h] ; (1)
00000077 mov rax,qword ptr [rsp+20h]
0000007c add rax,rcx
0000007f mov qword ptr [rsp+30h],rax
The instruction (1) converts an unsigned int32 into a signed long with sign extension (bug or feature?). 指令(1)将unsigned int32转换为带符号扩展(bug或feature?)的带符号long。 Therefore
rcx
contains 0xFFFFFFFFFFFF0000
, while it should contain 0x00000000FFFF0000
for the addition to work properly. 因此
rcx
包含0xFFFFFFFFFFFF0000
,而它应该包含0x00000000FFFF0000
以使加法正常工作。
And according to 64 bit arithmetic: 并根据64位算术:
0xFFFFFFFFFFFF0000 +
0x00000000024539E0 =
0x00000000024439E0
The add overflows indeed. 添加溢出确实。
I don't know if this is a bug or intended behavior, I'm going to check SSCLI before trying to give any conclusion. 我不知道这是一个错误或预期的行为,我会在尝试给出任何结论之前检查SSCLI。 EDIT: See Ben Voigt's answer.
编辑:见Ben Voigt的回答。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.