在兼容 AMD64 的架构上,地址在被取消引用之前需要采用规范形式。
在 64 位模式下,如果地址位 63 到微架构实现的最高有效位被设置为全 1 或全零,则地址被认为是规范形式的。
现在,当前操作系统和体系结构上最重要的实现位是第 47 位。这给我们留下了一个 48 位的地址空间。
特别是当启用ASLR时,用户程序可以期望接收到第 47 位设置的地址。
如果使用诸如指针标记之类的优化并且使用高位来存储信息,则程序必须确保在取消引用地址之前将第 48 位到第 63 位设置回第 47 位。
但是考虑一下这段代码:
int main()
{
int* intArray = new int[100];
int* it = intArray;
// Fill the array with any value.
for (int i = 0; i < 100; i++)
{
*it = 20;
it++;
}
delete [] intArray;
return 0;
}
现在考虑一下intArray
,说:
0000 0000 0000 0000 0 111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1100
设置it
为intArray
并增加it
一次后,考虑sizeof(int) == 4
,将变为:
0000 0000 0000 0000 1 000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
第 47 位以粗体显示。这里发生的是指针算术检索到的第二个指针无效,因为不是规范形式。正确的地址应该是:
1111 1111 1111 1111 1 000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
程序如何处理这个问题?操作系统是否保证永远不会为您分配地址范围不随第 47 位变化的内存?