C中未初始化指针的危险究竟是什么?

我正在努力处理C,因为我通过Jim Trevor的“ 旋风:C语言的安全方言 ”为PL课程工作。 特雷弗和他的合着者正试图制作一个安全的C版本,因此他们用他们的语言消除了未初始化的指针。 在未初始化的指针上搜索一下 ,似乎未初始化的指针指向内存中的随机位置。 似乎这一点使它们不安全。 如果引用非itilialized指针,则跳转到内存的不安全部分。 期。 但特雷弗谈论它们的方式似乎暗示它更复杂。 他引用了下面的代码,并解释说当函数FrmGetObjectIndex取消引用f时,它不是访问有效指针,而是访问一个不可预测的地址 – 当分配f的空间时堆栈上的任何内容。

什么是Trevor的意思是“当f的空间分配时,堆栈中的任何东西”? 默认情况下,“未初始化”指针是否已初始化为内存中的随机位置? 或者他们的“随机”行为是否与为这些指针分配的内存有关,因为堆栈上的意外行为会填充奇怪的值(然后被引用)。

Form *f; switch (event->eType) { case frmOpenEvent: f = FrmGetActiveForm(); ... case ctlSelectEvent: i = FrmGetObjectIndex(f, field); ... } 

什么是Trevor的意思是“当f的空间分配时,堆栈中的任何东西”?

他的意思是,在大多数汇编语言中,使用单独的指令来保留堆栈上的空间并在新保留的空间内写入初始值。 如果C程序使用未初始化的变量,程序通常会在运行时执行保留堆栈空间但没有设置指令的指令。 当使用指针时,它将字面上包含在保留空间之前堆栈上的位模式。 在好的情况下,这将是一个无效的地址。 在不好的情况下,这将恰好是一个有效的地址,并且效果将是不可预测的。

这只是一种典型行为。 从理论的角度来看,使用不确定值是未定义的行为 。 可能会发生比简单地访问无效地址或有效地址更奇怪的事情(使用意外或故意使用未初始化数据(非地址)的示例)。


以下是Cyclone旨在阻止C的受限子集的危险:

 int a, *p; int main(int c, char **v){ int l, *lp, i; if (c & 1) a = l + 1; // danger if (c & 2) *lp = 3; // danger if (c & 4) { p = &a; for (i=0; i<=1; i++) { int block_local; *p = 4; // danger p = &block_local; } } } 

在最后一个危险的行中,实际上,很可能将4写入变量block_local ,但实际上,在第二次迭代中, p是不确定的,程序不应该访问*p ,并且它是未定义的行为什么时候呢。

在现代操作系统上,危险是核心转储。 在没有内存管理的早期系统上,可能存储器映射到外部硬件的i / o,危险程度完全不同。