(Ответ в процессе разработки)
Я проверил испущенный x64 asm, и это мои наблюдения:
Базовый указатель:
data:
00000000024539E0
Указатель с правильным переносом:
data + (uint)0xFFFF0000:
00000001024439E0
Разборка инструкций:
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
Указатель с неправильным переносом:
data + offset:
00000000024439E0
Разборка инструкций:
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
Инструкция (1) преобразует беззнаковый int32 в длинное со знаком с расширением знака (ошибка или функция?).Поэтому rcx
содержит 0xFFFFFFFFFFFF0000
, в то время как оно должно содержать 0x00000000FFFF0000
для правильной работы сложения.
И согласно 64-битной арифметике:
0xFFFFFFFFFFFF0000 +
0x00000000024539E0 =
0x00000000024439E0
Действительно, переполнение add.
Я не знаю, является ли это ошибкой или предполагаемым поведением, я собираюсь проверить SSCLI, прежде чем пытаться дать какое-либо заключение.РЕДАКТИРОВАТЬ: см. Ответ Бена Фойгта.