c++ - 非 NULL 保留指针值

标签 c++ c pointers magic-numbers type-punning

如何创建保留指针值?

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

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

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

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

最佳答案

在任何现代系统上,您都可以使用指针值 12、... 4095 来实现此类目的。另一个常用的选择是 (uintptr_t)-1,它在技术上较差,但比 1 使用得更频繁。

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

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

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

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

关于c++ - 非 NULL 保留指针值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20718384/

相关文章:

c++ - 在 C++ 中读取 RAW 图像或 RAW 图像有标题吗?

c++ - 使用 strlen() 查找字符串数组的长度

c - 在 Win32 应用程序中使用 C 而不是 C++ 从 URL 读取 XML

c - Lex&YACC编译错误: expected ')' before '.' token

c++ - C++ 中的 23 位用户定义类型

c++ - "std::cout"在 Android-ndk 中是否可用

c - 将文件中的 ASCII 字符读入数组

c - int * (*) 的类型 (int * , int * (*)())

c - 以连贯的方式打印 (int *) 类型的指针

c - 移动指针以便以不同的顺序打印