2

如何创建保留的指针值?

上下文是这样的:我一直在考虑如何为动态脚本语言实现数据结构(我不打算实现这个 - 只是想知道它会如何完成)。

字符串可以包含任意字节,包括 NUL。因此,有必要单独存储该值。这需要一个指针(指向数组)和一个数字。第一个技巧是,如果指针为 NULL,则它不可能是有效字符串,因此该数字可用于实际整数。

如果可以创建第二个保留指针值,这可以用来暗示另一个字段现在被用作浮点值。这可以做到吗?

一种想法是 mmap() 一个没有权限的地址,也可以这样做来替换 NULL 指针的使用。

4

3 回答 3

7

在任何现代系统上,您都可以将指针值1, 2, ...4095用于此类目的。另一个常见的选择是(uintptr_t)-1,它在技术上较差,但使用频率更高1

为什么这些值是“安全的”?
现代系统通过使其无法在虚拟地址零映射任何内容来防止 NULL 指针访问。几乎任何对 NULL 指针的取消引用都会命中这个不存在的区域,并且硬件会告诉操作系统系统发生了一些不好的事情,这会触发操作系统对进程进行段错误。
由于虚拟内存页面是页面对齐的(在当前硬件上至少为 4k),并且没有任何内容映射到地址 0,因此没有任何内容可以映射到整个范围0, ..., 4095,以相同的方式保护所有这些地址,您可以将它们用作特殊用途价值观。

为此保留多少虚拟内存空间是一个系统参数,在 linux 上由 控制/proc/sys/vm/mmap_min_addr,root 用户可以将其更改为零,这将禁用此保护(这不是一个非常聪明的想法)。Ubuntu 上的默认值为 64k(即 16 页)。

(uintptr_1)-1这也是安全性低于1;的原因。即使任何超过一个字节的加载都会命中零页,但地址(uintptr_1)-1本身不一定以这种方式受到保护。因此,对字符串进行操作(char*)-1不一定会出现段错误。

编辑:
我对特殊映射的原始解释似乎有点陈旧,这可能是旧 Mac/PPC 平台上处理事情的方式。尽管效果几乎相同,但我更改了答案的细节以反映现代 linux。无论如何,重要的不是如何实现空页保护,重要的是任何理智的现代系统都会有一些至少包含上述地址范围的空页保护。可以在此 SO 答案中找到更多详细信息:https ://stackoverflow.com/a/12645890/2445184

于 2013-12-21T11:37:48.103 回答
5

在标准 C(和标准 C++)中,100% 有效且有效的方法很简单:声明一个变量,将其地址用作魔法值。

char *ptr;
char magic;
if (ptr == &magic) { ... }

这保证了magic永远不会与另一个对象有任何重叠。

诸如魔术指针值之类的值也(char *) 1有其优点,但是很容易弄错(即使您忽略了(char *) 1可能是有效对象的理论实现,如果您将(int *) 1其用作魔术指针值,并且优化器会假定int *值已适当对齐,它可能会删除仅在 100% 有效代码中而不是在您的代码中的无操作检查),我建议使用标准方法,并且仅当您发现它们可以帮助您调试时才可以选择临时切换到魔术指针值。

于 2013-12-21T11:57:19.257 回答
1

mmap如果地址已被分配,则该地址可能会失败。可能最好使用一些静态变量或函数的地址。或通过 获取唯一地址malloc(1)

于 2013-12-21T11:27:02.143 回答