c++overflowinteger-overflowcl.exe

Pointer arithmetic confusion or weird behavior


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.


Solution

  • 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
        }
    }