【发布时间】:2009-08-11 01:24:19
【问题描述】:
用于 32 位系统的 C++ 开发(无论是 Linux,Mac OS 或
Windows,PowerPC 或 x86)我已经初始化了指针
否则将是未定义的(例如,他们不能立即
得到一个合适的值)像这样:
int *pInt = reinterpret_cast<int *>(0xDEADBEEF);
(为了节省打字和成为DRY,右侧通常会 保持不变,例如BAD_PTR。)
如果 pInt 在获得正确值之前被取消引用,那么 它会在大多数系统上立即崩溃(而不是 当某些内存被覆盖或消失时,会在很久以后崩溃 进入一个很长的循环)。
当然,行为取决于底层 硬件(从奇数中获取 4 字节整数 来自用户进程的地址 0xDEADBEEF 可能是完美的 有效),但是对于所有的崩溃都是 100% 可靠的 到目前为止我开发的系统(Mac OS 68xxx,Mac OS PowerPC, Linux Redhat Pentium, Windows GUI Pentium, Windows 控制台奔腾)。例如在 PowerPC 上它是非法的(总线 fault) 从一个奇数地址获取一个 4 字节整数。
这在 64 位系统上有什么好的价值?
【问题讨论】:
-
我见过一些系统,其中前 1K 内存被定义为无效。因此,如果取消引用 NULL 指针,该进程将很快死亡。 0xDEADBEEF 可能是一个有效的位置。
-
@Robert:我见过中断向量从 0 开始的系统,因此取消引用 NULL 函数指针似乎只是重新启动系统(但不会重新初始化堆栈等)。任何地址都可能是某物的有效位置。
-
@bk1e:IVT 应该从不可以从用户模式访问。但是您是正确的,因为没有理由无法映射地址
0。在 Linux 中,通过更改内核中的选项很容易映射到地址0。无论如何,这里学到的教训是不要使用愚蠢的模式将指针标记为无效,使用null或结构中的单独标志。假设它会崩溃是完全不负责任和无知的,如果你幸运的话,你只会得到一个段错误,这很可能会导致远程代码执行,并且过去已经有很多很多次了。 -
@bk1e,但 C 标准保证 NULL(以及分别转换为指针的 0)将是您无法取消引用的无效指针。
-
@iconiK:“不能取消引用”是什么意思?您当然可以取消引用 NULL,但结果是未定义的行为(根据 C99 第 6.5.3.2 节)。空指针保证与任何对象或函数比较不相等(根据 C99 第 6.3.2.3 节),因此如果地址 0 处存在 C 对象或 C 函数,编译器应该将
(void*)0转换为指向除地址 0。但是,中断向量表不是 C 对象或 C 函数,所以我认为编译器没有义务保证 NULL 不指向中断向量表。
标签: c++ debugging 64-bit defensive-programming