C++ 对齐内存分配器:内存损坏(游戏引擎架构[Jason Gregory])
我正在读S.212,无意中发现了他分配对齐内存的代码。我认为他正在产生内存损坏,我自己用以下代码进行了尝试:C++ 对齐内存分配器:内存损坏(游戏引擎架构[Jason Gregory]),c++,memory,architecture,game-engine,memory-alignment,C++,Memory,Architecture,Game Engine,Memory Alignment,我正在读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 // ret
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;
}
void*myalloc(无符号大小)
{
//这将不会返回一个有效的内存地址,但它是确定的,因为
//它永远不会被取消引用!它只是为了检查一个真正的malloc是否会被取消引用
//返回这个明显未对齐的内存地址
返回重新解释(0x00001);
}
void*allocatedAligned(无符号大小\字节,无符号对齐)
{
unsigned expandedSize\u bytes=大小\u字节+对齐;
unsigned rawAddress=(unsigned)myalloc(expandedSize_字节);
无符号掩码=对齐-1;
无符号不对中=原始地址和掩码;
无符号调整=对准-未对准;
无符号对齐地址=原始地址+调整;
无符号*ptrAdjustment=reinterpret_cast(对齐地址-4);
//*ptrAdjustment=adjustment;//此处已损坏
//返回reinterpret_cast(alignedAddress);这是jasons函数通常返回的结果
返回PTR调整;
}
int main()
{
void*ptr=allocatedAligned(4,4);
我还没有读过你提到的这本书,也没有读过这个特殊的技巧。但是我认为有一些基本的概念需要被提及来回答你的问题
但是我必须反对这条线,因为它是
破坏记忆
这不是内存损坏的例子,因为上面的程序没有在示例代码中分配内存。上面的程序在第行崩溃
*ptrAdjustment = adjustment;
因为ptrAdjustment指针没有从堆内存分配器接收到有效内存(空指针)。因为在上面的代码中,我们没有分配任何内存
我认为我们需要更改上面的代码来从malloc()API分配地址。这样myalloc将返回有效内存
void* myalloc( unsigned size )
{
return reinterpret_cast<void*>( malloc(size) );
}
void*myalloc(无符号大小)
{
返回重新解释铸件(malloc(尺寸));
}
然而,我们不应该太在意地址的对齐(除非绝对需要),因为内存分配器确实返回正确对齐的地址(8或16字节)
此外,您的程序必须编写myfree()类函数来释放myalloc()分配的内存。这与内存损坏一样严重
<> P>在C++程序中,我们应该避免使用原始指针,而是通过使用示例的数学来开始使用AND.</P> < P>:
size\u字节
为4,而无符号对齐
为4
expandedSize\u字节
设置为8
mask
设置为3
未对准
设置为1&3,即1
调整
设置为4-1,即3
alignedAddress
设置为0x0001+3,即4
ptrAdjustment
设置为4-4,即0x0000
是的,如果您的示例场景实际发生,注释掉的行将尝试写入分配区域之外的内存
另一方面,如果原始地址已经至少对齐了4,并且请求的对齐是4或更大,那么看起来数学是可行的,这样就不会有无效的内存访问。可能作者假设会是这样。或者可能他只是针对这些场景测试了他的数学。毕竟,使用现代C/C++malloc本身应该只返回具有合理对齐方式的地址。代码已断开。如果malloc将返回已正确对齐的地址,例如0,而您请求8字节对齐的地址,则代码将返回地址4,这显然是错误的。应删除以下行:
unsigned*ptrAdjustment=reinterpret\u cast(alignedAddress-4);
代码应该只返回alignedAddress:
return reinterpret\u cast(alignedAddress);
(也应该是void*
notunsigned*
,他应该使用size\t
notunsigned
)。如果您希望代码返回原始malloc()地址,以防它已经正确对齐,您只需将上面的行更改为:
return reinterpret\u cast(未对齐?对齐地址:rawAddress);
同样要学究化,函数中应该有assert来验证对齐是否为power-of-2,例如assert((对齐和(对齐-1))==0)
我知道myalloc没有返回有效内存;)它只是关于主内存中的打印…如果malloc返回有效内存,它将损坏内存…myalloc只是一个“黑客”看看会发生什么…@lifeOfPI:正如我提到的,我没有访问你提到的那本书的权限。因此,我不知道作者编写自定义内存分配器以使内存地址与特定值对齐的目的是什么。但总而言之,在程序中对内存的任何访问超出请求的大小都会导致内存损坏on.谢谢你的回答,但这些都是我没有要求的信息…不关心容器、免费、malloc等…只是:这是一个腐败吗?是/否!我没有尝试malloc,因为正如你所说的,你获取的地址具有合理的对齐方式。也许他的意图是重新对齐ie.4字节对齐d地址到16或128字节对齐…代码可能会被破坏,但1.海报对书中的代码进行了修改。2.此处的原始海报未指明书作者的原始意图,因此建议的修复不起作用。ptrAdjustment故意在原始地址和这些地址的前2字节返回“wasted”用于存储地址的调整量,以便在调整地址时