非NULL保留指针值
non-NULL reserved pointer value
如何创建保留指针值?
上下文是这样的:我一直在考虑如何实现动态脚本语言的数据结构(我不打算实现这个,只是想知道如何实现)。
字符串可以包含任意字节,包括NUL。因此,有必要单独存储该值。这需要一个指针(指向数组)和一个数字。第一个技巧是,如果指针为NULL,则它不可能是有效的字符串,因此该数字可以用于实际的整数。
如果可以创建第二个保留指针值,这可以用来暗示另一个字段现在被用作浮点值。这能做到吗?
一种想法是mmap()一个没有权限的地址,这也可以用来代替NULL指针的使用。
在任何现代系统上,只需使用指针值1
、2
。。。CCD_ 3。另一个常见的选择是(uintptr_t)-1
,它在技术上较差,但使用频率高于1
。
为什么这些价值观是"安全的">
现代系统通过不可能映射虚拟地址0处的任何内容来防止NULL指针访问。几乎任何对NULL指针的取消引用都会碰到这个不存在的区域,硬件会告诉操作系统发生了不好的事情,这会触发操作系统中断进程
由于虚拟内存页面是页面对齐的(在当前硬件上至少4k),并且没有任何东西映射到地址零,因此没有任何东西可以映射到整个范围0, ..., 4095
,以相同的方式保护所有这些地址,并且您可以将它们用作特殊用途值。
为此保留多少虚拟内存空间是一个系统参数,在linux上由/proc/sys/vm/mmap_min_addr
控制,根用户可以将其更改为零,这将禁用这种保护(这不是一个非常明智的想法)。Ubuntu上的默认值是64k(即16页)。
这也是(uintptr_1)-1
的安全性不如1
的原因;即使超过一个字节的任何加载都将命中零页,地址(uintptr_1)-1
本身也不一定以这种方式受到保护。因此,在(char*)-1
上执行字符串操作不一定是segfault。
编辑:
我最初对特殊映射的解释似乎有点过时,可能这是旧Mac/PPC平台上处理事情的方式。尽管效果基本相同,但我更改了答案的细节以反映现代linux。无论如何,重要的一点不是如何实现空页保护,重要的是任何健全的现代系统都会有一些零页保护,至少包括上述地址范围。有关更多详细信息,请参阅SO的回答:https://stackoverflow.com/a/12645890/2445184
在标准C(和标准C++)中,100%有效且有效的方法很简单:声明一个变量,将其地址用作魔术值。
char *ptr;
char magic;
if (ptr == &magic) { ... }
这保证了magic
永远不会与另一个对象有任何重叠。
诸如CCD_ 13之类的魔术指针值也具有它们的优点,但很容易出错(即使你忽略(char *) 1
可能是有效对象的理论实现,如果你使用(int *) 1
作为魔术指针值,并且优化器假设int *
值适当对齐,它可能只会删除100%有效代码中没有操作的检查,而不是在你的代码中),我建议使用标准方法,只有当您发现魔术指针值有助于调试时,才可以选择临时切换到魔术指针值。
mmap
如果地址已分配,则寻址可能失败。可能最好使用某个静态变量或函数的地址。或者通过malloc(1)
获得唯一地址。
- 指针保留字符串
- 保留函数指针模板参数
- 如何在成为指向基类的指针后保留对子类方法的使用?
- 保留计时器集合(对象与指针)的最佳方法
- 更改保留指向其字段的原始指针的对象地址
- 释放指向保留嵌套变量内存地址的结构的指针
- 如果引用应该保留,不删除析构函数中的指针会导致内存泄漏吗?
- 如何在字符指针数组中保留指向每个单词的指针?
- 指向结构的指针保留某些属性,同时将其他属性重置为零(使用 map)
- 即使阵列腐烂到指针,如何将函数的参数保留为数组,这很好
- clock_nanosleep - 请求和保留的相同指针
- 如何在不覆盖C 中保留指针的价值
- 无法保留指向内存的指针
- 结构中的C++数组指针保留内存位置,但丢失所有值
- 删除动态数组,但保留指针
- 如何在参数中传递双重指针,以保留值
- C++:为指向两种类型之一的指针保留打开选项
- 返回类型,或如何保留对象指针的类型
- 保留存储在STL容器中的指针所指向的值(unordered_map)
- 非NULL保留指针值