When the following has run, I get _pfloatPos and _charPos being different:
float* const _pData = new float[0x50000000];
float* const _floatPos = _pData + 0x400000B0;
char* const _charPos = ((char*)_pData) + 0x400000B0 * 4;
if ((char*)_floatPos != _charPos)
{
throw "Derp.";
}
Maybe I've got brain fog and missed something basic. The two addresses should be the same, right?
I looked at the disassembly. 1000002C0h is 4 * 0x400000B0 . For the second one it seems to have been truncated at some point.
float* const _floatPos = _pData + 0x400000B0;
00007FF7CE48F6E2 mov rax,1000002C0h
00007FF7CE48F6EC mov rcx,qword ptr [_pData]
00007FF7CE48F6F0 add rcx,rax
00007FF7CE48F6F3 mov rax,rcx
00007FF7CE48F6F6 mov qword ptr [_floatPos],rax
char* const _charPos = ((char*)_pData) + 0x400000B0 * 4;
00007FF7CE48F6FA mov rax,qword ptr [_pData]
00007FF7CE48F6FE add rax,2C0h
00007FF7CE48F704 mov qword ptr [_charPos],rax
I am using visual Studio 2017 Version 15.9.2, but I'm not sure about the version of the compiler.
The two integer literals 0x400000B0 and 4 are each only given 4 bytes (even in x86-64), and so multiplying them causes an overflow. Appending L's doesn't change anything. Appending LL's makes them 64-bit, and solves the problem. But my solution will be to use std::int64_t for ints from now on.
Test:
#include <iostream>
#include <cassert>
using namespace std;
int main()
{
{ // plain literals
float* const _pData = 0;
float* const _floatPos = _pData + 0x400000B0;
char* const _charPos = ((char*)_pData) + 0x400000B0 * 4;
assert((char*)_floatPos != _charPos);
}
{ // append L
float* const _pData = 0;
float* const _floatPos = _pData + 0x400000B0L;
char* const _charPos = ((char*)_pData) + 0x400000B0L * 4L;
assert((char*)_floatPos != _charPos);
}
{ // append LL
float* const _pData = 0;
float* const _floatPos = _pData + 0x400000B0L;
char* const _charPos = ((char*)_pData) + 0x400000B0LL * 4LL;
assert((char*)_floatPos == _charPos); // success
}
}