对齐的内存分配器:内存损坏(游戏引擎架构[Jason Gregory])

时间:2014-06-29 13:01:48

标签: c++ memory architecture game-engine memory-alignment

我正在阅读Game Engine Architecture by Jason Gregory S.212,当我偶然发现他正在分配对齐内存的代码时。我认为他正在制造内存损坏,我自己尝试使用以下代码:

void* myalloc( unsigned size )
{
    // this will not return a valid memory address but its ok since
    // it will never be dereferenced! its just to check what if a real malloc would
    // return this obviously UNALIGNED memory address
    return reinterpret_cast<void*>( 0x00001 );
}
void* allocatedAligned( unsigned size_bytes, unsigned alignment )
{
    unsigned expandedSize_bytes = size_bytes + alignment;
    unsigned rawAddress = (unsigned)myalloc( expandedSize_bytes );

    unsigned mask = alignment - 1;
    unsigned misalignment = rawAddress & mask;
    unsigned adjustment = alignment - misalignment;

    unsigned alignedAddress = rawAddress + adjustment;

    unsigned* ptrAdjustment = reinterpret_cast<unsigned*>( alignedAddress - 4 );
    //*ptrAdjustment = adjustment; //Corruption here
    //return reinterpret_cast<unsigned*>( alignedAddress ); this is what jasons function normally returns
    return ptrAdjustment;
}

int main()
{
    void* ptr = allocatedAligned( 4, 4 );
    std::cout << ptr << std::endl; // this shouldn't print an address lower than 0x0001
    return 1;
}

对齐的工作原理应该如此,但我必须对行*ptrAdjustment = adjustment,因为它会破坏内存。它在从myalloc()收到的地址之前写入内存,还是我错了? main()不应该打印任何小于myalloc()返回的地址?!

我期待着你的回答,谢谢!

注意:这个例子是关于:写入内存的位置,而不是:myalloc()返回错误的内存....

(我对代码的更改:

  • 使用无符号而非U32
  • 使用myalloc()代替allocateUnaligned()
  • c ++ cast而不是c-style )

3 个答案:

答案 0 :(得分:2)

代码被破坏了。如果malloc将返回已经正确对齐的地址,比如0并且您请求8字节对齐的地址,则代码将返回地址4,这显然是错误的。应删除以下行:

unsigned* ptrAdjustment = reinterpret_cast<unsigned*>( alignedAddress - 4 );

代码应该只返回alignedAddress:

return reinterpret_cast<unsigned*>( alignedAddress );

(也应该是void*而不是unsigned*,他应该使用size_t而不是unsigned)。如果您希望代码返回原始的malloc()地址,以防它已经正确对齐,您只需将上面的行更改为:

return reinterpret_cast<void*>(misalignment?alignedAddress:rawAddress);

同样要迂腐,应该在函数中断言以验证对齐是2的幂,例如assert((alignment&(alignment-1))==0);

答案 1 :(得分:1)

完成示例的计算:

size_bytes为4,unsigned alignment为4

expandedSize_bytes设置为8

mask设置为3

misalignment设置为1&amp; 3是1。

adjustment设置为4 - 1,即3。

alignedAddress设置为0x0001 + 3,即4。

ptrAdjustment设置为4 - 4,即0x0000。

所以是的,如果您的示例场景确实发生了,那注释掉的行会尝试写入分配区域之外的内存。

另一方面,如果原始地址已经对齐至少4并且请求的对齐为4或更大,那么看起来数学计算结果是没有无效的内存访问。也许作者认为会是这种情况。或许也许他只针对那种场景测试了他的数学。毕竟,使用现代C / C ++ malloc本身应该只返回具有合理对齐的地址。

答案 2 :(得分:0)

我没有读过你提到的这本书和这种特殊的技巧。但我认为有一些基本概念需要提及来回答你的问题。

  

但我必须反对行* ptrAdjustment =调整,因为它恕我直言   腐蚀记忆

这不是内存损坏的示例,因为上面的程序不在示例代码中分配内存。上面的程序在

行崩溃了
*ptrAdjustment = adjustment; 

因为 ptrAdjustment 指针没有从堆内存分配器接收的有效内存(NULL指针)。因为在上面的代码中我们没有分配任何内存。

我认为我们需要更改上面的代码以从malloc()API分配地址。这样 myalloc 将返回有效内存。

void* myalloc( unsigned size )
{
    return reinterpret_cast<void*>( malloc(size) );
}

然而,我们不应该打扰(直到绝对需要)很多关于地址的对齐,因为内存分配器会返回正确对齐的地址(8或16字节)。

此外,您的程序必须编写 myfree() 类型的函数来释放由 myalloc()分配的内存即可。这与内存损坏同样严重。

在C ++程序中,我们应该避免使用原始指针,而是开始使用STL containersmart pointer