为了避免溢出,对象可以接近最大指针值

How near to the maximum pointer value can an object be to avoid overflow?

本文关键字:接近 指针 对象 溢出      更新时间:2023-10-16

一个有效指针(作为全局指针,在堆栈上分配,mallocnewVirtualAlloc或程序/库可能使用的任何其他分配方法)可以接近最大值多少,这样ptr + n就有溢出的风险?

我遇到了很多在处理字符串/数组时向指针添加值的代码(在C++中,有时也在通用的"随机访问迭代器"模板函数中)。

例如

auto end = arr_ptr + len; //or just whatever some_container.end() returns
for (auto i = begin; i < end; ++i) { ... }
for (auto i = begin; i + 2 <= end; i += 2) { ...i[0]...i[1]... }
if (arr_ptr + 4 <= end && memcmp(arr_ptr, "test", 4) == 0) { ... }
if (arr_ptr + count > end) resize(...);

最后一个数组元素以0xFFFFFFFF结束(假设为32位),这样end == 0是否有效?如果不是,它能有多近?

我认为总是使用p != end(并且只添加1)或将长度取为len = end - begin,然后使用它(例如(end - begin) >= 4)总是安全的,但我想知道这是否真的是一个需要注意的问题,以及审计和更改现有代码的问题。

该标准不讨论指针溢出,而是讨论指针算术可以合法地形成哪些指针值。简单地说,合法范围是指向对象/数组的指针加上一个超过结束指针的指针。

然后,C或C++实现有责任不在某些特定于实现的危险(如指针溢出)阻止这些合法指针值正常工作的位置创建任何对象。

因此,无论是malloc等,还是堆栈(假设您没有超过任何堆栈边界),都不会给您一个char数组,从您无法(由于溢出)添加数组大小的地址开始。

它能有多近?

尽可能接近允许所有必需的指针值正常工作。因此,在这个32位系统上,从0xFFFFFFFE开始的1字节对象将是最大可能的地址。标准不允许将2添加到地址中,因此就实现而言,这样做会溢出"无关紧要"。对于一个2字节的对象,如果类型未对齐,则最大值为0xFFFFFFFD,但这是一个奇数,因此如果需要2对齐,则为0xFFFFFFFC

当然,其他实现细节可能会规定一个下限。例如,系统在0的任一侧保留一页内存并使其不可访问,这并不罕见。这有助于捕捉有人访问了偏移量较小的空指针的错误。诚然,正偏移比负偏移更有可能发生这种情况,但仍然如此。如果您的32位系统决定这样做,那么malloc将需要考虑到这一点,并且永远不会返回0xFFFFFFFE