繁体   English   中英

C ++最大有效内存地址

[英]C++ Maximum valid memory address

我经常看到代码添加一个值,例如指针的长度,然后使用这个值,例如

T* end = buffer + bufferLen;//T* + size_t

if (p < end)

但是,缓冲区是否有可能在“buffer + bufferLen”可能溢出的内存末尾附近分配(例如0xFFFFFFF0 + 0x10),导致“p <end”为假,即使p是有效的元素地址(例如0xFFFFFFF8)。

如果有可能的话,当我看到许多与开始/结束范围一起工作的东西时,如何避免在最后一个元素之后结束下一个元素

从标准:

5.9关系运算符[expr.rel]

如果两个指针指向同一数组的元素或超出数组末尾的指针,则指向具有较高下标的对象的指针会比较高。

所以你不必担心; 一致的实现将确保过去的结束指针与数组的其余部分正确比较。 此外,

3.7.4.1分配函数[basic.stc.dynamic.allocation]

[...]返回的指针应适当对齐,以便可以将其转换为具有基本对齐要求(3.11)的任何完整对象类型的指针,然后用于访问分配的存储中的对象或数组[.. ]

这意味着返回的指针应该能够被视为指向适当大小的数组开头的指针,因此5.9继续保持。 如果分配函数调用是调用operator new[] (5.3.4:5)的结果,则会出现这种情况。

实际上,如果你在一个平台上,可以想象分配器(非一致地)返回一个以0xFFFFFFFF结尾的内存块,你可以在大多数情况下写

if (p != end)

连续内存分配的元素不可能具有非连续的地址。 end始终具有比start更高的地址。

例如,在分配恰好以0xFFFFFFFF结束的情况下,意味着end将是0x00000000,这将是一个错误并且代码应该被修复以适应该场景。

在某些平台上虽然这种情况在设计上是不可能的,但为了简单起见,可能是逻辑上的合理折衷。 例如,我会毫不犹豫地在Windows用户模式应用程序上编写if(p < end)

确实,在许多[start, end)对算法端点超过最后一个有效条目。 但是你的实现永远不应该取消引用 end ,实际访问的最后一个条目应该是end-1 ,它保证在有效区域内。 如果你的算法解引用*end则是一个错误。 事实上,有一些测试分配器故意将该区域放在有效页面的最后几个字节上,然后是一个未分配的区域。 对于这样的分配器,解引用*end的算法将导致保护错误。

FLG_HEAP_PAGE_ALLOCS

打开页堆调试,该调试验证动态堆内存操作(包括分配和释放),并在检测到堆错误时导致调试器中断。

在系统注册表或内核模式下设置时,此选项在为图像文件和标准页堆调试设置时启用完整页堆调试。

  • 整页堆调试(对于/ i)在分配结束时放置一个不可访问的页面。

  • 标准页堆调试(对于/ r或/ k)在释放时检查分配。

为图像文件设置此标志与在命令行中为图像文件键入gflags / p enable / full相同

至于指针overfllow的问题:没有操作系统分配包含VA地址0xFFFFFFFF的页面,同样没有操作系统分配包含0x00000000的页面。 为了发生这种溢出, *start的大小必须足够大以使start+1跳过有效范围结束时的所有保留VA。 但是,在这种情况下,分配给addess start应该是最后一个有效VA地址如下至少一个这样的规模,这意味着start+1将是有效的(它遵循start+N也总是有效,只要start被分配为sizeof(*start)*N )。

别担心。 你的分配器(可能是new ,但也许是别的东西)不会给你一些如此接近它所包含的内存末尾的东西。

担心边界检查。 你永远不会得到像这样包装的分配,所以只要你不溢出数组(无论如何都有未定义的行为),你就不会结束。

注意为内核保留大块进程地址空间也很有用。 在大多数操作系统上,保留此高阶区域。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM